diff -u --recursive --new-file v2.0.33/linux/CREDITS linux/CREDITS
--- v2.0.33/linux/CREDITS	Tue Dec  2 13:52:30 1997
+++ linux/CREDITS	Wed Jun  3 15:17:46 1998
@@ -35,6 +35,15 @@
 S: San Jose, California 95129
 S: USA
 
+N: Andrea Arcangeli
+E: arcangeli@mbox.queen.it
+W: http://www.cs.unibo.it/~arcangel/
+P: 1024/CB4660B9 CC A0 71 81 F4 A0 63 AC  C0 4B 81 1D 8C 15 C8 E5
+D: Fixed a 2.0.33 mm bug that corrupts memory in linux/mm/vmalloc.c
+S: Via Ciaclini 26
+S: Imola 40026
+S: Italy
+
 N: Derek Atkins
 E: warlord@MIT.EDU
 D: Linux-AFS Port, random kernel hacker,
@@ -81,6 +90,14 @@
 S: Notre Dame, Indiana
 S: USA
 
+N: James Banks
+E: james.banks@caldera.com
+D: TLAN network driver
+S: Caldera, Inc.
+S: 633 South 550 East
+S: Provo, UT 84606
+S: USA
+
 N: Peter Bauer
 E: 100136.3530@compuserve.com
 D: Driver for depca-ethernet-board
@@ -89,10 +106,12 @@
 S: Germany
 
 N: Fred Baumgarten
-E: dc6iq@insu1.etec.uni-karlsruhe.de
+E: dc6iq@insl1.etec.uni-karlsruhe.de
+E: dc6iq@adacom.org
+E: dc6iq@db0ais.#hes.deu.eu (packet radio)
 D: NET-2 & netstat(8)
-S: Kandelstrasse 27
-S: 76297 Stutensee
+S: Soevener Strasse 11
+S: 53773 Hennef
 S: Germany
 
 N: Donald Becker
@@ -207,7 +226,8 @@
 
 N: Gordon Chaffee
 E: chaffee@plateau.cs.berkeley.edu
-D: vfat filesystem
+W: http://bmrc.berkeley.edu/people/chaffee/
+D: vfat, fat32, joliet, native language support
 S: 3674 Oakwood Terrace #201
 S: Fremont, California 94536
 S: USA
@@ -401,11 +421,12 @@
 S: Germany
 
 N: Jeremy Fitzhardinge
-E: jeremy@sw.oz.au
+E: jeremy@zip.com.au
 D: Improved mmap and munmap handling
 D: General mm minor tidyups
-S: 99 Albermarle Street
-S: Newtown 2042
+S: 67 Surrey St.
+S: Darlinghurst, Sydney
+S: NSW 2010
 S: Australia
 
 N: Ralf Flaxa
@@ -477,11 +498,11 @@
 D: Kernel / timekeeping stuff
 
 N: Dmitry S. Gorodchanin
-E: begemot@bgm.rosprint.net
+E: pgmdsg@ibi.com
 D: RISCom/8 driver, misc kernel fixes.
-S: 6/1 M.Koneva bl, apt #125 
-S: Poltava 314023
-S: Ukraine
+S: 4 Main Street
+S: Woodbridge, Connecticut 06525
+S: USA
 
 N: Paul Gortmaker
 E: gpg109@rsphy1.anu.edu.au
@@ -617,6 +638,7 @@
 N: Ron Holt
 E: ron@caldera.com
 W: http://www.holt.org/
+P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A  40 E3 FB 71 D1 C8 0B 56
 D: Kernel development
 D: Minor kernel modifications to support Wabi and Wine
 S: Caldera, Inc.
@@ -680,7 +702,7 @@
 S: USA
 
 N: Bernhard Kaindl
-E: bkaindl@netway.at
+E: bernhard.kaindl@gmx.net
 E: edv@bartelt.via.at
 D: Author of a menu based configuration tool, kmenu, which 
 D: is the predecessor of 'make menuconfig' and 'make xconfig'.
@@ -714,9 +736,11 @@
 
 N: Ian Kluft
 E: ikluft@thunder.sbay.org
-D: Smail binary packages for Slackware and Debian
-S: 2200 Monroe Street #1509
-S: Santa Clara, California 95050-3452
+W: http://www.kluft.com/~ikluft/
+D: NET-1 beta testing & minor patches, original Smail binary packages for
+D: Slackware and Debian, vote-taker for 2nd comp.os.linux reorganization
+S: PO Box 611311
+S: San Jose, CA 95161-1311
 S: USA
 
 N: Alain L. Knaff
@@ -764,8 +788,8 @@
 N: Bas Laarhoven
 E: bas@vimec.nl
 D: Loadable modules and ftape driver
-S: Mr. v. Boemellaan 39
-S: NL-5237 KA 's-Hertogenbosch
+S: J. Obrechtstr 23
+S: NL-5216 GP 's-Hertogenbosch
 S: The Netherlands
 
 N: Savio Lam
@@ -806,6 +830,14 @@
 E: loewis@informatik.hu-berlin.de
 D: script binary format
 
+N: Jamie Lokier
+E: jamie@imbolc.ucc.ie
+D: Reboot-through-BIOS for broken 486 motherboards
+S: 26 Oatlands Road
+S: Oxford
+S: OX2 0ET
+S: United Kingdom
+
 N: Mark Lord
 E: mlord@pobox.com
 D: Author of IDE driver (ide.c), hd.c support
@@ -914,8 +946,8 @@
 N: Dirk Melchers
 E: dirk@merlin.nbg.sub.org
 D: 8 bit XT hard disk driver for OMTI5520
-S: Heidackerstrass 19
-S: D-91056 Erlangen
+S: Schloessleinsgasse 31
+S: D-90453 Nuernberg
 S: Germany
 
 N: Michael Meskes
@@ -968,6 +1000,7 @@
 
 N: Rick Miller
 E: rdmiller@execpc.com
+W: http://www.execpc.com/~rdmiller/
 D: Original Linux Device Registrar (Major/minor numbers)
 D: au-play, bwBASIC
 S: S78 W16203 Woods Road
@@ -1101,8 +1134,12 @@
 D: Some PCI kernel support
 
 N: Stefan Probst
-E: snprobst@immd4.informatik.uni-erlangen.de
-D: The Linux Support Team Erlangen
+E: sp@caldera.de
+D: The Linux Support Team Erlangen, 1993-97
+S: Caldera (Deutschland) GmbH
+S: Lazarettstrasse 8
+S: 91054 Erlangen
+S: Germany
 
 N: Daniel Quinlan
 E: quinlan@pathname.com
@@ -1427,6 +1464,14 @@
 S: Obere Heerbergstrasse 17
 S: 97078 Wuerzburg
 S: Germany
+
+N: Greg Ungerer
+E: gerg@stallion.com
+D: Author of Stallion multiport serial drivers
+S: Stallion Technologies
+S: 33 Woodstock Rd
+S: Toowong, QLD. 4066
+S: Australia
 
 N: Jeffrey A. Uphoff
 E: juphoff@nrao.edu
diff -u --recursive --new-file v2.0.33/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.33/linux/Documentation/Changes	Mon Aug 18 20:16:26 1997
+++ linux/Documentation/Changes	Wed Jun  3 15:17:46 1998
@@ -40,11 +40,21 @@
    Voyez le site http://www.linux-kheops.com/traduc/kernels/ pour la
 traduction francaise (merci, David Bourgin).  (French translation)
 
-Last updated: August 14, 1997.
-Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
+   Per quelli che preferiscono avere una versione in Italiano di questo
+documento, si consulti la traduzione di Giovanni Bortolozzo reperibile a
+http://www.pluto.linux.it/ildp/kernel/Changes-2.0.html (Italian
+translation).
 
-Current Releases
-****************
+   The most current version should always be available from
+http://cyberbuzz.gatech.edu/kaboom/linux/ as well.
+
+Last updated: February 16, 1998.
+Current Author: Chris Ricker (kaboom@gatech.edu).
+
+Current Releases (the latest necessary for basic functionality, not
+*******************************************************************
+
+   necessarily the latest and greatest)
 
 - Kernel modules	 2.0.0
 - PPP daemon		 2.2.0f
@@ -372,6 +382,12 @@
 masquerading.  You'll need to get
 ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this.
 
+   To enable IP forwarding, you may need to
+
+   echo 1 > /proc/sys/net/ipv4/ip_forwarding
+
+   as well.
+
 ISDN support
 ============
 
@@ -587,6 +603,14 @@
 you'll need to get the latest version, currently available at
 ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs/e2fsprogs-1.06.tar.gz.
 
+FlagShip and /dev/full
+======================
+
+   The behavior of /dev/full changed with kernel 2.0.31.  In addition to
+improving system security, the change broke executables created by the
+FlagShip database compiler.  Fixes can be found at http://www.fship.com
+via the "What's New" or "Support" buttons.
+
 How to know the version of the installed programs
 *************************************************
 
@@ -725,8 +749,7 @@
 
 Please send info about any other packages that 2.0.x "broke" or about
 any new features of 2.0.x that require extra or new packages for use to
-Chris Ricker (gt1355b@prism.gatech.edu).  I generate this from a
-modified texinfo setup, so you don't need to bother generating a diff
-against the current version before you send the additional information
-to me.
+Chris Ricker <kaboom@gatech.edu>.  I generate this from a modified
+texinfo setup, so you don't need to bother generating a diff against
+the current version before you send the additional information to me.
 
diff -u --recursive --new-file v2.0.33/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.0.33/linux/Documentation/Configure.help	Tue Mar 10 13:19:08 1998
+++ linux/Documentation/Configure.help	Wed Jun  3 15:17:46 1998
@@ -1,4 +1,4 @@
-# Maintained by Axel Boldt (boldt@math.ucsb.edu) 
+# Maintained by Axel Boldt (boldt@math.ucsb.edu)
 #
 # This version of the Linux kernel configuration help texts
 # corresponds to the kernel versions 2.0.x.
@@ -6,16 +6,16 @@
 # International versions of this file available on the WWW:
 #   - http://jf.gee.kyoto-u.ac.jp/JF/JF-ftp/euc/Configure.help.euc
 # is a Japanese translation, maintained by Tetsuyasu YAMADA
-# (tetsu@cauchy.nslab.ntt.jp). 
-#   - http://nevod.perm.su/service/linux/doc/kernel/Configure.help 
+# (tetsu@cauchy.nslab.ntt.jp).
+#   - http://nevod.perm.su/service/linux/doc/kernel/Configure.help
 # is a Russian translation, maintained by kaf@linux.nevod.perm.su.
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
 # via ftp (user: anonymous) from sunsite.unc.edu in the directory
-# /pub/Linux/docs/HOWTO. 
+# /pub/Linux/docs/HOWTO.
 #
-# Format of this file: description<nl>variable<nl>helptext<nl><nl>. 
+# Format of this file: description<nl>variable<nl>helptext<nl><nl>.
 # If the question being documented is of type "choice", we list
 # only the first occurring config variable. The help texts
 # must not contain empty lines. No variable should occur twice; if it
@@ -29,7 +29,7 @@
 # hypothetical user who has just bought a PC, removed Windows,
 # installed Linux and is now recompiling the kernel for the first
 # time. Tell them what to do if they're unsure. Technical information
-# should go in a README in the Documentation directory. Mention all 
+# should go in a README in the Documentation directory. Mention all
 # the relevant READMEs and HOWTOs in the help text.
 #
 # All this was shamelessly stolen from several different sources. Many
@@ -39,24 +39,24 @@
 
 Prompt for development and/or incomplete code/drivers
 CONFIG_EXPERIMENTAL
-  Some of the various things that Linux supports (such as network 
-  drivers, filesystems, network protocols, etc.) can be in a state 
-  of development where the functionality, stability, or the level of 
-  testing is not yet high enough for general use. This is usually
-  known as the "alpha-test" phase amongst developers. If a feature is
-  currently in alpha-test, then the developers usually discourage 
+  Some of the various things that Linux supports (such as network
+  drivers, filesystems, network protocols, etc.) can be in a state
+  of development where the functionality, stability, or the level of
+  testing is not yet high enough for general use.  This is usually
+  known as the "alpha-test" phase amongst developers.  If a feature is
+  currently in alpha-test, then the developers usually discourage
   uninformed widespread use of this feature by the general public to
-  avoid "Why doesn't this work?" type mail messages. However, active
-  testing and use of these systems is welcomed. Just be aware that it
+  avoid "Why doesn't this work?" type mail messages.  However, active
+  testing and use of these systems is welcomed.  Just be aware that it
   may not meet the normal level of reliability or it may fail to work
-  in some special cases. Detailed bug reports from people familiar with
-  the kernel internals are usually welcomed by the developers. 
+  in some special cases.  Detailed bug reports from people familiar
+  with the kernel internals are usually welcomed by the developers.
   Unless you intend to help test and develop a feature or driver that
-  falls into this category, or you have a situation that requires using 
-  these features you should probably say N here, which will cause this 
-  configure script to present you with fewer choices. If you say Y here,
-  you will be offered the choice of using features or drivers that are
-  currently considered to be in the alpha-test phase.
+  falls into this category, or you have a situation that requires
+  using these features you should probably say N here, which will
+  cause this configure script to present you with fewer choices.  If
+  you say Y here, you will be offered the choice of using features or
+  drivers that are currently considered to be in the alpha-test phase.
 
 Kernel math emulation
 CONFIG_MATH_EMULATION
@@ -81,14 +81,13 @@
 
 Normal floppy disk support
 CONFIG_BLK_DEV_FD
-  If you want to use your floppy disk drive(s) under Linux, say
-  Y. Information about this driver, especially important for IBM
-  Thinkpad users, is contained in drivers/block/README.fd.  This
-  driver is also available as a module ( = code which can be inserted
-  in and removed from the running kernel whenever you want). If you
-  want to compile it as a module, say M here and read
-  Documentation/modules.txt.
-  
+  If you want to use your floppy disk drive(s) under Linux, say Y.
+  Information about this driver, especially important for IBM Thinkpad
+  users, is contained in drivers/block/README.fd.  This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 RAM disk support
 CONFIG_BLK_DEV_RAM
   Enabling this option will allow you to use a portion of your RAM
@@ -125,17 +124,17 @@
   from the machine to itself.  Most users will answer N here.
 
 Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
-CONFIG_BLK_DEV_IDE 
+CONFIG_BLK_DEV_IDE
   This will use the full-featured IDE driver to control up to four
   IDE interfaces, for a combination of up to eight IDE
   disk/cdrom/tape/floppy drives.  Useful information about large
   (>540MB) IDE disks, soundcard IDE ports, and other topics, is all
   contained in Documentation/ide.txt.  If you have one or more IDE
-  drives, say Y here.  If your system has no IDE drives, or if memory
-  requirements are really tight, you could say N here, and select
-  the Old harddisk driver instead to save about 13kB of memory in
-  the kernel.  To fine-tune IDE drive/interface parameters for
-  improved performance, look for the hdparm package at
+  drives, say Y here.  If your system has no IDE drives, or if
+  memory requirements are really tight, you could say N here, and
+  select the Old harddisk driver instead to save about 13kB of
+  memory in the kernel.  To fine-tune IDE drive/interface parameters
+  for improved performance, look for the hdparm package at
   sunsite.unc.edu:/pub/Linux/kernel/patches/diskdrives/
 
 Old harddisk (MFM/RLL/IDE) driver
@@ -165,7 +164,7 @@
   address (0x1f0), along with IDE drives at the secondary/3rd/4th port
   addresses.  Normally, just say N here; you will then use the new
   driver for all 4 interfaces.
-  
+
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
   If you have a CDROM drive using the ATAPI protocol, say Y.  ATAPI is
@@ -198,12 +197,11 @@
 CONFIG_BLK_DEV_IDEFLOPPY
   If you have an IDE floppy which uses the ATAPI protocol, say Y.
   ATAPI is a new protocol used by IDE cdrom/tape/floppy drives,
-  similar to the SCSI protocol.  IDE floppy drives include the
-  LS-120 and the ATAPI ZIP (ATAPI PD-CD drives are not supported
-  by this driver; support for PD-CD drives is available through
-  the SCSI emulation).  At boot time, the FLOPPY drive will be
-  identified along with other IDE devices, as "hdb" or "hdc", or
-  something similar.
+  similar to the SCSI protocol.  IDE floppy drives include the LS-120
+  and the ATAPI ZIP (ATAPI PD-CD drives are not supported by this
+  driver; support for PD-CD drives is available through the SCSI
+  emulation).  At boot time, the FLOPPY drive will be identified along
+  with other IDE devices, as "hdb" or "hdc", or something similar.
 
 SCSI emulation support
 CONFIG_BLK_DEV_IDESCSI
@@ -315,21 +313,21 @@
 
 XT harddisk support
 CONFIG_BLK_DEV_XD
-  Very old 8 bit hard disk controllers used in the IBM XT computer. To
-  include a driver for these, say Y. If you want to compile the driver
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. It's pretty unlikely that you have one of
-  these: say N.
+  Very old 8 bit hard disk controllers used in the IBM XT computer.
+  To include a driver for these, say Y.  If you want to compile the
+  driver as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want), say M here and read
+  Documentation/modules.txt.
+  It's pretty unlikely that you have one of these: say N.
 
 Multiple devices driver support
 CONFIG_BLK_DEV_MD
   This driver lets you combine several harddisk partitions into one
-  logical block device. Information about how and why to use it and the
-  necessary tools are available over ftp (user: anonymous) from
+  logical block device.  Information about how and why to use it and
+  the necessary tools are available over ftp (user: anonymous) from
   sweet-smoke.ufr-info-p7.ibp.fr/pub/public/Linux in the md package
-  and the md-FAQ. Please read drivers/block/README.md. If unsure, say
-  N.
+  and the md-FAQ. Please read drivers/block/README.md.  If unsure,
+  say N.
 
 Linear (append) mode
 CONFIG_MD_LINEAR
@@ -351,16 +349,16 @@
   in and removed from the running kernel whenever you want), say M
   here and read Documentation/modules.txt. If unsure, say Y.
 
-Support for Deskstation RPC44 
+Support for Deskstation RPC44
 CONFIG_DESKSTATION_RPC44
   This is a machine with a R4400 100 MHz CPU. To compile a Linux
-  kernel that runs on these, say Y here. For details about Linux
-  on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (To browse the WWW, you need to
-  have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access
+  to a machine on the Internet that has one of the programs lynx,
+  netscape or Mosaic).
 
-Support for Mips Magnum 3000 
+Support for Mips Magnum 3000
 CONFIG_MIPS_MAGNUM_3000
   To compile a Linux kernel that runs on these, say Y here. For
   details about Linux on the MIPS architecture, check out the
@@ -371,20 +369,20 @@
 Support for Mips Magnum 4000
 CONFIG_MIPS_MAGNUM_4000
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
-  kernel that runs on these, say Y here. For details about Linux
-  on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (To browse the WWW, you need to
-  have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access
+  to a machine on the Internet that has one of the programs lynx,
+  netscape or Mosaic).
 
 Support for Olivetti M700
 CONFIG_OLIVETTI_M700
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
-  kernel that runs on these, say Y here. For details about Linux
-  on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (To browse the WWW, you need to
-  have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access
+  to a machine on the Internet that has one of the programs lynx,
+  netscape or Mosaic).
 
 Support for Deskstation Tyne
 CONFIG_DESKSTATION_TYNE
@@ -398,34 +396,33 @@
 Support for Acer PICA 1 chipset
 CONFIG_ACER_PICA_61
   This is a machine with a R4400 134/150 MHz CPU. To compile a Linux
-  kernel that runs on these, say Y here. For details about
-  Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the
-  WWW at http://lena.fnet.fr/ (To browse the WWW, you need to have
-  access to a machine on the Internet that has one of the programs
-  lynx, netscape or Mosaic).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access
+  to a machine on the Internet that has one of the programs lynx,
+  netscape or Mosaic).
 
 Support for DECstation
 CONFIG_DECSTATION
   The DECStation 3100 (with a MIPS R2000 series CPU) and DECStation
-  5000/xxx (MIPS R3000 series CPU) are also sometimes labeled
-  PMAX. They often run the Ultrix operating system. To compile a Linux
-  kernel that runs on these, say Y here. For details about Linux
-  on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (To browse the WWW, you need to
-  have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic).
+  5000/xxx (MIPS R3000 series CPU) are also sometimes labeled PMAX.
+  They often run the Ultrix operating system. To compile a Linux
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access
+  to a machine on the Internet that has one of the programs lynx,
+  netscape or Mosaic).
 
 CPU type
 CONFIG_CPU_R3000
-  Give the type of your machine's MIPS CPU. For this question,
-  it suffices to give a unique prefix of the option you want to
-  choose. 
+  Give the type of your machine's MIPS CPU. For this question, it
+  suffices to give a unique prefix of the option you want to choose.
 
 Networking support
 CONFIG_NET
-  Unless you really know what you are doing, you should say Y
-  here. The reason is that some programs need it even if you configure
-  a stand-alone machine that won't be connected to any other computer.
+  Unless you really know what you are doing, you should say Y here.
+  The reason is that some programs need it even if you configure a
+  stand-alone machine that won't be connected to any other computer.
   from an older kernel, you should consider updating your networking
   tools too; read net/README for details.
 
@@ -445,8 +442,8 @@
 CONFIG_FIREWALL
   A firewall is a computer which protects a local network from the
   rest of the World: all traffic to and from computers on the local
-  net is inspected by the firewall first. If you want to configure
-  your Linux box as a firewall for a local network, say Y here. If
+  net is inspected by the firewall first.  If you want to configure
+  your Linux box as a firewall for a local network, say Y here.  If
   your local network is TCP/IP based, you will have to say Y to "IP:
   firewalling", below.  You also need to say Y here and enable "IP
   firewalling" below in order to be able to use IP masquerading
@@ -456,43 +453,21 @@
   need to allocate valid IP host addresses for the machines on the
   local net) or to use the ip packet accounting to see what is using
   all your network bandwidth. Chances are that you should use this on
-  any machine being run as a router and not on a host. If unsure, say
-  N.
+  any machine being run as a router and not on a host.
+  If unsure, say N.
 
 SYN flood protection
 CONFIG_SYN_COOKIES
   Normal TCP/IP networking is open to an attack known as SYN flooding.
   This attack prevents legitimate users from being able to connect to
   your computer and requires very little work for the attacker.
-  SYN cookies provide protection against this type of attack. With
+  SYN cookies provide protection against this type of attack.  With
   this option turned on the TCP/IP stack will use a cryptographic
   challenge protocol known as SYN cookies to enable legitimate users
   to continue to connect, even when your machine is under attack.
-  The RST_COOKIES option provides an alternative method to accomplish
-  the same end. SYN cookies use less space than RST cookies,
-  but have a small probability of introducing an non timed-out
-  failure to connect in the remote TCP. You can use both options
-  simultatenously.  If you are SYN flooded, the source address
-  reported by the kernel is likely to have been forged by the attacker.
-  The source address is reported as an aid in tracing the packets to 
-  their actual source.  
-
-SYN flood protection
-CONFIG_RST_COOKIES
-  Normal TCP/IP networking is open to an attack known as SYN flooding.
-  This attack prevents legitimate users from being able to connect to
-  your computer and requires very little work for the attacker.
-  SYN cookies provide protection against this type of attack. With
-  this option turned on the TCP/IP stack will use a cryptographic
-  challenge protocol known as RST cookies to enable legitimate users
-  to continue to connect, even when your machine is under attack.
-  The SYN_COOKIES option provides an alternative method to accomplish
-  the same end. RST cookies use more space than SYN cookies on your
-  machine, but never increase the probability of a frozen connection
-  in a remote TCP. You can use both options simultatenously.  If you 
-  are SYN flooded, the source address reported by the kernel is likely 
-  to have been forged by the attacker.  The source address is reported 
-  as an aid in tracing the packets to their actual source.  
+  If you are SYN flooded, the source address reported by the kernel is 
+  likely to have been forged by the attacker.  The source address is 
+  reported as an aid in tracing the packets to their actual source.
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -544,17 +519,16 @@
   the kernel to be able to use the memory above 64MB, pass the command
   line option "mem=XXXM" (where XXX is the memory size in megabytes)
   to your kernel during boot time. See the documentation of your boot
-  loader (lilo or loadlin) about how to pass options to the
-  kernel. The lilo procedure is also explained in the SCSI-HOWTO,
-  available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  You also need at least 512kB
-  of RAM cache if you have more than 64MB of RAM.  Some other things
-  to try when experiencing seemingly random, "weird" problems: 1)
-  passing the "no-hlt" option to the kernel 2) passing the "no-387"
-  option to the kernel 3) passing the "mem=4M" option to the kernel
-  (thereby disabling all but the first 4M of RAM) 4) disabling the
-  cache from your BIOS settings 5) exchanging RAM chips 6) exchanging
-  the motherboard.
+  loader (lilo or loadlin) about how to pass options to the kernel.
+  The lilo procedure is also explained in the SCSI-HOWTO, available
+  via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  You also need at least 512kB of RAM cache if you have more than 64MB
+  of RAM. Some other things to try when experiencing seemingly random,
+  "weird" problems: 1) passing the "no-hlt" option to the kernel
+  2) passing the "no-387" option to the kernel 3) passing the "mem=4M"
+  option to the kernel (thereby disabling all but the first 4M of RAM)
+  4) disabling the cache from your BIOS settings
+  5) exchanging RAM chips  6) exchanging the motherboard.
 
 Using SRM as bootloader
 CONFIG_ALPHA_SRM
@@ -607,7 +581,7 @@
   about which PCI hardware does work under Linux and which doesn't.
   If some of your PCI devices don't work and you get a warning during
   boot time ("man dmesg"), please follow the instructions at the top
-  of include/linux/pci.h. 
+  of include/linux/pci.h.
 
 PCI bridge optimization (experimental)
 CONFIG_PCI_OPTIMIZE
@@ -622,24 +596,24 @@
   i82371SB or i82371AB), you will want to enable this option to allow
   use of bus-mastering DMA data transfers. Read the comments at the
   beginning of drivers/block/triton.c and Documentation/ide.txt.
-  Check the file Documentation/Changes for location and latest version of
-  the hdparm utility. It is safe to say Y to this question.
+  Check the file Documentation/Changes for location and latest version
+  of the hdparm utility. It is safe to say Y to this question.
 
 System V IPC
 CONFIG_SYSVIPC
-  Inter Process Communication is a suite of library functions and system
-  calls which let processes (= running programs) synchronize and
-  exchange information. It is generally considered to be a good thing,
-  and some programs won't run unless you enable this. In particular,
-  if you want to run the DOS emulator dosemu under Linux (read the
-  DOSEMU-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO), you'll need to say Y here. You
-  can find documentation about IPC in ipc.info, which is contained in
-  sunsite.unc.edu:/pub/Linux/docs/man/info.tar.gz (extract with "tar
-  xzvf filename"). These docs are in the info format which is used to
-  document GNU software and can be read from within emacs ("Ctrl-h i")
-  or with the program info ("man info"). Enabling this option enlarges
-  your kernel by about 7kB. Just say Y.
+  Inter Process Communication is a suite of library functions and
+  system calls which let processes (= running programs) synchronize
+  and exchange information. It is generally considered to be a good
+  thing, and some programs won't run unless you enable this. In
+  particular, if you want to run the DOS emulator dosemu under Linux
+  (read the DOSEMU-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO), you'll need to say Y here.
+  You can find documentation about IPC in ipc.info, which is contained
+  in sunsite.unc.edu:/pub/Linux/docs/man/info.tar.gz (extract with
+  "tar xzvf filename"). These docs are in the info format which is
+  used to document GNU software and can be read from within emacs
+  ("Ctrl-h i") or with the program info ("man info"). Enabling this
+  option enlarges your kernel by about 7kB. Just say Y.
 
 Kernel support for ELF binaries
 CONFIG_BINFMT_ELF
@@ -669,7 +643,7 @@
 CONFIG_KERNEL_ELF
   The gcc version 2.7.0 and newer produces the new ELF binary format
   as default. If you have such a compiler (try "gcc -v"), say Y here,
-  otherwise N.  
+  otherwise N.
   It is possible, albeit almost pointless, to compile the kernel in
   a.out (i.e. QMAGIC) format even if your compiler produces ELF as
   default. For that, you would have to say N here and change the
@@ -691,7 +665,7 @@
   wish to ensure that absolutely none of your programs will use this
   older executable format. If you don't know what to answer at this
   point then answer Y. If someone told you "You need a kernel with
-  QMAGIC support" then you'll have to say Y here. You may answer M 
+  QMAGIC support" then you'll have to say Y here. You may answer M
   to compile a.out support as a module and later load the module when
   you want to use a program or library in a.out format. Saying M or N
   here is dangerous though, because some crucial programs on your
@@ -717,8 +691,8 @@
   warrant removing support. However its removal is a good idea if you
   do not have the JDK installed. If you don't know what to answer at
   this point then answer Y. You may answer M for module support and
-  later load the module when you install the JDK or find an interesting
-  Java program that you can't live without.
+  later load the module when you install the JDK or find an
+  interesting Java program that you can't live without.
 
 Processor type
 CONFIG_M386
@@ -733,7 +707,7 @@
   say "386" or "486" here even if running on a Pentium or PPro
   machine. If you don't know what to do, say "386".
 
-Compile the kernel into the ELF object format 
+Compile the kernel into the ELF object format
 CONFIG_ELF_KERNEL
   ELF (Executable and Linkable Format) is a format for libraries and
   executables used across different architectures and operating
@@ -756,27 +730,27 @@
 
 Enable loadable module support
 CONFIG_MODULES
-  Kernel modules are small pieces of compiled code which can be 
+  Kernel modules are small pieces of compiled code which can be
   inserted in or removed from the running kernel, using the
-  programs insmod and rmmod. This is described in the file 
-  Documentation/modules.txt. Modules can be device drivers, file 
-  systems, binary executable formats, and so on. If you think that 
-  you may want to make use of modules with this kernel in the future, 
+  programs insmod and rmmod. This is described in the file
+  Documentation/modules.txt. Modules can be device drivers, file
+  systems, binary executable formats, and so on. If you think that
+  you may want to make use of modules with this kernel in the future,
   then say Y here. If unsure, say Y.
 
 Set version information on all symbols for modules
 CONFIG_MODVERSIONS
   Usually, modules have to be recompiled whenever you switch to a new
-  kernel. Enabling this option makes it possible, and safe, to use the
-  same modules even after compiling a new kernel; this requires the
-  program modprobe. All the software needed for module support is in
-  the modules package (check the file Documentation/Changes for
+  kernel.  Enabling this option makes it possible, and safe, to use
+  the same modules even after compiling a new kernel; this requires
+  the program modprobe. All the software needed for module support is
+  in the modules package (check the file Documentation/Changes for
   location and latest version).  NOTE: if you say Y here but don't
   have the program genksyms (which is also contained in the above
   mentioned modules package), then the building of your kernel will
   fail.  If you are going to use modules that are generated from
   non-kernel sources, you would benefit from this option. Otherwise
-  it's not that important. So, N ought to be a safe bet.
+  it's not that important.  So, N ought to be a safe bet.
 
 Kernel daemon support
 CONFIG_KERNELD
@@ -796,7 +770,7 @@
 
 ARP daemon support (EXPERIMENTAL)
 CONFIG_ARPD
-  Normally, the kernel maintains an internal cache which maps IP 
+  Normally, the kernel maintains an internal cache which maps IP
   addresses to hardware addresses on the local network, so that
   Ethernet/Token Ring/ etc. frames are sent to the proper address on
   the physical networking layer.  For small networks having a few
@@ -824,8 +798,7 @@
   program which gives you almost full Internet connectivity if you
   have a regular dial up shell account on some Internet connected Unix
   computer. Read the Term-HOWTO, available via ftp (user: anonymous)
-  on sunsite.unc.edu:/pub/Linux/docs/HOWTO).  Short answer:
-  say Y.
+  on sunsite.unc.edu:/pub/Linux/docs/HOWTO).  Short answer: say Y.
 
 IP: forwarding/gatewaying
 CONFIG_IP_FORWARD
@@ -890,22 +863,21 @@
   If you want to configure your Linux box as a firewall for a local
   TCP/IP based network, say Y here. This will enlarge your kernel by
   about 2kB. You may need to read the FIREWALL-HOWTO, available via
-  ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the
-  ipfwadm tool (check the file Documentation/Changes for location and
-  latest version) to allow selective blocking of internet traffic
-  based on type, origin and destination.  You need to enable IP
-  firewalling in order to be able to use IP masquerading (i.e. local
-  computers can chat with an outside host, but that outside host is
-  made to think that it is talking to the firewall box. Makes the
-  local network completely invisible and avoids the need to allocate
-  valid IP host addresses for the machines on the local net) or to use
-  the IP packet accounting to see what is using all your network
-  bandwidth.  This option is also needed when you want to enable the
-  transparent proxying support (makes the computers on the local
-  network think they're talking to a remote computer, while in reality
-  the traffic is redirected by your Linux firewall to a local proxy
-  server).
+  ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  Also, you will need the ipfwadm tool (check the file
+  Documentation/Changes for location and latest version) to allow
+  selective blocking of internet traffic based on type, origin and
+  destination.  You need to enable IP firewalling in order to be able
+  to use IP masquerading (i.e. local computers can chat with an
+  outside host, but that outside host is made to think that it is
+  talking to the firewall box. Makes the local network completely
+  invisible and avoids the need to allocate valid IP host addresses
+  for the machines on the local net) or to use the IP packet
+  accounting to see what is using all your network bandwidth.  This
+  option is also needed when you want to enable the transparent
+  proxying support (makes the computers on the local network think
+  they're talking to a remote computer, while in reality the traffic
+  is redirected by your Linux firewall to a local proxy server).
 
 IP: accounting
 CONFIG_IP_ACCT
@@ -914,8 +886,8 @@
   a router or a firewall for some local network, in which case you
   naturally should have said Y to IP forwarding/gatewaying resp. IP
   firewalling. The data is accessible with "cat /proc/net/ip_acct", so
-  you want to say Y to the /proc filesystem below, if you say Y
-  here. To specify what exactly should be recorded, you need the tool
+  you want to say Y to the /proc filesystem below, if you say Y here.
+  To specify what exactly should be recorded, you need the tool
   ipfwadm (check the file Documentation/Changes for location and
   latest version).
 
@@ -934,12 +906,12 @@
   in and removed from the running kernel whenever you want), one
   encapsulator and one decapsulator. You can read details in
   drivers/net/README.tunnel. Most people can say N.
-  
+
 IP: firewall packet logging
 CONFIG_IP_FIREWALL_VERBOSE
-  This gives you information about what your firewall did with
-  packets it received. The information is handled by the klogd demon
-  which is responsible for kernel messages ("man klogd").
+  This gives you information about what your firewall did with packets
+  it received.  The information is handled by the klogd demon which is
+  responsible for kernel messages ("man klogd").
 
 IP: transparent proxying (EXPERIMENTAL)
 CONFIG_IP_TRANSPARENT_PROXY
@@ -969,35 +941,31 @@
   Internet using SLiRP [SLiRP is a SLIP/PPP emulator that works if you
   have a regular dial up shell account on some UNIX computer; get it
   from ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/].)
-  Details on how to set things up are contained in the
-  IP Masquerading FAQ, available at http://www.indyramp.com/masq/
+  Details on how to set things up are contained in the IP Masquerading
+  FAQ, available at http://www.indyramp.com/masq/
   To use masquerading you must also enable Network Firewalls, IP
   forwarding/gatewaying, IP firewalling and (ideally, but optionally)
   IP always defragment.
   If you want this, say Y.
 
-IP: ipautofw masquerade support
-CONFIG_IP_MASQUERADE_IPAUTOFW (Experimental)
-  ipautofw is a program by Richard Lynch allowing additional
-  support for masquerading protocols which do not (as yet)
-  have additional protocol helpers.  
-  Information and source for ipautofw is available from
-  ftp://ftp.netis.com/pub/members/rlynch/
-  The ipautofw code is still under development and so is currently
-  marked EXPERIMENTAL.
-  If you want this, say Y.
+IP: ipautofw masquerading (EXPERIMENTAL)
+CONFIG_IP_MASQUERADE_IPAUTOFW
+  Richard Lynch's ipautofw allows masquerading to work with protocols
+  which do not (as yet) have specific protocol helpers.  Its source,
+  and other information, is available at
+  ftp://ftp.netis.com/pub/members/rlynch/.
 
 IP: ICMP masquerading
 CONFIG_IP_MASQUERADE_ICMP
   The basic masquerade code described for CONFIG_IP_MASQUERADE only
-  handles TCP or UDP packets (and ICMP errors for existing 
+  handles TCP or UDP packets (and ICMP errors for existing
   connections).  This option adds additional support for masquerading
   ICMP packets, such as ping or the probes used by the Windows 95
   tracert program.
   If you want this, say Y.
 
-IP: always defragment 
-CONFIG_IP_ALWAYS_DEFRAG 
+IP: always defragment
+CONFIG_IP_ALWAYS_DEFRAG
   This option means that all incoming fragments (= parts of IP packets
   that arose when some host between origin and destination decided
   that the IP packets were too large and cut them in pieces) will be
@@ -1006,30 +974,30 @@
   have enabled the masquerading support (CONFIG_IP_MASQUERADE),
   because this facility requires that second and further fragments can
   be related to TCP or UDP port numbers, which are only stored in the
-  first fragment.  When using IP firewall support
-  (CONFIG_IP_FIREWALL), you might also want to enable this option, to
-  have a more reliable firewall (otherwise second and further
-  fragments will always be accepted by the firewall).  When using
-  transparent proxying (CONFIG_IP_TRANSPARENT_PROXY), this option is
-  implicit, although it is safe to say Y here. Do not say Y to this
-  option except when running either a firewall that is the sole link
-  to your network or a transparent proxy. Never ever say Y to this for
-  a normal router or host.
+  first fragment. When using IP firewall support (CONFIG_IP_FIREWALL),
+  you might also want to enable this option, to have a more reliable
+  firewall (otherwise second and further fragments will always be
+  accepted by the firewall).  When using transparent proxying
+  (CONFIG_IP_TRANSPARENT_PROXY), this option is implicit, although it
+  is safe to say N here.  Do not say Y to this option except when
+  running either a firewall that is the sole link to your network or
+  a transparent proxy.
+  Never ever say Y to this for a normal router or host.
 
 IP: aliasing support
 CONFIG_IP_ALIAS
   Sometimes it is useful to give several addresses to a single network
-  interface (= serial port or ethernet card). The most common case is
+  interface (= serial port or ethernet card).  The most common case is
   that you want to serve different WWW documents to the outside
   according to which of your host names they used to connect to
-  you. This is explained in detail on the WWW at
+  you.  This is explained in detail on the WWW at
   http://www.thesphere.com/~dlp/TwoServers/ (to browse the WWW, you
   need to have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic). Another scenario would be that
+  programs lynx, netscape or Mosaic).  Another scenario would be that
   there are two logical networks living on your local ethernet and you
-  want to access them both with the same ethernet card. The
+  want to access them both with the same ethernet card.  The
   configuration of these alias addresses is done with a special name
-  syntax explained in Documentation/networking/alias.txt. If you want
+  syntax explained in Documentation/networking/alias.txt.  If you want
   this, say Y. Most people don't need it and say N.
 
 IP: multicast routing (EXPERIMENTAL)
@@ -1047,9 +1015,10 @@
 CONFIG_INET_PCTCP
   If you have been having difficulties telneting to your Linux machine
   from a DOS system that uses (broken) PC/TCP networking software (all
-  versions up to OnNet 2.0) over your local ethernet  try enabling this
-  option.  Everyone else says N. People having problems with NCSA telnet
-  should see the file linux/Documentation/networking/ncsa-telnet.
+  versions up to OnNet 2.0) over your local ethernet try enabling this
+  option.  Everyone else says N.
+  People having problems with NCSA telnet should see the file
+  linux/Documentation/networking/ncsa-telnet.
 
 Reverse ARP
 CONFIG_INET_RARP
@@ -1077,55 +1046,57 @@
 CONFIG_INET_SNARL
   Say Y if you are on a subnetted network with all machines connected
   by Ethernet segments only, as this option optimizes network access
-  for this special case. If there are other connections, e.g. SLIP
-  links, between machines of your IP network, say N.  If in doubt, say
-  N. The PATH mtu discovery facility will cover most cases anyway.
+  for this special case.  If there are other connections, e.g. SLIP
+  links, between machines of your IP network, say N.  If in doubt,
+  say N. The PATH mtu discovery facility will cover most cases anyway.
 
 Disable Path MTU Discovery (normally enabled)
 CONFIG_NO_PATH_MTU_DISCOVERY
   MTU (maximal transfer unit) is the size of the chunks we send out
-  over the net. "Path MTU Discovery" means that, instead of always
+  over the net.  "Path MTU Discovery" means that, instead of always
   sending very small chunks, we start out sending big ones and if we
   then discover that some host along the way likes its chunks smaller,
-  we adjust to a smaller size. This is good, so most people say
-  N. However, some versions of DOS NCSA telnet (and other software)
-  are broken and can only connect to your Linux machine if you say Y
-  here. See also Documentation/networking/ncsa-telnet for the location
-  of fixed NCSA telnet clients.
+  we adjust to a smaller size.  This is good, so most people say N.
+  However, some versions of DOS NCSA telnet (and other software) are
+  broken and can only connect to your Linux machine if you say Y here.
+  See also Documentation/networking/ncsa-telnet for the location of
+  fixed NCSA telnet clients.
 
 Disable NAGLE algorithm (normally enabled)
 CONFIG_TCP_NAGLE_OFF
   The NAGLE algorithm works by requiring an acknowledgment before
   sending small IP frames (= packets).  This keeps tiny telnet and
   rlogin packets from congesting Wide Area Networks.  Most people
-  strongly recommend to say N here, thereby leaving NAGLE
-  enabled. Those programs that would benefit from disabling this
-  facility can do it on a per connection basis themselves.
+  strongly recommend to say N here, thereby leaving NAGLE enabled.
+  Those programs that would benefit from disabling this facility can
+  do it on a per connection basis themselves.
 
 IP: Drop source routed frames
 CONFIG_IP_NOSR
   Usually, the originator of an IP frame (= packet) specifies only the
   destination, and the hosts along the way do the routing, i.e. they
-  decide how to forward the frame. However, there is a feature of the
+  decide how to forward the frame.  However, there is a feature of the
   IP protocol that allows to specify the full route for a given frame
   already at its origin. A frame with such a fully specified route is
-  called "source routed". The question now is whether we should honour
-  these route requests when such frames arrive, or if we should
-  drop all those frames instead. Honouring them can introduce security
-  problems (and is rarely a useful feature), and hence it is recommended
-  that you say Y here unless you really know what you're doing.
+  called "source routed".  The question now is whether we should
+  honour these route requests when such frames arrive, or if we should
+  drop all those frames instead.  Honouring them can introduce
+  security problems (and is rarely a useful feature), and hence it is
+  recommended that you say Y here unless you really know what you're
+  doing.
 
 IP: Allow large windows (not recommend if <16Mb of memory)
 CONFIG_SKB_LARGE
-  On high speed, long distance networks the performance limit on 
+  On high speed, long distance networks the performance limit on
   networking becomes the amount of data a machine can buffer until the
-  other end confirms its reception. (At 45Mbit/second there are a lot
-  of bits between New York and London ..). This option allows larger
-  amounts of data to be "in flight" at a given time. It also means a user
-  process can require a lot more memory for network buffers and thus this
-  option is best only used on machines with 16Mb of memory or higher. 
+  other end confirms its reception.  (At 45Mbit/second there are a lot
+  of bits between New York and London...)  This option allows larger
+  amounts of data to be "in flight" at a given time.  It also means a
+  user process can require a lot more memory for network buffers and
+  thus this option is best only used on machines with 16Mb of
+  memory or higher.
   Unless you are using long links with end to end speeds of over 2Mbit
-  a second or   satellite links this option will make no difference to
+  a second or satellite links this option will make no difference to
   performance.
 
 The IPX protocol
@@ -1153,42 +1124,42 @@
 Full internal IPX network
 CONFIG_IPX_INTERN
   The full internal IPX network enables you to allocate sockets on
-  different virtual nodes of the internal network. This is done by
-  evaluating the field sipx_node of the socket address given to the bind
-  call. So applications should always initialize the node field to 0
-  when binding a socket on the primary network. In this case the socket
-  is assigned the default node that has been given to the kernel when
-  the internal network was created.
-  By enabling the full internal IPX network the cross-forwarding of
-  packets targeted at 'special' sockets to sockets listening on the
-  primary network is disabled. This might break existing applications,
-  especially RIP/SAP daemons. A RIP/SAP daemon that works well with the
-  full internal net can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs.
+  different virtual nodes of the internal network.  This is done by
+  evaluating the field sipx_node of the socket address given to the
+  bind call.  So applications should always initialize the node field
+  to 0 when binding a socket on the primary network.  In this case the
+  socket is assigned the default node that has been given to the
+  kernel when the internal network was created.  By enabling the full
+  internal IPX network the cross-forwarding of packets targeted at
+  'special' sockets to sockets listening on the primary network is
+  disabled.  This might break existing applications, especially
+  RIP/SAP daemons.  A RIP/SAP daemon that works well with the full
+  internal net can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs.
   If you don't know what you are doing, say N.
 
 Appletalk DDP
 CONFIG_ATALK
   Appletalk is the way Apple computers speak to each other on a
-  network. EtherTalk is the name used for appletalk over ethernet and
-  Localtalk is appletalk over the apple serial links. If your linux box 
-  is connected to such a network and you want to join the conversation,
-  say Y. You will need to use the netatalk package so that your Linux
-  box can act as a print and file server for macs as well as access
-  appletalk printers. Check out
-  http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
-  WWW for details (to browse the WWW, you need to have access to a
-  machine on the Internet that has one of the programs lynx, netscape
-  or Mosaic). The NET-2-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
-  as well. This driver is also available as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want). If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. I hear that the GNU boycott of Apple is
-  over, so even politically correct people are allowed to say Y here.
-  At the time the kernel is released the localtalk drivers are not
-  yet ready to ship. The kernel however supports localtalk and when
-  such drivers become available all you will need to do is download
-  and install the localtalk driver.
+  network.  EtherTalk is the name used for appletalk over ethernet
+  and Localtalk is appletalk over the apple serial links.  If your
+  linux box is connected to such a network and you want to join the
+  conversation, say Y.  You will need to use the netatalk package
+  so that your Linux box can act as a print and file server for
+  macs as well as access appletalk printers.  Check out
+  http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on
+  the WWW for details (to browse the WWW, you need to have access to
+  a machine on the Internet that has one of the programs lynx,
+  netscape or Mosaic).  The NET-2-HOWTO, available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains
+  valuable information as well.  This driver is also available as a
+  module (= code which can be inserted in and removed from the running
+  kernel whenever you want).  If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.  I hear that the GNU
+  boycott of Apple is over, so even politically correct people are
+  allowed to say Y here.  At the time the kernel is released the
+  localtalk drivers are not yet ready to ship.  The kernel however
+  supports localtalk and when such drivers become available all you
+  will need to do is download and install the localtalk driver.  
 
 Amateur Radio AX.25 Level 2
 CONFIG_AX25
@@ -1209,8 +1180,8 @@
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also
   want to check out the file Documentation/networking/ax25.txt in the
   kernel source. More information about digital amateur radio in
-  general is on the WWW at
-  http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
+  general is on the WWW at http://www.cis.ohio-state.edu/
+  /hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
   (To browse the WWW, you need to have access to a machine on the
   Internet that has one of the programs lynx, netscape or Mosaic).
 
@@ -1220,14 +1191,13 @@
   routing.  A comprehensive listing of all the software for Linux
   amateur radio users as well as information about how to configure an
   AX.25 port is contained in the HAM-HOWTO, available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. You also might
-  also want to check out the file
-  Documentation/networking/ax25.txt. More information about digital
-  amateur radio in general is on the WWW at
-  http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.  You also might
+  also want to check out the file Documentation/networking/ax25.txt.
+  More information about digital amateur radio in general is on the
+  WWW at http://www.cis.ohio-state.edu
+  /hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
   (To browse the WWW, you need to have access to a machine on the
-  Internet that has one of the programs lynx, netscape or
-  Mosaic). 
+  Internet that has one of the programs lynx, netscape or Mosaic).
 
 AX.25 over Ethernet
 CONFIG_BPQETHER
@@ -1241,33 +1211,32 @@
 CONFIG_BRIDGE
   If you say Y here, then your Linux box will be able to act as an
   ethernet bridge, which means that the different ethernet segments it
-  is connected to will appear as one ethernet to the
-  participants. Several such bridges can work together to create even
-  larger networks of ethernets using the IEEE802.1 spanning tree
-  algorithm. As this is a standard, Linux bridges will interwork
-  properly with other third party bridge products. In order to use
-  this, you'll need the bridge configuration tools available via ftp
-  (user: anonymous) from shadow.cabi.net. Note that if your box acts
-  as a bridge, it probably contains several ethernet devices, but the
-  kernel is not able to recognize more than one at boot time without
-  help; for details read the Multiple-Ethernet-mini-HOWTO, available
-  via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The Bridging code is
-  still in test. If unsure, say N.
+  is connected to will appear as one ethernet to the participants.
+  Several such bridges can work together to create even larger
+  networks of ethernets using the IEEE802.1 spanning tree algorithm.
+  As this is a standard, Linux bridges will interwork properly with
+  other third party bridge products. In order to use this, you'll need
+  the bridge configuration tools available via ftp (user: anonymous)
+  from shadow.cabi.net. Note that if your box acts as a bridge, it
+  probably contains several ethernet devices, but the kernel is not
+  able to recognize more than one at boot time without help; for
+  details read the Multiple-Ethernet-mini-HOWTO, available via ftp
+  (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  The Bridging code is still in test. If unsure, say N.
 
 Kernel/User network link driver (EXPERIMENTAL)
 CONFIG_NETLINK
   This driver allows for two-way communication between certain parts
   of the kernel or modules and user processes; the user processes are
   able to read from and write to character special files in the /dev
-  directory having major mode 36. So far, the kernel uses it to
+  directory having major mode 36.  So far, the kernel uses it to
   publish some network related information if you enable "Routing
-  messages", below. Say Y if you want to experiment with it; this is
-  EXPERIMENTAL code, which means that it need not be completely stable.
-  You need to include this if you want to use arpd, a daemon that
-  helps keep the internal ARP cache (a mapping between IP addresses
-  and hardware addresses on the local network) small. If unsure, say
-  N.
+  messages", below.  Say Y if you want to experiment with it; this is
+  EXPERIMENTAL code, which means that it need not be completely
+  stable.  You need to include this if you want to use arpd, a daemon
+  that helps keep the internal ARP cache (a mapping between IP
+  addresses and hardware addresses on the local network) small.
+  If unsure, say N.
 
 Routing messages
 CONFIG_RTNETLINK
@@ -1281,27 +1250,26 @@
   If you want to use a SCSI harddisk, SCSI tapedrive, SCSI CDROM or
   any other SCSI device under Linux, say Y and make sure that you know
   the name of your SCSI host adapter (the card inside your computer
-  that "speaks" the SCSI protocol), because you will be asked for
-  it. You also need to say Y here if you want support for the parallel
-  port version of the 100MB IOMEGA ZIP drive. Please read the
-  SCSI-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  This driver is also
-  available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). If you want to compile
-  it as a module, say M here and read Documentation/modules.txt and
-  Documentation/scsi.txt.
+  that "speaks" the SCSI protocol), because you will be asked for it.
+  You also need to say Y here if you want support for the parallel
+  port version of the 100MB IOMEGA ZIP drive.  Please read the
+  SCSI-HOWTO, available via ftp (user: anonymous) in sunsite.unc.edu:
+  /pub/Linux/docs/HOWTO.  This driver is also available as a module
+  (= code which can be inserted in and removed from the running kernel
+  whenever you want).  If you want to compile it as a module, say M
+  here and read Documentation/modules.txt and Documentation/scsi.txt.
 
 SCSI disk support
 CONFIG_BLK_DEV_SD
   If you want to use a SCSI harddisk or the SCSI or parallel port
-  version of the IOMEGA ZIP drive under Linux, say Y and read the
-  SCSI-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This is NOT for SCSI
-  CDROMs. This driver is also available as a module ( = code which can
-  be inserted in and removed from the running kernel whenever you
-  want). If you want to compile it as a module, say M here and read
+  version of the IOMEGA ZIP drive under Linux, say Y and read
+  the SCSI-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This is NOT for SCSI CDROMs.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
   Documentation/modules.txt and Documentation/scsi.txt.
-  
+
 SCSI tape support
 CONFIG_CHR_DEV_ST
   If you want to use a SCSI tapedrive under Linux, say Y and read the
@@ -1316,13 +1284,12 @@
 SCSI CDROM support
 CONFIG_BLK_DEV_SR
   If you want to use a SCSI CDROM under Linux, say Y and read the
-  SCSI-HOWTO and the CDROM-HOWTO from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also make sure to enable the
-  ISO9660 filesystem later. This driver is also available as a module
-  ( = code which can be inserted in and removed from the running
-  kernel whenever you want). If you want to compile it as a module,
-  say M here and read Documentation/modules.txt and
-  Documentation/scsi.txt .
+  SCSI-HOWTO and the CDROM-HOWTO from sunsite.unc.edu:
+  /pub/Linux/docs/HOWTO. Also make sure to enable the ISO9660
+  filesystem later. This driver is also available as a module ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt and Documentation/scsi.txt.
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
@@ -1345,7 +1312,7 @@
 CONFIG_SCSI_MULTI_LUN
   If you have a SCSI device that supports more than one LUN (Logical
   Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
-  can say Y here to force the SCSI driver to probe for multiple LUNs. 
+  can say Y here to force the SCSI driver to probe for multiple LUNs.
   A SCSI device with multiple LUNs acts logically like multiple SCSI
   devices.  The vast majority of SCSI devices have only one LUN, and
   so most people can say N here and should in fact do so, because it
@@ -1355,7 +1322,7 @@
 CONFIG_SCSI_CONSTANTS
   The error messages regarding your SCSI hardware will be easier to
   understand if you enable this; it will enlarge your kernel by about
-  12KB. If in doubt, say Y.
+  12KB.  If in doubt, say Y.
 
 AdvanSys SCSI support
 CONFIG_SCSI_ADVANSYS
@@ -1384,112 +1351,106 @@
   3.4 of the SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that Trantor was
   recently purchased by Adaptec, and some former Trantor products are
-  being sold under the Adaptec name. If it doesn't work out of
-  the box, you may have to change some settings in
-  drivers/scsi/aha1542.h.  If you want to compile this as a module ( =
-  code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
- 
+  being sold under the Adaptec name.  If it doesn't work out of the
+  box, you may have to change some settings in drivers/scsi/aha1542.h.
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt.
+
 Adaptec AHA1740 support
 CONFIG_SCSI_AHA1740
-  This is support for a SCSI host adapter. It is explained in section
-  3.5 of the SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If it doesn't work out of
-  the box, you may have to change some settings in
-  drivers/scsi/aha1740.h. This driver is also available as a module (
-  = code which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt.
+  This is support for a SCSI host adapter.  It is explained in
+  section 3.5 of the SCSI-HOWTO, available via ftp (user: anonymous)
+  at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If it doesn't work out
+  of the box, you may have to change some settings in
+  drivers/scsi/aha1740.h. This driver is also available as a module
+  ( = code which can be inserted in and removed from the running
+  kernel whenever you want). If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
 
 Adaptec AIC7xxx chipset SCSI controller support
 CONFIG_SCSI_AIC7XXX
-  This is support for the various aic7xxx based Adaptec SCSI controllers.
-  These include the 274x EISA cards, 284x VLB cards, 294x PCI cards,
-  394x PCI cards, 3985 PCI card, and several versions of the Adaptec
-  built-in SCSI controllers on various PC motherboards.  Information on
-  the configuration options for this controller can be found by checking
-  the help file for each of the available configuration options.
-
-Enable tagged command queueing
-CONFIG_AIC7XXX_TAGGED_QUEUEING
-  Tagged command queueing is used to allow acceptable devices to have more
-  than one SCSI command active on the SCSI bus at the same time.  Regardless
-  of this option setting, only devices that report they are capable of
-  tagged queueing will use this support.  This option is highly recommended
-  if you use any SCSI hard drives on your aic7xxx SCSI controller for
-  performance reasons.  Default: Y
+  This is support for the various aic7xxx based Adaptec SCSI
+  controllers.  These include the 274x EISA cards, 284x VLB cards,
+  294x PCI cards, 394x PCI cards, 3985 PCI card, and several versions
+  of the Adaptec built-in SCSI controllers on various PC motherboards.
+  Information on the configuration options for this controller can be
+  found by checking the README.aic7xxx file, usually in
+  /usr/src/linux/drivers/scsi.
 
 Override driver defaults for commands per LUN
 CONFIG_OVERRIDE_CMDS
-  Use this option to allow you to override the default maximum number of
-  commands that a single device on the aic7xxx controller is allowed to have
-  active at one time.  This option only effects tagged queueing capable
-  devices.  The driver uses a "failsafe" value of 8 by default.  This is
-  much lower than many devices can handle, but left in place for safety sake.
+  Use this option to allow you to override the default maximum number
+  of commands that a single device on the aic7xxx controller is
+  allowed to have active at one time.  This option only effects tagged
+  queueing capable devices.  The driver uses a "failsafe" value of 8
+  by default.  This is much lower than many devices can handle, but
+  left in place for safety sake.
+  NOTE:  This does not actually enabled tagged queueing on any
+  particular device.  The driver has changed in this respect.  Please
+  see the file README.aic7xxx in /usr/src/linux/drivers/scsi for more
+  information on how to get particular devices to use tagged command
+  queueing.
   Default: N
 
 Maximum number of commands per LUN
 CONFIG_AIC7XXX_CMDS_PER_LUN
-  Specify the maximum number of commands per lun you would like to allocate
-  per device.  Reasonable figures are in the range of 14 to 32 commands per
-  device, but depending on hardware could be increased or decreased from
-  that figure.  If the number is too high for any particular device, the
-  driver will automatically compensate usually after only 10 minutes of
-  uptime and will issue a message to alert you to the fact that the number
-  of commands for that device has been reduced.  It will not hinder
-  performance if a portion of your devices eventually have their commands
-  per lun reduced, but is a waste of memory if all of your devices end
-  up reducing this number down to a more reasonable figure.  Default: 24
-
-Enable SCB paging
-CONFIG_AIC7XXX_PAGE_ENABLE
-  This option allows the driver to issue more commands to the controller
-  than it has physical space to store.  Since some aic7xxx chipsets can only
-  store 3 commands, and the majority can only store 16, not enabling this
-  capability can effectively negate any performance increase you might get
-  from enabling Tagged Queueing.  Default: Y
+  Specify the maximum number of commands per lun you would like to
+  allocate per device.  Reasonable figures are in the range of 14 to
+  32 commands per device, but depending on hardware could be increased
+  or decreased from that figure.  If the number is too high for any
+  particular device, the driver will automatically compensate usually
+  after only 10 minutes of uptime and will issue a message to alert
+  you to the fact that the number of commands for that device has been
+  reduced.  It will not hinder performance if a portion of your
+  devices eventually have their commands per lun reduced, but is a
+  waste of memory if all of your devices end up reducing this number
+  down to a more reasonable figure.  Default: 24
 
 Collect statistics to report in /proc
 CONFIG_AIC7XXX_PROC_STATS
-  This option tells the driver to keep track of how many commands have been
-  sent to each particular device and report that information to the user
-  via the /proc/scsi/aic7xxx/x file, where x is the number of the aic7xxx
-  controller you want the information on.  This adds a small amount of
-  overhead to each and every SCSI command the aic7xxx driver handles, so if
-  you aren't really interested in this information, it is best to leave it
-  disabled.  Default: N
+  This option tells the driver to keep track of how many commands have
+  been sent to each particular device and report that information to
+  the user via the /proc/scsi/aic7xxx/x file, where x is the number
+  of the aic7xxx controller you want the information on.  This adds
+  a small amount of overhead to each and every SCSI command the
+  aic7xxx driver handles, so if you aren't really interested in this
+  information, it is best to leave it disabled.  Default: N
 
 Delay in seconds after SCSI bus reset
 CONFIG_AIC7XXX_RESET_DELAY
-  This sets how long the driver will wait after resetting the SCSI bus before
-  attempting to communicate with the devices on the SCSI bus again.  This
-  delay will be used during the reset phase at bootup time as well as after
-  any reset that might occur during normal operation.  Reasonable numbers
-  range anywhere from 5 to 15 seconds depending on your devices.  DAT tape
-  drives are notorious for needing more time after a bus reset to be
-  ready for the next command, but most hard drives and CD-ROM devices are
-  ready in only a few seconds.  This option has a maximum upper limit of
-  20 seconds to avoid bad interactions between the aic7xxx driver and the
-  rest of the linux kernel.  The default value is a "failsafe" value that
-  should work with just about any device.  Default: 15
+  This sets how long the driver will wait after resetting the SCSI bus
+  before attempting to communicate with the devices on the SCSI bus
+  again.  This delay will be used during the reset phase at bootup
+  time as well as after any reset that might occur during normal
+  operation.  Reasonable numbers range anywhere from 5 to 15 seconds
+  depending on your devices. DAT tape drives are notorious for needing
+  more time after a bus reset to be ready for the next command, but
+  most hard drives and CD-ROM devices are ready in only a few seconds.
+  This option has a maximum upper limit of 20 seconds to avoid bad
+  interactions between the aic7xxx driver and the rest of the linux
+  kernel.  The default value has been reduced.  If this doesn't work
+  with your hardware, try increasing this value.  Default: 5
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
-  This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters.
-  Consult the SCSI-HOWTO, available via anonymous ftp from sunsite.unc.edu in
-  /pub/Linux/docs/HOWTO, and the files README.BusLogic and README.FlashPoint in
-  drivers/scsi for more information.  If this driver does not work correctly
-  without modification, please contact the author, Leonard N. Zubkoff, by email
-  to lnz@dandelion.com.  You can also build this driver as a module ( = code
-  which can be inserted in and removed from the running kernel whenever you
-  want), but only a single instance may be loaded.  If you want to compile it
+  This is support for BusLogic MultiMaster and FlashPoint SCSI Host
+  Adapters.  Consult the SCSI-HOWTO, available via anonymous ftp from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO, and the files README.BusLogic
+  and README.FlashPoint in drivers/scsi for more information.  If this
+  driver does not work correctly without modification, please contact
+  the author, Leonard N. Zubkoff, by email to lnz@dandelion.com.
+  You can also build this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  but only a single instance may be loaded.  If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
 Omit BusLogic SCSI FlashPoint support
 CONFIG_SCSI_OMIT_FLASHPOINT
-  This option allows you to omit the FlashPoint support from the BusLogic
-  SCSI driver.  The FlashPoint SCCB Manager code is substantial, so users of
-  MultiMaster Host Adapters may wish to omit it.
+  This option allows you to omit the FlashPoint support from the
+  BusLogic SCSI driver.  The FlashPoint SCCB Manager code is
+  substantial, so users of MultiMaster Host Adapters may wish to
+  omit it.
 
 DTC3180/3280 SCSI support
 CONFIG_SCSI_DTC3280
@@ -1528,29 +1489,30 @@
 UltraStor 14F/34F support
 CONFIG_SCSI_U14_34F
   This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
-  The source at drivers/scsi/u14-34f.c contains some information about 
-  this hardware. If the driver doesn't work out of the box, you may have 
-  to change some settings in drivers/scsi/u14-34f.c.
-  Read the SCSI-HOWTO, available via ftp (user: anonymous) at 
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that there is also another
-  driver for the same hardware: "UltraStor SCSI support", below.
-  You should enable both only if you want 24F support as well. This
-  driver is also available as a module ( = code which can be inserted
-  in and removed from the running kernel whenever you want). If you
-  want to compile it as a module, say M here and read
+  The source at drivers/scsi/u14-34f.c contains some information about
+  this hardware.  If the driver doesn't work out of the box, you may
+  have to change some settings in drivers/scsi/u14-34f.c.
+  Read the SCSI-HOWTO, available via ftp (user: anonymous) at
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that there is also
+  another driver for the same hardware: "UltraStor SCSI support",
+  below.  You should enable both only if you want 24F support as well.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
 Future Domain 16xx SCSI support
 CONFIG_SCSI_FUTURE_DOMAIN
   This is support for Future Domain's 16-bit SCSI host adapters
-  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and other
-  adapters based on the Future Domain chipsets (Quantum ISA-200S,
-  ISA-250MG; Adaptec AHA-2920; and at least one IBM board).  It is
-  explained in section 3.7 of the SCSI-HOWTO, available via ftp (user:
-  anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  This driver is
-  also available as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want). If you want to
-  compile it as a module, say M here and read Documentation/modules.txt.
+  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX)
+  and other adapters based on the Future Domain chipsets (Quantum
+  ISA-200S, ISA-250MG; Adaptec AHA-2920; and at least one IBM board).
+  It is explained in section 3.7 of the SCSI-HOWTO, available via ftp
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Generic NCR5380/53c400 SCSI support
 CONFIG_SCSI_GENERIC_NCR5380
@@ -1563,7 +1525,7 @@
   ( = code which can be inserted in and removed from the running
   kernel whenever you want). If you want to compile it as a module,
   say M here and read Documentation/modules.txt.
- 
+
 Enable NCR53c400 extensions
 CONFIG_SCSI_GENERIC_NCR53C400
   This enables certain optimizations for the NCR53c400 scsi cards. You
@@ -1592,19 +1554,19 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-always negotiate synchronous transfers
+Always negotiate synchronous transfers
 CONFIG_SCSI_NCR53C7xx_sync
   In general, this is good; however, it is a bit dangerous since there
   are some broken SCSI devices out there. Take your chances. Safe bet
   is N.
 
-allow FAST-SCSI [10MHz]
+Allow FAST-SCSI [10MHz]
 CONFIG_SCSI_NCR53C7xx_FAST
-  This will enable 10MHz FAST-SCSI transfers with your host
-  adapter. Some systems have problems with that speed, so it's safest
-  to say N here.
- 
-allow DISCONNECT
+  This will enable 10MHz FAST-SCSI transfers with your host adapter.
+  Some systems have problems with that speed, so it's safest to say N
+  here.
+
+Allow DISCONNECT
 CONFIG_SCSI_NCR53C7xx_DISCONNECT
   This enables the disconnect/reconnect feature of the NCR SCSI
   controller.  When this is enabled, a slow SCSI device will not lock
@@ -1622,14 +1584,14 @@
   of PCI-SCSI controllers. This driver supports parity checking,
   tagged command queuing, fast scsi II transfer up to 10 MB/s with
   narrow scsi devices and 20 MB/s with wide scsi devices.
-  Support of Ultra SCSI data transfers with NCR53C860 and NCR53C875 
+  Support of Ultra SCSI data transfers with NCR53C860 and NCR53C875
   controllers has been recently added to the driver.
   Please read drivers/scsi/README.ncr53c8xx for more information.
   Linux/i386 and Linux/Alpha are supported by this driver.
 
-synchronous data transfers frequency
+Synchronous data transfers frequency
 CONFIG_SCSI_NCR53C8XX_SYNC
-  SCSI-2 specifications allow scsi devices to negotiate a synchronous 
+  SCSI-2 specifications allow scsi devices to negotiate a synchronous
   transfer period of 25 nano-seconds or more.
   The transfer period value is 4 times the agreed transfer period.
   So, data can be transferred at a 10 MHz frequency, allowing 10
@@ -1649,16 +1611,16 @@
   Use a 25 ns period for 10 Mhz synchronous data transfers.
   If you don't know what to do now, go with the default.
 
-use normal IO
+Use normal IO
 CONFIG_SCSI_NCR53C8XX_IOMAPPED
   This option allows you to force the driver to use normal IO.
-  Memory mapped IO has less latency than normal IO and works for most 
+  Memory mapped IO has less latency than normal IO and works for most
   Intel-based hardware.
-  Under Linux/Alpha only normal IO is currently supported by the driver 
-  and so, this option has no effect.
+  Under Linux/Alpha only normal IO is currently supported by the
+  driver and so, this option has no effect.
   The normal answer therefore is N.
 
-not allow targets to disconnect
+Not allow targets to disconnect
 CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
   This option is only provided for safety if you suspect some scsi
   device of yours to not support properly the target-disconnect
@@ -1666,7 +1628,7 @@
   not allow targets to disconnect is not reasonable if there is more
   than 1 device on a scsi bus.  The normal answer therefore is N.
 
-enable tagged command queuing
+Enable tagged command queuing
 CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
   This option allows you to enable tagged command queuing support at
   linux start-up.  Some scsi devices do not properly support this
@@ -1681,33 +1643,35 @@
   The safe answer therefore is N.
   The normal answer therefore is Y.
 
-maximum number of queued commands
+Maximum number of queued commands
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS
   This option allows you to specify the maximum number of commands
   that can be queued to a device, when tagged command queuing is
   possible.  The default value is 4. Minimum is 2, maximum is 12.  The
   normal answer therefore is the default one.
 
-detect and read serial NVRAM
+Detect and read serial NVRAM
 CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
   Enable support for reading the serial NVRAM data on Symbios and
-  some Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for
-  systems with more than one Symbios compatible controller where at least
-  one has a serial NVRAM, or for a system with a mixture of Symbios and
-  Tekram cards. Enables setting the boot order of host adaptors
-  to something other than the default order or "reverse probe" order. 
-  Also enables Symbios and Tekram cards to be distinguished so
-  CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in a system with a
-  mixture of Symbios and Tekram cards so the Symbios cards can make use of
-  the full range of Symbios features, differential, led pin, without
-  causing problems for the Tekram card(s).
+  some Symbios compatible cards, and Tekram DC390W/U/F cards.  Useful
+  for systems with more than one Symbios compatible controller where
+  at least one has a serial NVRAM, or for a system with a mixture of
+  Symbios and Tekram cards.  Enables setting the boot order of host
+  adaptors to something other than the default order or "reverse
+  probe" order.  Also enables Symbios and Tekram cards to be
+  distinguished so CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in
+  a system with a mixture of Symbios and Tekram cards so the Symbios
+  cards can make use of the full range of Symbios features,
+  differential, led pin, without causing problems for the Tekram
+  card(s).
       (added by Richard Waltham: dormouse@farsrobt.demon.co.uk)
-  Also enables setting host and targets SCSI features as defined in the 
-  user setup for each host using a serial NVRAM (added by the maintainer).
+  Also enables setting host and targets SCSI features as defined in
+  the user setup for each host using a serial NVRAM (added by the
+  maintainer).
   The default answer is N, the normal answer should be Y.
   Read drivers/scsi/README.ncr53c8xx for more information.
 
-assume boards are SYMBIOS compatible
+Assume boards are SYMBIOS compatible
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
   This option allows you to enable some features depending on GPIO
   wiring.  These General Purpose Input/Output pins can be used for
@@ -1722,97 +1686,95 @@
   0x12).  This option must be set to N if your system has at least one
   53C8XX based scsi board with a vendor-specific BIOS (example: Tekram
   DC-390/U/W/F).  If unsure, say N.
-  However, if all your non Symbios compatible boards have NvRAM, setting 
-  option CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT allows the driver to 
-  distinguish Symbios compatible boards from other ones.
-  So, you can answer Y if all non Symbios compatible boards have NVRAM.
+  However, if all your non Symbios compatible boards have NVRAM,
+  setting option CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT allows the driver
+  to distinguish Symbios compatible boards from other ones.  So,
+  you can answer Y if all non Symbios compatible boards have NVRAM.
 
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
-  This is support for an ISA bus SCSI host adapter. You'll find
-  more information in drivers/scsi/in2000.readme. If it doesn't
-  work out of the box, you may have to change the jumpers for IRQ
-  or address selection. If you want to compile this as a module 
-  ( = code which can be inserted in and removed from the running
-  kernel whenever you want), say M here and read 
-  Documentation/modules.txt.
+  This is support for an ISA bus SCSI host adapter.  You'll find more
+  information in drivers/scsi/in2000.readme.  If it doesn't work out
+  of the box, you may have to change the jumpers for IRQ or address
+  selection.  If you want to compile this as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt.
 
 PAS16 SCSI support
 CONFIG_SCSI_PAS16
-  This is support for a SCSI host adapter. It is explained in section
+  This is support for a SCSI host adapter.  It is explained in section
   3.10 of the SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
   box, you may have to change some settings in drivers/scsi/pas16.h.
- 
+
 Qlogic FAS SCSI support
 CONFIG_SCSI_QLOGIC_FAS
   This driver works only with the ISA, VLB, and PCMCIA versions of the
   Qlogic FastSCSI! cards as well as any other card based on the FASXX
   chip (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards); it
-  does NOT support the PCI version. The PCI versions are supported by
+  does NOT support the PCI version.  The PCI versions are supported by
   the Qlogic ISP driver though.  Information about this driver is
   contained in drivers/scsi/README.qlogicfas.  You should also read
   the SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also available
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want).  If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
 
 Qlogic ISP SCSI support (EXPERIMENTAL)
 CONFIG_SCSI_QLOGIC_ISP
   This driver works for all QLogic PCI SCSI host adapters (IQ-PCI,
-  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter
-  card is supported by the "AM53/79C974 PCI SCSI" driver). If you say
-  Y here, make sure to say Y to "PCI BIOS support" as well. More
-  information is contained in the file
-  drivers/scsi/README.qlogicisp. You should also read the SCSI-HOWTO,
-  available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also available
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card.  (This latter
+  card is supported by the "AM53/79C974 PCI SCSI" driver.)  If you
+  say Y here, make sure to say Y to "PCI BIOS support" as well.  More
+  information is contained in the file drivers/scsi/README.qlogicisp.
+  You should also read the SCSI-HOWTO, available via ftp (user:
+  anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want).  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Seagate ST-02 and Future Domain TMC-8xx SCSI support
 CONFIG_SCSI_SEAGATE
-  These are 8-bit SCSI controllers; the ST-01 is also supported by this
-  driver.  It is explained in section 3.9 of the SCSI-HOWTO, available
-  via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
-  box, you may have to change some settings in drivers/scsi/seagate.h.
+  These are 8-bit SCSI controllers; the ST-01 is also supported by
+  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
+  available via ftp (user: anonymous) at sunsite.unc.edu:
+  /pub/Linux/docs/HOWTO.  If it doesn't work out of the box, you may
+  have to change some settings in drivers/scsi/seagate.h.
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you
-  want). If you want to compile it as a module, say M here and read
+  want).  If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
 Trantor T128/T128F/T228 SCSI support
 CONFIG_SCSI_T128
-  This is support for a SCSI host adapter. It is explained in section
+  This is support for a SCSI host adapter.  It is explained in section
   3.11 of the SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If it doesn't work out of
-  the box, you may have to change some settings in
-  drivers/scsi/t128.h. Note that Trantor was recently purchased by
-  Adaptec, and some former Trantor products are being sold under the
-  Adaptec name.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
+  box, you may have to change some settings in drivers/scsi/t128.h.
+  Note that Trantor was recently purchased by Adaptec, and some former
+  Trantor products are being sold under the Adaptec name.
 
 UltraStor SCSI support
 CONFIG_SCSI_ULTRASTOR
   This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
-  adapter family. This driver is explained in section 3.12 of the
+  adapter family.  This driver is explained in section 3.12 of the
   SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
-  box, you may have to change some settings in
-  drivers/scsi/ultrastor.h. If you want to compile this as a module (
-  = code which can be inserted in and removed from the running kernel
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If it doesn't work out of
+  the box, you may have to change some settings in
+  drivers/scsi/ultrastor.h.  If you want to compile this as a module
+  (= code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
   Note that there is also another driver for UltraStor hardware:
   "UltraStor 14F/34F support", above.
- 
+
 7000FASST SCSI support
 CONFIG_SCSI_7000FASST
   This driver supports the Western Digital 7000 SCSI host adapter.
   Some information is in the source: drivers/scsi/wd7000.c.  This
   driver is also available as a module ( = code which can be inserted
-  in and removed from the running kernel whenever you want). If you
+  in and removed from the running kernel whenever you want).  If you
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
@@ -1821,10 +1783,10 @@
   This driver supports all the EATA/DMA-compliant SCSI host adapters
   and does not need any BIOS32 service.
   DPT ISA and all EISA i/o addresses are probed looking for the "EATA"
-  signature. If "PCI bios support" is enabled, the addresses of all the
-  PCI SCSI controllers reported by BIOS32 are probed as well.
+  signature.  If "PCI bios support" is enabled, the addresses of all
+  the PCI SCSI controllers reported by BIOS32 are probed as well.
   Note that there is also another driver for the same hardware:
-  "EATA-DMA support". You should enable only one of them.
+  "EATA-DMA support".  You should enable only one of them.
   You want to read the start of drivers/scsi/eata.c and the
   SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
@@ -1834,9 +1796,9 @@
 
 NCR53c406a SCSI support
 CONFIG_SCSI_NCR53C406A
-  This is support for the NCR53c406a SCSI host adapter. For user
+  This is support for the NCR53c406a SCSI host adapter.  For user
   configurable parameters, check out drivers/scsi/NCR53c406.c in the
-  kernel source. Also read the SCSI-HOWTO, available via ftp (user:
+  kernel source.  Also read the SCSI-HOWTO, available via ftp (user:
   anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to
   compile this driver as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
@@ -1846,7 +1808,7 @@
 CONFIG_SCSI_DC390T
   This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with
   the Am53C974A chip, and perhaps other cards using the same chip.
-  This driver does _not_ support the DC390W/U/F adaptor with the 
+  This driver does _not_ support the DC390W/U/F adaptor with the
   NCR/Symbios chips.
 
 AM53/79C974 PCI SCSI support
@@ -1855,15 +1817,17 @@
   drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
   available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you.
+  Use the native DC390 driver if you've got a Tekram DC390(T) PCI-SCSI
+  host adapter.
 
 GDT SCSI Disk Array Controller support
 CONFIG_SCSI_GDTH
-  This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI) 
+  This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI)
   manufactured by ICP vortex. It is documented in the kernel source in
   drivers/scsi/gdth.c and drivers/scsi/gdth.h. This driver is also
   available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). If you want to compile 
-  it as a module, say M here and read Documentation/modules.txt. 	
+  from the running kernel whenever you want). If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. 
 
 IOMEGA Parallel Port ZIP drive SCSI support
 CONFIG_SCSI_PPA
@@ -1882,6 +1846,15 @@
   the SCSI version of the ZIP drive: it will be supported
   automatically if you enabled the generic "SCSI disk support", above.
 
+IOMEGA ZIP drive - Buggy EPP chipset support
+CONFIG_SCSI_PPA_HAVE_PEDANTIC
+  Contacts with the Iomega driver development team indicate there are
+  a few reputably bad EPP implementations in existance. The following
+  mainboard chipsets will probably require the PEDANTIC option to
+  reliably transfer data:
+       Winbond xxx837
+       National Semiconductor PC87306 (early revisions)
+
 Network device support?
 CONFIG_NETDEVICES
   You can say N here in case you don't intend to connect to any other
@@ -1908,6 +1881,7 @@
   read Olaf Kirch's excellent book "Network Administrator's Guide", to
   be found in sunsite.unc.edu:/pub/Linux/docs/LDP.  If unsure, say Y.
 
+Ethernet (10 or 100Mbit)
 CONFIG_NET_ETHERNET
   Ethernet is the most common protocol used on Local Area Networks
   (LANs) in universities or companies. 10-base-2 and 10-base-T and
@@ -1924,88 +1898,87 @@
 CONFIG_DUMMY
   This is essentially a bit-bucket device (i.e. traffic you send to
   this device is consigned into oblivion) with a configurable IP
-  address. It is most commonly used in order to make your currently
-  inactive SLIP address seem like a real address for local
-  programs. If you use SLIP or PPP, you might want to enable it. Read
-  about it in the Network Administrator's Guide, available via ftp
-  (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/LDP. Since
-  this thing comes often handy, the default is Y. It won't enlarge
-  your kernel either. What a deal.  If you want to compile this as a
+  address.  It is most commonly used in order to make your currently
+  inactive SLIP address seem like a real address for local programs.
+  If you use SLIP or PPP, you might want to enable it.  Read about it
+  in the Network Administrator's Guide, available via ftp (user:
+  anonymous) from sunsite.unc.edu:/pub/Linux/docs/LDP.  Since this
+  thing comes often handy, the default is Y.  It won't enlarge your
+  kernel either.  What a deal.  If you want to compile this as a
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. If you want to use more than one dummy
   device at a time, you need to compile it as a module. Instead of
   'dummy', it will they will then be called 'dummy0', 'dummy1' etc.
-  
+
 SLIP (serial line) support
 CONFIG_SLIP
   Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
   connect to your Internet service provider or to connect to some
-  other local Unix box or if you want to configure your Linux box as a
-  Slip/CSlip server for other people to dial in.  SLIP (Serial Line
+  other local Unix box or if you want to configure your Linux box as
+  a Slip/CSlip server for other people to dial in.  SLIP (Serial Line
   Internet Protocol) is the protocol used to send Internet traffic
-  over telephone lines or serial cables (also known as
-  nullmodems). Normally, your access provider has to support SLIP in
-  order for you to be able to use it, but there is now a SLIP emulator
-  called SLiRP around (available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/system/Network/serial/) which allows you
-  to use SLIP over a regular dial up shell connection. If you plan to
-  use SLiRP, make sure to say Y to CSLIP, below. The NET-2-HOWTO,
-  available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO, explains how to configure
-  SLIP. Note that you don't need this option if you just want to run
-  term (term is a program which gives you almost full Internet
-  connectivity if you have a regular dial up shell account on some
-  Internet connected Unix computer. Read the Term-HOWTO). SLIP support
-  will enlarge your kernel by about 4kB. If unsure, say N.  If you
-  want to compile this as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt as well as
+  over telephone lines or serial cables (also known as nullmodems).
+  Normally, your access provider has to support SLIP in order for you
+  to be able to use it, but there is now a SLIP emulator called SLiRP
+  around (available via ftp (user: anonymous) from sunsite.unc.edu:
+  /pub/Linux/system/Network/serial/) which allows you to use SLIP over
+  a regular dial up shell connection.  If you plan to use SLiRP, make
+  sure to say Y to CSLIP, below.  The NET-2-HOWTO, available via ftp
+  (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO, explains
+  how to configure SLIP.  Note that you don't need this option if you
+  just want to run term (term is a program which gives you almost full
+  Internet connectivity if you have a regular dial up shell account on
+  some Internet connected Unix computer.  Read the Term-HOWTO).  SLIP
+  support will enlarge your kernel by about 4kB.  If unsure, say N.
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
-  
+
 CSLIP compressed headers
 CONFIG_SLIP_COMPRESSED
   This protocol is faster than SLIP because it uses compression on the
   TCP/IP headers (not on the data itself), but it has to be supported
   on both ends. Ask your access provider if you are not sure and say
-  Y, just in case. You will still be able to use plain SLIP. If you
+  Y, just in case.  You will still be able to use plain SLIP.  If you
   plan to use SLiRP, the SLIP emulator (available via ftp (user:
   anonymous) from sunsite.unc.edu:/pub/Linux/system/Network/serial/)
   which allows you to use SLIP over a regular dial up shell
-  connection, you definitely want to say Y here. The NET-2-HOWTO,
+  connection, you definitely want to say Y here.  The NET-2-HOWTO,
   available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, explains how to configure
-  CSLIP. This won't enlarge your kernel.
+  CSLIP.  This won't enlarge your kernel.
 
 Keepalive and linefill
 CONFIG_SLIP_SMART
   Adds additional capabilities to the SLIP driver to support the
-  RELCOM line fill and keepalive monitoring. Ideal on poor quality
+  RELCOM line fill and keepalive monitoring.  Ideal on poor quality
   analogue lines.
 
 Six bit SLIP encapsulation
 CONFIG_SLIP_MODE_SLIP6
   Just occasionally you may need to run IP over hostile serial
   networks that don't pass all control characters or are only seven
-  bit. Saying Y here adds an extra mode you can use with SLIP:
-  "slip6". In this mode, SLIP will only send normal ascii symbols over
-  the serial device. Naturally, this has to be supported at the other
-  end of the link as well. It's good enough, for example, to run IP
-  over the async ports of a Camtec JNT Pad. If unsure, say N.
+  bit.  Saying Y here adds an extra mode you can use with SLIP:
+  "slip6".  In this mode, SLIP will only send normal ascii symbols
+  over the serial device.  Naturally, this has to be supported at the
+  other end of the link as well.  It's good enough, for example, to
+  run IP over the async ports of a Camtec JNT Pad.  If unsure, say N.
 
 Radio network interfaces
 CONFIG_NET_RADIO
-  Radio based interfaces for Linux. This includes amateur radio
-  (AX.25), support for wireless ethernet and other systems. Note that
+  Radio based interfaces for Linux.  This includes amateur radio
+  (AX.25), support for wireless ethernet and other systems.  Note that
   the answer to this question won't directly affect the kernel:
   saying N will just cause this configure script to skip all the
   questions about radio interfaces. Some user-level drivers for scarab
   devices which don't require special kernel support are available via
-  ftp (user: anonymous) from shadow.cabi.net. If unsure, say N.
+  ftp (user: anonymous) from shadow.cabi.net.  If unsure, say N.
 
 PPP (point-to-point) support
 CONFIG_PPP
-  PPP (Point to Point Protocol) is a newer and better SLIP. It serves
+  PPP (Point to Point Protocol) is a newer and better SLIP.  It serves
   the same purpose: sending Internet traffic over telephone (and other
   serial) lines.  Ask your access provider if they support it, because
   otherwise you can't use it (not quite true any more: the free
@@ -2018,25 +1991,25 @@
   this option if you just want to run term (term is a program which
   gives you almost full Internet connectivity if you have a regular
   dial up shell account on some Internet connected UNIX computer. Read
-  the Term-HOWTO). The PPP option enlarges your kernel by about
-  16kB. This driver is also available as a module ( = code which can
-  be inserted in and removed from the running kernel whenever you
-  want). If you said Y to "Version information on all symbols" above,
-  then you cannot compile the PPP driver into the kernel; you can only
-  compile it as a module. If you want to compile it as a module, say M
-  here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. Note that, no matter what
+  the Term-HOWTO).  The PPP option enlarges your kernel by about 16kB.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you said Y to "Version information on all symbols" above, then
+  you cannot compile the PPP driver into the kernel; you can only
+  compile it as a module.  If you want to compile it as a module,
+  say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.  Note that, no matter what
   you do, the BSD compression code (used to compress the IP packets
   sent over the serial line; has to be supported at the other end as
   well) can only be compiled as a module; it is called bsd_comp.o and
   will show up in the directory modules once you have said "make
-  modules". If unsure, say N.
+  modules".  If unsure, say N.
 
-16 channels instead of 4 
+16 channels instead of 4
 CONFIG_PPP_LOTS
   Saying Y here will allow you to have up to 16 PPP connections
-  running in parallel. This is mainly useful if you intend your linux
-  box to act as a dial-in PPP server. Most people can say N.
+  running in parallel.  This is mainly useful if you intend your
+  linux box to act as a dial-in PPP server.  Most people can say N.
 
 STRIP (Starmode Radio IP) support
 CONFIG_STRIP
@@ -2050,15 +2023,15 @@
   many people into thinking that you can plug a Metricom modem into a
   phone line and use it as a modem.)  You can use STRIP on any Linux
   machine with a serial port, although it is obviously most useful for
-  people with laptop computers. If you think you might get a Metricom
+  people with laptop computers.  If you think you might get a Metricom
   radio in the future, there is no harm in saying yes to STRIP now,
   except that it makes the kernel a bit bigger.
 
 WIC (Radio IP bridge)
 CONFIG_WIC
   Support for the WIC parallel port radio bridge. You'll probably want
-  to say N.  If you want to compile this driver as a module though ( =
-  code which can be inserted in and removed from the running kernel
+  to say N.  If you want to compile this driver as a module though
+  (= code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
 
 Z8530 SCC kiss emulation driver for AX.25
@@ -2161,7 +2134,7 @@
   it as a module, say M here and read Documentation/modules.txt.
 
 Max open DLCI
-CONFIG_DLCI_COUNT 
+CONFIG_DLCI_COUNT
   This is the maximal number of logical point-to-point frame relay
   connections (the identifiers of which are called DCLIs) that
   the driver can handle. The default is probably fine.
@@ -2176,11 +2149,11 @@
 Sangoma S502A FRAD support
 CONFIG_SDLA
   Say Y here if you need a driver for the Sangoma S502A, S502E, and
-  S508 Frame Relay Access Devices. These are multi-protocol
-  cards, but only frame relay is supported by the driver at this
-  time. Please read Documentation/framerelay.txt. This driver is also
+  S508 Frame Relay Access Devices.  These are multi-protocol cards,
+  but only frame relay is supported by the driver at this time.
+  Please read Documentation/framerelay.txt.  This driver is also
   available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). If you want to compile
+  from the running kernel whenever you want).  If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
 Sun LANCE Ethernet support
@@ -2191,8 +2164,8 @@
 
 Sun Intel Ethernet support
 CONFIG_SUN_INTEL
-  This is support for the intel ethernet cards on some Sun workstations
-  (all those with a network interface 'ie0' under SunOS).
+  This is support for the intel ethernet cards on some Sun
+  workstations (all those with a network interface 'ie0' under SunOS).
 
 Western Digital/SMC cards
 CONFIG_NET_VENDOR_SMC
@@ -2235,8 +2208,8 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
   Important: There have been many reports that, with some motherboards
-  mixing an SMC Ultra and an Adaptec AHA1542 SCSI card causes corruption
-  problems with many operating systems.
+  mixing an SMC Ultra and an Adaptec AHA1542 SCSI card causes
+  corruption problems with many operating systems.
 
 SMC Ultra32 support
 CONFIG_ULTRA32
@@ -2279,28 +2252,28 @@
 3COM cards
 CONFIG_NET_VENDOR_3COM
   If you have a network (ethernet) card belonging to this class, say Y
-  and read the Ethernet-HOWTO, available via ftp (user: anonymous)
-  in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the answer to
-  this question doesn't directly affect the kernel: saying N will just
+  and read the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that the answer to this
+  question doesn't directly affect the kernel: saying N will just
   cause this configure script to skip all the questions about 3COM
   cards. If you say Y, you will be asked for your specific card in the
   following questions. If you plan to use more than one network card
   under linux, read the Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. 
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
 3c501 support
 CONFIG_EL1
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Also, consider buying a new
-  card, since the 3c501 is slow and obsolete. This driver is also 
+  card, since the 3c501 is slow and obsolete.  This driver is also
   available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). If you want to compile
-  it as a module, say M here and read Documentation/modules.txt as well
-  as Documentation/networking/net-modules.txt. If you plan to use more
-  than one network card under linux, read the 
-  Multiple-Ethernet-mini-HOWTO, available from 
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini - and don't use 3c501s.
+  from the running kernel whenever you want).  If you want to compile
+  it as a module, say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt.
+  If you plan to use more than one network card under linux,
+  read the Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini---and don't use 3c501s.
 
 3c503 support
 CONFIG_EL2
@@ -2310,9 +2283,9 @@
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want). If you want to compile it as a
   module, say M here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more
-  than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
+  Documentation/networking/net-modules.txt.
+  If you plan to use more than one network card under linux,
+  read the Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
 3c505 support
@@ -2324,9 +2297,9 @@
   compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more
-  than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
+  Documentation/networking/net-modules.txt.
+  If you plan to use more than one network card under linux,
+  read the Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
 3c507 support
@@ -2390,37 +2363,38 @@
 ARCnet support
 CONFIG_ARCNET
   If you have a network card of this type, say Y and check out the
-  (arguably) beautiful poetry in Documentation/networking/arcnet.txt. 
+  (arguably) beautiful poetry in Documentation/networking/arcnet.txt.
   You might also want to have a look at the Ethernet-HOWTO, available
   via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO
-  (even though ARCnet is not really ethernet). This driver is also
+  (even though ARCnet is not really ethernet).  This driver is also
   available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). If you want to compile it
-  as a module, say M here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more
-  than one network card under linux, read the
+  from the running kernel whenever you want).  If you want to compile
+  it as a module, say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt. If you plan to
+  use more than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
-  
+
 Enable arc0e (ARCnet "ether-encap" packet format)
 CONFIG_ARCNET_ETH
-  This allows you to use "ethernet encapsulation" with your ARCnet card
-  via the virtual arc0e device.  You only need arc0e if you want to
-  talk to nonstandard ARCnet software, specifically, DOS/Windows-style
-  "NDIS" drivers.  You do not need to enable this option to communicate
-  with industry-standard RFC1201 implementations, like the arcether.com
-  packet driver or most DOS/Windows ODI drivers.  RFC1201 is included
-  automatically as the arc0 device.  Please read the ARCnet
-  documentation in Documentation/networking/arcnet.txt for more
-  information about using arc0e and arc0s.
+  This allows you to use "ethernet encapsulation" with your ARCnet
+  card via the virtual arc0e device.  You only need arc0e if you want
+  to talk to nonstandard ARCnet software, specifically,
+  DOS/Windows-style "NDIS" drivers.  You do not need to enable this
+  option to communicate with industry-standard RFC1201
+  implementations, like the arcether.com packet driver or most
+  DOS/Windows ODI drivers.  RFC1201 is included automatically as the
+  arc0 device.  Please read the ARCnet documentation in
+  Documentation/networking/arcnet.txt for more information about
+  using arc0e and arc0s.
 
 Enable arc0s (ARCnet RFC1051 packet format)
 CONFIG_ARCNET_1051
   This allows you to use RFC1051 with your ARCnet card via the virtual
   arc0s device.  You only need arc0s if you want to talk to ARCnet
   software complying with the "old" standard, specifically, the DOS
-  arcnet.com packet driver, Amigas running AmiTCP, and some variants of
-  NetBSD.  You do not need to enable this option to communicate with
+  arcnet.com packet driver, Amigas running AmiTCP, and some variants
+  of NetBSD. You do not need to enable this option to communicate with
   industry-standard RFC1201 implementations, like the arcether.com
   packet driver or most DOS/Windows ODI drivers.  RFC1201 is included
   automatically as the arc0 device.  Please read the ARCnet
@@ -2492,17 +2466,18 @@
 FMV-181/182/183/184 support
 CONFIG_FMV18X
   If you have a Fujitsu FMV-181/182/183/184 network (ethernet) card,
-  say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous)
-  in sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also
-  available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). If you want to compile it
-  as a module, say M here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more
-  than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you use FMV-183 or
-  FMV-184 and it is not working, you may need to disable Plug & Play
-  mode of the card.
+  say Y and read the Ethernet-HOWTO, available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+  If you plan to use more than one network card under linux,
+  read the Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  If you use FMV-183 or FMV-184 and it is not working, you may need
+  to disable Plug & Play mode of the card.
 
 Intel EtherExpress/Pro 100B support'
 CONFIG_EEXPRESS_PRO100B
@@ -2558,7 +2533,7 @@
 Ottawa PI and PI/2 support
 CONFIG_PI
   This is a driver for the Ottawa Amateur Radio Club PI and PI2 cards,
-  which are commonly used to send internet traffic over amateur radio. 
+  which are commonly used to send internet traffic over amateur radio.
   More information about these cards is on the WWW at
   http://hydra.carleton.ca/info/pi2.html (To browse the WWW, you need
   to have access to a machine on the Internet that has one of the
@@ -2586,7 +2561,7 @@
     This driver is fairly stable and may be compiled as a module
   (wavelan.o). It implements many nice feature and the Wireless
   Extensions (you must get the Wireless tools from the net).
-    For documentation, refer to :
+    For documentation, refer to:
       o the wavelan man page, wireless tools man pages
       o wavelan.p.h and the source code
       o Ethernet-HOWTO, Multiple-Ethernet-mini-HOWTO, Module-HOWTO
@@ -2753,6 +2728,14 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
+TI ThunderLAN support (EXPERIMENTAL)
+CONFIG_TLAN
+  If you have a TLAN based network card which is supported by this
+  driver, say Y and read the Ethernet-HOWTO.  Devices currently
+  supported are the Compaq Netelligent 10, Netelligent 10/100, and
+  Internal NetFlex 3.  This driver is also available as a module.
+  Please email feedback to james.banks@caldera.com.
+
 Zenith Z-Note support
 CONFIG_ZNET
   The Zenith Z-Note notebook computer has a built-in network
@@ -2820,13 +2803,13 @@
   both drivers as modules. If you plan to use more than one network
   card under linux, read the Multiple-Ethernet-mini-HOWTO, available
   from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
- 
+
 Token Ring driver support
 CONFIG_TR
   Token Ring is IBM's way of communication on a local network; the
   rest of the world uses ethernet. If you are connected to a token
-  ring network and want to use your Token Ring card under Linux, say Y.
-  Most people can say N here.
+  ring network and want to use your Token Ring card under Linux,
+  say Y.  Most people can say N here.
 
 IBM Tropic chipset based adapter support
 CONFIG_IBMTR
@@ -2853,10 +2836,10 @@
   Most of these drivers use a file include/linux/<driver_name>.h where
   you can define your interface parameters and switch some internal
   goodies.
-  All these CDROM drivers are also usable as a module (= code which can
-  be inserted in and removed from the running kernel whenever you want).
-  If you want to compile them as module, say M instead of Y and read
-  Documentation/modules.txt.
+  All these CDROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want).  If you want to compile them as module, say M instead of Y
+  and read Documentation/modules.txt.
   If you want to use any of these CDROM drivers, you also have to say
   Y to "ISO9660 cdrom filesystem support" below (this answer will get
   "defaulted" for you if you enable any of the Linux CDROM drivers).
@@ -2875,14 +2858,14 @@
 Standard Mitsumi [no XA/Multisession] CDROM support
 CONFIG_MCD
   This is the older of the two drivers for the older Mitsumi models
-  LU-005, FX-001 and FX-001D. This is not the right driver for the 
-  FX-001DE and the triple or quad speed models (all these are IDE/ATAPI
-  models).
+  LU-005, FX-001 and FX-001D. This is not the right driver for
+  the FX-001DE and the triple or quad speed models (all these are
+  IDE/ATAPI models).
   With the old LU-005 model, the whole drive chassis slides out for
-  cd insertion.  The FX-xxx models use a motorized tray type mechanism.
-  Note that this driver does not support XA or MultiSession CDs (PhotoCDs).
-  There is a new driver (next question) which can do this. If you want
-  that one, say N here.
+  cd insertion. The FX-xxx models use a motorized tray type mechanism.
+  Note that this driver does not support XA or MultiSession CDs
+  (PhotoCDs).  There is a new driver (next question) which can do
+  this. If you want that one, say N here.
   If the driver doesn't work out of the box, you might want to have
   a look at linux/include/linux/mcd.h.
 
@@ -2890,10 +2873,10 @@
 CONFIG_MCDX
   Use this driver if you want to be able to read XA or MultiSession
   CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005,
-  FX-001 or FX-001D CDROM drive. In addition, this driver uses much less
-  kernel memory than the old one, if that is a concern. This driver is
-  able to support more than one drive, but each drive needs a separate
-  interface card. Check out Documentation/cdrom/mcdx.
+  FX-001 or FX-001D CDROM drive.  In addition, this driver uses much
+  less kernel memory than the old one, if that is a concern.  This
+  driver is able to support more than one drive, but each drive needs
+  a separate interface card.  Check out Documentation/cdrom/mcdx.
 
 Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support
 CONFIG_SBPCD
@@ -2913,7 +2896,7 @@
   addresses and drive types; this can help to find facts in cases you
   are not sure, but can consume some time during the boot process if
   none of the supported drives gets found.
-  Once your drive got found, you should enter the reported parameters 
+  Once your drive got found, you should enter the reported parameters
   into linux/include/linux/sbpcd.h and set "DISTRIBUTION 0" there.
   This driver can support up to four CDROM interface cards, and each
   card can support up to four CDROM drives; if you say Y here, you
@@ -2938,7 +2921,8 @@
 
 Sony CDU535 CDROM support
 CONFIG_CDU535
-  This is the driver for the older Sony CDU-535 and CDU-531 CDROM drives.
+  This is the driver for the older Sony CDU-535 and CDU-531 CDROM
+  drives.
 
 Goldstar R420 CDROM support
 CONFIG_GSCD
@@ -2958,7 +2942,7 @@
   compatible interface. It also works with the Lasermate CR328A. If
   you have one of those, say Y. This driver does not work for the
   Optics Storage 8001 drive; use the IDE-ATAPI CDROM driver for that
-  one. 
+  one.
 
 Sanyo CDR-H94A CDROM support
 CONFIG_SJCD
@@ -2990,8 +2974,8 @@
   The command line
                 isp16=noisp16
   will skip detection and configuration after all.
-  N.B. options are case sensitive. 
-  Read Documentation/cdrom/isp16 for details. 
+  N.B. options are case sensitive.
+  Read Documentation/cdrom/isp16 for details.
 
 Quota support
 CONFIG_QUOTA
@@ -3077,7 +3061,7 @@
   FAT support. This is not a filesystem in itself, but it provides
   the foundation for the other filesystems. This option will enlarge
   your kernel about 24 kB. If unsure, say Y. If you want to compile
-  this as a module however ( = code which can be inserted in and 
+  this as a module however ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt. Note that if you compile the FAT
   support as a module, you cannot compile any of the FAT-based file-
@@ -3114,16 +3098,16 @@
 vfat fs support
 CONFIG_VFAT_FS
   This allows you to mount MSDOS partitions of your harddrive. It
-  will let you use filenames in a way compatible with the long 
+  will let you use filenames in a way compatible with the long
   filenames used by Windows'95 and Windows NT fat-based (not NTFS)
   partitions. It does not support Windows'95 compressed filesystems.
   You cannot use the VFAT filesystem for your root partition; use
   UMSDOS instead. This option enlarges your kernel by about 10 kB and
   it only works if you enabled the "fat fs support" above. Please read
   the file Documentation/filesystems/vfat.txt for details.
-  If unsure, say N. If you want to compile this as a module ( = code 
-  which can be inserted in and removed from the running kernel whenever 
-  you want), say M here and read Documentation/modules.txt.
+  If unsure, say N. If you want to compile this as a module ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read Documentation/modules.txt.
 
 umsdos: Unix like fs on top of std MSDOS fs
 CONFIG_UMSDOS_FS
@@ -3146,6 +3130,158 @@
   Documentation/modules.txt. Note that the filesystem of your root
   partition cannot be a module.
 
+nls: Native language codepages and Unicode support
+CONFIG_NLS
+  This is required by the FAT based filesystems and by the ISO9660
+  filesystem with Joliet support.  Joliet is a Microsoft extension
+  for CDROMs that supports Unicode.
+  This allows translation between different character sets.  When
+  dealing with the FAT based filesystems, there are two character
+  sets that are important. The first is the codepage.  Codepages are
+  character sets that are used by DOS to allow filenames to have
+  native language characters when character sets were limited to
+  256 characters. The codepage is the character set that is used to
+  store native language characters on disk.
+  The two most common codepages are 437 in the United States and 850
+  in much of Europe. The second important character set is the
+  input/output character set. This is the character set that is
+  displayed on the screen. In the United States, this will almost
+  always be the ISO 8859-1 character set. This is the default. Linux
+  will only do a translation of the FAT filenames, not the contents
+  of the files.
+
+nls iso8859-1
+CONFIG_NLS_ISO8859_1
+  ISO8859-1 is the Latin 1 character set, and it covers most West
+  European languages such as Albanian, Catalan, Danish, Dutch,
+  English, Faeroese, Finnish, French, German, Galician, Irish,
+  Icelandic, Italian, Norwegian, Portuguese, Spanish, Swedish, and
+  Valencian.
+
+nls iso8859-2
+CONFIG_NLS_ISO8859_2
+  ISO8859-2 is the Latin 2 character set, and it works for most
+  Latin-written Slavic and Central European languages: Czech, German,
+  Hungarian, Polish, Rumanian, Croatian, Slovak, Slovene.
+
+nls iso8859-3
+CONFIG_NLS_ISO8859_3
+  ISO8859-3 is the Latin 3 character set, and it s popular with
+  authors of Esperanto, Galician, Maltese, and Turkish.
+
+nls iso8859-4
+CONFIG_NLS_ISO8859_4
+  ISO8859-4 is the Latin 4 character set, and it introduces letters
+  for Estonian, Latvian, and Lithuanian. It is an incomplete
+  predecessor of Latin 6.
+
+nls iso8859-5
+CONFIG_NLS_ISO8859_5
+  ISO8859-5 is a Cyrillic character set, and you can type Bulgarian,
+  Byelorussian, Macedonian, Russian, Serbian, and Ukrainian.
+  Note that the charset KOI8-R is preferred in Russia.
+
+nls iso8859-6
+CONFIG_NLS_ISO8859_6
+  ISO8859-6 is the Arabic character set.
+
+nls iso8859-7
+CONFIG_NLS_ISO8859_7
+  ISO8859-7 is the Modern Greek character set.
+
+nls iso8859-8
+CONFIG_NLS_ISO8859_8
+  ISO8859-8 is the Hebrew character set.
+
+nls iso8859-9
+CONFIG_NLS_ISO8859_9
+  ISO8859-9 is the Latin 5 character set, and it replaces the rarely
+  needed Icelandic letters in Latin 1 with the Turkish ones.
+  Useful in Turkey.
+
+nls iso8859-10
+CONFIG_NLS_ISO8859_10
+  ISO8859-10 is the Latin 6 character set, and it adds the last
+  Inuit (Greenlandic) and Sami (Lappish) letters that were missing
+  in Latin 4 to cover the entire Nordic area.
+
+nls koi8-r
+CONFIG_NLS_KOI8_R
+  This is the preferred Russian character set.
+
+nls codepage 437
+CONFIG_NLS_CODEPAGE_437
+  This is the DOS codepage that is used in the United States and parts
+  of Canada.
+
+nls codepage 737
+CONFIG_NLS_CODEPAGE_737
+  This is the codepage used by DOS for Greek.
+
+nls codepage 775
+CONFIG_NLS_CODEPAGE_775
+  This is the codepage used by DOS for the Baltic Rim Languages.
+
+nls codepage 850
+CONFIG_NLS_CODEPAGE_850
+  This is the DOS codepage that is used in much of Europe--United
+  Kingdom, Germany, Spain, Italy, and [add more countries here].
+  It has some characters useful to many European languages that are
+  not part of codepage 437.
+
+nls codepage 852
+CONFIG_NLS_CODEPAGE_852
+  This is the Latin 2 codepage used by DOS for much of Central and
+  Eastern Europe.  It has all the required characters for these
+  languages: Albanian, Croatian, Czech, English, Finnish, Hungarian,
+  Irish, German, Polish, Romanian, Serbian (Latin transcription),
+  Slovak, Slovenian, and Sorbian.
+
+nls codepage 855
+CONFIG_NLS_CODEPAGE_855
+  This is the DOS codepage that is used for Cyrillic.
+
+nls codepage 857
+CONFIG_NLS_CODEPAGE_857
+  This is the DOS codepage that is used for Turkish.
+
+nls codepage 860
+CONFIG_NLS_CODEPAGE_860
+  This is the DOS codepage that is used for Portuguese.
+
+nls codepage 861
+CONFIG_NLS_CODEPAGE_861
+  This is the DOS codepage that is used for Icelandic.
+
+nls codepage 862
+CONFIG_NLS_CODEPAGE_862
+  This is the DOS codepage that is used for Hebrew.
+
+nls codepage 863
+CONFIG_NLS_CODEPAGE_863
+  This is the DOS codepage that is used for Canadian French.
+
+nls codepage 864
+CONFIG_NLS_CODEPAGE_864
+  This is the DOS codepage that is used for Arabic.
+
+nls codepage 865
+CONFIG_NLS_CODEPAGE_865
+  This is the DOS codepage that is used in the Nordic European
+  countries.
+
+nls codepage 866
+CONFIG_NLS_CODEPAGE_866
+  This is the DOS codepage that is used for Cyrillic/Russian.
+
+nls codepage 869
+CONFIG_NLS_CODEPAGE_869
+  This is the DOS codepage that is used for Greek.
+
+nls codepage 874
+CONFIG_NLS_CODEPAGE_874
+  This is the DOS codepage that is used for Thai.
+
 /proc filesystem support
 CONFIG_PROC_FS
   This is a virtual filesystem providing information about the status
@@ -3163,7 +3299,7 @@
   source of trouble if two devices are mistakenly configured to use
   the same IRQ). Several programs depend on this, so everyone should
   say Y here.
-  
+
 NFS filesystem support
 CONFIG_NFS_FS
   If you are connected to some other (usually local) Unix computer
@@ -3245,7 +3381,7 @@
   inserted in and removed from the running kernel whenever you
   want). If you want to compile it as a module, say M here and read
   Documentation/modules.txt. If unsure, say N.
-  
+
 System V and Coherent filesystem support
 CONFIG_SYSV_FS
   SCO, Xenix and Coherent are commercial Unix systems for intel
@@ -3318,12 +3454,12 @@
 SMD disklabel (Sun partition tables) support
 CONFIG_SMD_DISKLABEL
   Like most systems, SunOS uses its own partition table format,
-  incompatible with all others. Enabling this option allows you to read
-  these partition tables and further mount SunOS disks on your Linux
-  box if you also have configured BSD ufs filesystem support. This is
-  mainly used to carry data from a Sparc under SunOS to your Linux box
-  via a removable medium like magneto-optical or ZIP drives. If you
-  don't know what all this is about, say N.
+  incompatible with all others.  Enabling this option allows you to
+  read these partition tables and further mount SunOS disks on your
+  Linux box if you also have configured BSD ufs filesystem support.
+  This is mainly used to carry data from a Sparc under SunOS to your
+  Linux box via a removable medium like magneto-optical or ZIP drives.
+  If you don't know what all this is about, say N.
 
 SMB filesystem support (to mount WfW shares etc..)
 CONFIG_SMB_FS
@@ -3367,20 +3503,21 @@
 
 Amiga FFS filesystem support (EXPERIMENTAL)
 CONFIG_AFFS_FS
-  The Fast File System (FFS) is the common filesystem used on harddisks
-  by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also
-  possible to mount diskfiles used by the Un*X Amiga Emulator by Bernd
-  Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html)
+  The Fast File System (FFS) is the common filesystem used on
+  harddisks by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20).
+  It's also possible to mount diskfiles used by
+  the Un*X Amiga Emulator by Bernd Schmidt
+  (http://www-users.informatik.rwth-aachen.de/~crux/uae.html).
   If you want to do the latter, you will also need the loop device
-  support. Say Y if you want to be able to read and write files from
-  and to an Amiga FFS partition of your harddrive. Amiga floppies
+  support.   Say Y if you want to be able to read and write files from
+  and to an Amiga FFS partition of your harddrive.  Amiga floppies
   however cannot be read with this driver due to an incompatibility of
   the floppy controller used in an Amiga and the standard floppy
-  controller in PCs and workstations. Read
-  Documentation/filesystems/affs.txt. This filesystem is also available
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  controller in PCs and workstations.  Read
+  Documentation/filesystems/affs.txt.  This filesystem is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
   If unsure, say N.
 
 Standard/generic serial support
@@ -3428,7 +3565,7 @@
   safe to say N. (As of 1.3.9x kernels, this driver's minor numbers
   start at 0 instead of 32.)
 
-Stallion multiport serial support 
+Stallion multiport serial support
 CONFIG_STALDRV
   Stallion cards give you many serial ports. You would need something
   like this to connect more than two modems to your linux box, for
@@ -3436,8 +3573,8 @@
   asked for your specific card model in the next questions. Make sure
   to read drivers/char/README.stallion in this case. If you have never
   heard about all this, it's safe to say N.
- 
-Stallion EasyIO or EC8/32 support 
+
+Stallion EasyIO or EC8/32 support
 CONFIG_STALLION n
   If you have an EasyIO or EasyConnection 8/32 multiport Stallion
   card, then this is for you; say Y. Make sure to read
@@ -3508,7 +3645,7 @@
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. If you are unsure, say N and read the
-  HOWTO nevertheless: it will tell you what you have. 
+  HOWTO nevertheless: it will tell you what you have.
 
 PS/2 mouse (aka "auxiliary device") support
 CONFIG_PSMOUSE
@@ -3556,7 +3693,7 @@
   compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt. If you are unsure, say N and read
-  the HOWTO nevertheless: it will tell you what you have. 
+  the HOWTO nevertheless: it will tell you what you have.
 
 Support for user miscellaneous modules
 CONFIG_UMISC
@@ -3629,26 +3766,26 @@
 CONFIG_APM_DO_ENABLE
   Enable APM features at boot time.  From page 36 of the APM BIOS
   specification: "When disabled, the APM BIOS does not automatically
-  power manage devices, enter the Standby State, enter the Suspend State,
-  or take power saving steps in response to CPU Idle calls."  This driver
-  will make CPU Idle calls when Linux is idle (unless this feature is
-  turned off -- see below).  This should always save battery power, but
-  more complicated APM features will be dependent on your BIOS
-  implementation.  You may need to turn this option off if your computer
-  hangs at boot time when using APM support, or if it beeps continuously
-  instead of suspending.  Turn this off if you have a NEC UltraLite Versa
-  33/C or a Toshiba T400CDT.  This is off by default since most machines
-  do fine without this feature.
+  power manage devices, enter the Standby State, enter the Suspend
+  State, or take power saving steps in response to CPU Idle calls."
+  This driver will make CPU Idle calls when Linux is idle (unless this
+  feature is turned off -- see below).  This should always save
+  battery power, but more complicated APM features will be dependent
+  on your BIOS implementation.  You may need to turn this option off
+  if your computer hangs at boot time when using APM support, or if it
+  beeps continuously instead of suspending.  Turn this off if you have
+  a NEC UltraLite Versa 33/C or a Toshiba T400CDT.  This is off by
+  default since most machines do fine without this feature.
 
 Do CPU IDLE calls
 CONFIG_APM_CPU_IDLE
   Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
-  On some machines, this can activate improved power savings, such as a
-  slowed CPU clock rate, when the machine is idle.  These idle calls are
-  made after the idle loop has run for some length of time (e.g., 333
-  mS).  On some machines, this will cause a hang at boot time or whenever
-  the CPU becomes idle.  (On machines with more than one CPU, this option
-  does nothing.)
+  On some machines, this can activate improved power savings, such as
+  a slowed CPU clock rate, when the machine is idle.  These idle calls
+  are made after the idle loop has run for some length of time (e.g.,
+  333 ms).  On some machines, this will cause a hang at boot time or
+  whenever the CPU becomes idle.  (On machines with more than one CPU,
+  this option does nothing.)
 
 Enable console blanking using APM
 CONFIG_APM_DISPLAY_BLANK
@@ -3657,17 +3794,25 @@
   screen.  Note that this is only used by the VC screen blanker, and
   won't turn off the backlight when using X11 (this also doesn't have
   anything to do with your VESA-compliant power-saving monitor).
-  Further, this option doesn't work for all laptops -- it might not turn
-  off your backlight at all, or it might print a lot of errors to the
-  console, especially if you are using gpm.
+  Further, this option doesn't work for all laptops---it might not
+  turn off your backlight at all, or it might print a lot of errors to
+  the console, especially if you are using gpm.
 
-Power off on shutdown 
+Power off on shutdown
 CONFIG_APM_POWER_OFF
-  This option will power off the computer after the Linux kernel is halted
-  (e.g., with the halt(8) command).  As with the other APM options, this
-  option may not work reliably with some APM BIOS implementations.
+  This option will power off the computer after the Linux kernel is
+  halted (e.g., with the halt(8) command).  As with the other APM
+  options, this option may not work reliably with some APM BIOS
+  implementations.
+
+Ignore multiple suspend/standby events
+CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+  This option is necessary on the Thinkpad 560, but should work on all
+  other laptops. When the APM BIOS returns multiple suspend or standby
+  events while one is already being processed they will be ignored.
+  Without this the Thinkpad 560 has troubles with apmd, and pcmcia-cs.
 
-Watchdog Timer Support 
+Watchdog Timer Support
 CONFIG_WATCHDOG
   If you enable this option and create a character special file
   /dev/watchdog with major number 10 and minor number 130 using mknod
@@ -3713,8 +3858,8 @@
 
 Fan Tachometer
 CONFIG_WDT_501_FAN
-  Enable the Fan Tachometer on the WDT501. Only do this if you have a fan
-  tachometer actually set up.
+  Enable the Fan Tachometer on the WDT501. Only do this if you have
+  a fan tachometer actually set up.
 
 Software Watchdog
 CONFIG_SOFT_WATCHDOG
@@ -3764,11 +3909,11 @@
   information in various README files in drivers/sound.  If you want
   to compile this as a module ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. I'm told that even without a sound
-  card, you can make your computer say more than an occasional beep,
-  by programming the PC speaker. Kernel patches and programs to do
-  that are at
-  sunsite.unc.edu:/pub/Linux/kernel/patches/console/pcsndrv-X.X.tar.gz,
+  read Documentation/modules.txt.
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and programs to do that are at sunsite.unc.edu:
+  /pub/Linux/kernel/patches/console/pcsndrv-X.X.tar.gz,
   to be extracted with "tar xzvf filename".
 
 ProAudioSpectrum 16 support
@@ -3884,14 +4029,9 @@
 
 Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
 CONFIG_MAUI
-  Enable this option if you have a Turtle Beach Wave Front, Maui, or 
+  Enable this option if you have a Turtle Beach Wave Front, Maui, or
   Tropez sound card.
 
-Support for Crystal CS4232 based (PnP) cards
-CONFIG_CS4232
-  Use this option to enable experimental support for cards that use
-  the Plug and Play protocol.
-
 /dev/dsp and /dev/audio support
 CONFIG_AUDIO
   Answering N disables /dev/dsp and /dev/audio, the A/D and D/A
@@ -3923,7 +4063,7 @@
   become a kernel hacker, you can start with the Kernel Hacker's
   Guide, available via ftp (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/LDP. Mere mortals say N.
- 
+
 Profile shift count
 CONFIG_PROFILE_SHIFT
   This is used to adjust the granularity with which the addresses of
@@ -3977,7 +4117,7 @@
   (mgetty+sendfax by gert@greenie.muc.de with an extension, available
   with the ISDN utility package for example), you will be able
   to use your Linux box as an ISDN-answering machine. Of course, this
-  must be supported by the lowlevel driver also. Currently HiSax 
+  must be supported by the lowlevel driver also. Currently HiSax
   driver is the only voice-supporting drivers. See
   Documentation/isdn/README.audio for more information.
 
@@ -3996,8 +4136,8 @@
   This driver replaces the old Teles driver. It supports the Siemens
   chipset in a more general way. This chipset is used on various
   ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0,
-  Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and 
-  many compatibles). It's a complete rewrite of the original Teles 
+  Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and
+  many compatibles). It's a complete rewrite of the original Teles
   driver.
   See Documentation/isdn/README.HiSax for further informations on
   using this driver.
@@ -4006,7 +4146,7 @@
 CONFIG_HISAX_16_0
   This enables HiSax support for the Teles ISDN-cards S0-16.0,
   S0-8 and many compatibles.
-  See Documentation/isdn/README.HiSax on how to configure it 
+  See Documentation/isdn/README.HiSax on how to configure it
   using the different cards, a different D-channel protocol, or
   non-standard irq/port/shmem settings.
 
@@ -4014,7 +4154,7 @@
 CONFIG_HISAX_16_3
   This enables HiSax support for the Teles ISDN-cards S0-16.3
   the Teles/Creatix PnP and the Teles PCMCIA.
-  See Documentation/isdn/README.HiSax on how to configure it 
+  See Documentation/isdn/README.HiSax on how to configure it
   using the different cards, a different D-channel protocol, or
   non-standard irq/port/shmem settings.
 
@@ -4031,7 +4171,7 @@
   for the Elsa Quickstep series cards for the ISA bus.
   You don't have to select "HiSax Support for Elsa PCMCIA card"
   at the same time.
-  See Documentation/isdn/README.HiSax on how to configure it 
+  See Documentation/isdn/README.HiSax on how to configure it
   using the different cards, a different D-channel protocol, or
   non-standard irq/port/shmem settings.
 
@@ -4040,14 +4180,14 @@
   This enables HiSax support for the Elsa PCMCIA card.
   You don't have to select "HiSax Support for Elsa ISA cards" at
   the same time.
-  See Documentation/isdn/README.HiSax on how to configure it 
+  See Documentation/isdn/README.HiSax on how to configure it
   using the different cards, a different D-channel protocol, or
   non-standard irq/port/shmem settings.
 
 HiSax Support for ITK ix1-micro Revision 2
 CONFIG_HISAX_IX1MICROR2
   This enables HiSax support for the ITK ix1-micro Revision 2 card.
-  See Documentation/isdn/README.HiSax on how to configure it 
+  See Documentation/isdn/README.HiSax on how to configure it
   using the different cards, a different D-channel protocol, or
   non-standard irq/port/shmem settings.
 
diff -u --recursive --new-file v2.0.33/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd
--- v2.0.33/linux/Documentation/cdrom/ide-cd	Wed Sep 25 01:12:11 1996
+++ linux/Documentation/cdrom/ide-cd	Wed Jun  3 15:17:46 1998
@@ -277,7 +277,16 @@
     there are hardware problems with the interrupt setup; they
     apparently don't use interrupts.
 
-
+  - If you own a Pioneer DR-A24X, you _will_ get nasty error messages 
+    on boot such as "irq timeout: status=0x50 { DriveReady SeekComplete }"
+    The Pioneer DR-A24X cdrom drives are fairly popular these days.
+    Unfortunatly, these drives seem to become very confused when we perform
+    the standard Linux ATA disk drive probe. If you own one of these drives,
+    you can bypass the ATA probing which confuses these cdrom drives, by 
+    adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and runing 
+    lilo (again where X is the drive letter corresponding to where your drive 
+    is installed (see section 2))
+    
 c. System hangups.
 
   - If the system locks up when you try to access the cdrom, the most
diff -u --recursive --new-file v2.0.33/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.0.33/linux/Documentation/devices.txt	Wed Jul 10 03:11:44 1996
+++ linux/Documentation/devices.txt	Wed Jun  3 15:17:46 1998
@@ -78,10 +78,14 @@
 		  the position within the series.
   
     block	Floppy disks
-		  0 = /dev/fd0		First floppy disk autodetect
-		  1 = /dev/fd1		Second floppy disk autodetect
-		  2 = /dev/fd2		Third floppy disk autodetect
-		  3 = /dev/fd3		Fourth floppy disk autodetect
+		  0 = /dev/fd0		Controller 1, drive 1 autodetect
+		  1 = /dev/fd1		Controller 1, drive 2 autodetect
+		  2 = /dev/fd2		Controller 1, drive 3 autodetect
+		  3 = /dev/fd3		Controller 1, drive 4 autodetect
+		128 = /dev/fd4		Controller 2, drive 1 autodetect
+		129 = /dev/fd5		Controller 2, drive 2 autodetect
+		130 = /dev/fd6		Controller 2, drive 3 autodetect
+		131 = /dev/fd7		Controller 2, drive 4 autodetect
 
 		To specify format, add to the autodetect device number:
 		  0 = /dev/fd?		Autodetect format
diff -u --recursive --new-file v2.0.33/linux/Documentation/filesystems/00-INDEX linux/Documentation/filesystems/00-INDEX
--- v2.0.33/linux/Documentation/filesystems/00-INDEX	Sat Nov 30 02:21:18 1996
+++ linux/Documentation/filesystems/00-INDEX	Wed Jun  3 15:17:46 1998
@@ -4,6 +4,8 @@
 	- info and mount options for the Amiga Fast File System.
 hpfs.txt
 	- info and mount options for the OS/2 HPFS.
+isofs.txt
+	- info and mount options for the ISO9660 (CDROM) filesystem.
 ncpfs.txt
 	- info on Novell Netware(tm) filesystem using NCP protocol.
 smbfs.txt
diff -u --recursive --new-file v2.0.33/linux/Documentation/filesystems/isofs.txt linux/Documentation/filesystems/isofs.txt
--- v2.0.33/linux/Documentation/filesystems/isofs.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/filesystems/isofs.txt	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,31 @@
+Mount options that are the same as for msdos partitions.
+
+  uid=nnn	All files in the partition will be owned by user id nnn.
+  gid=nnn	All files in the partition will be in group nnn.
+  umask=nnn	The permission mask (see umask(1)) for the partition.
+  conv=binary   Data is returned exactly as is, with CRLF's.  [default]
+  conv=text     (Carriage return, line feed) is replaced with newline.
+  conv=mtext    (Carriage return, line feed) is returned as is (?).
+  conv=auto     Chooses, file by file, conv=binary or conv=text (by guessing)
+
+Mount options that are the same as vfat partitions. These are only useful
+when using discs encoded using Microsoft's Joliet extensions.
+  iocharset=name Character set to use for converting from Unicode to
+		ASCII.  Joliet filenames are stored in Unicode format, but
+		Unix for the most part doesn't know how to deal with Unicode.
+		There is also an option of doing UTF8 translations with the
+		utf8 option.
+  utf8          Encode Unicode names in UTF8 format. Default is no.
+
+Mount options that are unique to the isofs filesystem.
+  nojoliet      Ignore Joliet extensions if they are present.
+  norock        Ignore rockridge extensions if they are present.
+  unhide        Show hidden files (?).
+  cruft         Handle badly formatted CDs (?)
+  map=off       Do not map non-rockridge filenames to lowercase
+  map=normal    Map rockridge filenames to lowercase
+  check=relaxed 
+  check=strict
+  block=512     Set the block size for the disk to 512 bytes
+  block=1024    Set the block size for the disk to 1024 bytes
+  block=2048    Set the block size for the disk to 2048 bytes
diff -u --recursive --new-file v2.0.33/linux/Documentation/filesystems/vfat.txt linux/Documentation/filesystems/vfat.txt
--- v2.0.33/linux/Documentation/filesystems/vfat.txt	Thu Apr 11 23:49:29 1996
+++ linux/Documentation/filesystems/vfat.txt	Wed Jun  3 15:17:46 1998
@@ -8,6 +8,19 @@
 
 VFAT MOUNT OPTIONS
 ----------------------------------------------------------------------
+codepage=###  -- Sets the codepage for converting to shortname characters
+		 on FAT and VFAT filesystems.  By default, codepage 437
+		 is used.  This is the default for the U.S. and some
+		 European countries.
+iocharset=name-- Character set to use for converting between 8 bit characters
+		 and 16 bit Unicode characters. Long filenames are stored on
+		 disk in Unicode format, but Unix for the most part doesn't
+		 know how to deal with Unicode. There is also an option of
+		 doing UTF8 translations with the utf8 option.
+utf8	      -- UTF8 is the filesystem safe version of Unicode that
+		 is used by the console.  It can be be enabled for the
+		 filesystem with this option. If 'uni_xlate' gets set,
+		 UTF8 gets disabled.
 uni_xlate     -- Translate unhandled Unicode characters to special
 		 escaped sequences.  This would let you backup and
 		 restore filenames that are created with any Unicode
@@ -31,18 +44,59 @@
                   
 quiet         -- Stops printing certain warning messages.
 
+Explanation of Native Language Support in the VFAT Filesystem
+----------------------------------------------------------------------
+There are two different character sets are needed by the vfat
+filesystem.  The first is the codepage character set.  The codepage is
+the character set that is used to store short filenames on disk.  Its
+mount option is 'codepage=437' which 437 is the codepage number.
+
+Long filenames are stored in Unicode, but since the Linux filesystem
+doesn't deal with 16 bit characters, we need some way of converting
+characters.  There are a couple options of how to do this.  One is to
+use the 'utf8' mount option and I will cover that a bit later.  The
+other is to use the 'iocharset=iso8859-1' mount option where the
+iso8859-1 tells the filesystem which character set is used for input
+and output.  If you are in Russia, you might specify koi8-r here.
+If a Unicode character on disk cannot be mapped to anything in the
+iocharset, it is replaced with a '?'.
+
+The iocharset is used to convert long filenames to and from Unicode.
+It is currently implemented.  The codepage is used to convert short
+filenames to and from the iocharset.  This translation is not currently
+implemented.
+
+If no iocharset is specified and the default is unable to be loaded,
+the mount will succeed while falling back to doing no conversions at
+all.  If a charset is explicity specified and the charset cannot be
+loaded, the mount will fail.
+
+For the codepage, the default mount option is 'codepage=437'.  If a
+codepage is explicitly asked for and the load of the character set
+fails, the mount will fail.  Is no codepage is explicitly asked for
+and the load of the character set fails, the load will still succeed.
+
+UTF8 is an 8 bit, filesystem safe representation of Unicode.  It does
+not lose any information in the conversion.  However, you need to have
+a terminal or a program that knows how to deal with UTF8.  The Linux
+console can be put into a mode where it will correctly display UTF8
+characters.  I don't know if there is a similar mode for xterms, but
+I don't believe there is.  More information about UTF8 can be found
+at http://www.unicode.com
 
 TODO
 ----------------------------------------------------------------------
-* Need to get rid of the raw scanning stuff.  Instead, always use
-  a get next directory entry approach.  The only thing left that uses
-  raw scanning is the directory renaming code.
+* When only shortnames exist, translate them from the codepage character
+  set to the iocharset.  Currently, translations only occur when longnames
+  exist.  To translate, first convert from codepage to Unicode and then
+  to the output character set.
 
 * Need to add dcache_lookup code msdos filesystem.  This means the
   directories need to be versioned like the vfat filesystem.
 
-* Add support for different codepages.  Right now, we only support
-  the a single English codepage.
+* Need to get rid of the raw scanning stuff.  Instead, always use
+  a get next directory entry approach.  The only thing left that uses
+  raw scanning is the directory renaming code.
 
 * Fix the Posix filesystem support to work in 8.3 space.  This involves
   renaming aliases if a conflict occurs between a new filename and
@@ -55,6 +109,7 @@
 * When a volume name is the same as a directory name in the root
   directory of the filesystem, the directory name sometimes shows
   up empty an empty file.
+* autoconv option does not work correctly.
 
 BUG REPORTS
 ----------------------------------------------------------------------
@@ -194,271 +249,3 @@
 
 Finally, note that the extended name is stored in Unicode.  Each Unicode
 character takes two bytes.
-
-
-NOTES ON UNICODE TRANSLATION IN VFAT FILESYSTEM
-----------------------------------------------------------------------
-(Information provided by Steve Searle <steve@mgu.bath.ac.uk>)
-
-Char used as   Char(s) used   Char(s) used in     Entries which have
-filename       in shortname   longname slot       been corrected
-0x80 (128)     0x80           0xC7                   
-0x81 (129)     0x9A           0xFC
-0x82 (130)     0x90           0xE9                     E
-0x83 (131)     0xB6           0xE2                     E
-0x84 (132)     0x8E           0xE4                     E
-0x85 (133)     0xB7           0xE0                     E
-0x86 (134)     0x8F           0xE5                     E
-0x87 (135)     0x80           0xE7                     E
-0x88 (136)     0xD2           0xEA                     E
-0x89 (137)     0xD3           0xEB                     E
-0x8A (138)     0xD4           0xE8                     E
-0x8B (139)     0xD8           0xEF                     E
-0x8C (140)     0xD7           0xEE                     E
-0x8D (141)     0xDE           0xEC                     E
-0x8E (142)     0x8E           0xC4                     E
-0x8F (143)     0x8F           0xC5                     E
-0x90 (144)     0x90           0xC9                     E
-0x91 (145)     0x92           0xE6                     E
-0x92 (146)     0x92           0xC6                     E
-0x93 (147)     0xE2           0xF4                     E
-0x94 (148)     0x99           0xF6
-0x95 (149)     0xE3           0xF2
-0x96 (150)     0xEA           0xFB
-0x97 (151)     0xEB           0xF9
-0x98 (152)     "_~1"          0xFF
-0x99 (153)     0x99           0xD6
-0x9A (154)     0x9A           0xDC
-0x9B (155)     0x9D           0xF8
-0x9C (156)     0x9C           0xA3
-0x9D (157)     0x9D           0xD8
-0x9E (158)     0x9E           0xD7
-0x9F (159)     0x9F           0x92
-0xA0 (160)     0xB5           0xE1
-0xA1 (161)     0xD6           0xE0
-0xA2 (162)     0xE0           0xF3
-0xA3 (163)     0xE9           0xFA
-0xA4 (164)     0xA5           0xF1
-0xA5 (165)     0xA5           0xD1
-0xA6 (166)     0xA6           0xAA
-0xA7 (167)     0xA7           0xBA
-0xA8 (168)     0xA8           0xBF
-0xA9 (169)     0xA9           0xAE
-0xAA (170)     0xAA           0xAC
-0xAB (171)     0xAB           0xBD
-0xAC (172)     0xAC           0xBC
-0xAD (173)     0xAD           0xA1
-0xAE (174)     0xAE           0xAB
-0xAF (175)     0xAF           0xBB
-0xB0 (176)     0xB0           0x91 0x25
-0xB1 (177)     0xB1           0x92 0x25
-0xB2 (178)     0xB2           0x93 0x25
-0xB3 (179)     0xB3           0x02 0x25
-0xB4 (180)     0xB4           0x24 0x25
-0xB5 (181)     0xB5           0xC1
-0xB6 (182)     0xB6           0xC2
-0xB7 (183)     0xB7           0xC0
-0xB8 (184)     0xB8           0xA9
-0xB9 (185)     0xB9           0x63 0x25
-0xBA (186)     0xBA           0x51 0x25
-0xBB (187)     0xBB           0x57 0x25
-0xBC (188)     0xBC           0x5D 0x25
-0xBD (189)     0xBD           0xA2
-0xBE (190)     0xBE           0xA5
-0xBF (191)     0xBF           0x10 0x25
-0xC0 (192)     0xC0           0x14 0x25
-0xC1 (193)     0xC1           0x34 0x25
-0xC2 (194)     0xC2           0x2C 0x25
-0xC3 (195)     0xC3           0x1C 0x25
-0xC4 (196)     0xC4           0x00 0x25
-0xC5 (197)     0xC5           0x3C 0x25
-0xC6 (198)     0xC7           0xE3                     E
-0xC7 (199)     0xC7           0xC3
-0xC8 (200)     0xC8           0x5A 0x25                E
-0xC9 (201)     0xC9           0x54 0x25                E
-0xCA (202)     0xCA           0x69 0x25                E
-0xCB (203)     0xCB           0x66 0x25                E
-0xCC (204)     0xCC           0x60 0x25                E
-0xCD (205)     0xCD           0x50 0x25                E
-0xCE (206)     0xCE           0x6C 0x25                E
-0xCF (207)     0xCF           0xA4                     E
-0xD0 (208)     0xD1           0xF0
-0xD1 (209)     0xD1           0xD0
-0xD2 (210)     0xD2           0xCA
-0xD3 (211)     0xD3           0xCB
-0xD4 (212)     0xD4           0xC8
-0xD5 (213)     0x49           0x31 0x01
-0xD6 (214)     0xD6           0xCD
-0xD7 (215)     0xD7           0xCE
-0xD8 (216)     0xD8           0xCF
-0xD9 (217)     0xD9           0x18 0x25
-0xDA (218)     0xDA           0x0C 0x25
-0xDB (219)     0xDB           0x88 0x25
-0xDC (220)     0xDC           0x84 0x25
-0xDD (221)     0xDD           0xA6
-0xDE (222)     0xDE           0xCC
-0xDF (223)     0xDF           0x80 0x25
-0xE0 (224)     0xE0           0xD3
-0xE1 (225)     0xE1           0xDF
-0xE2 (226)     0xE2           0xD4
-0xE3 (227)     0xE3           0xD2
-0xE4 (228)     0x05           0xF5
-0xE5 (229)     0x05           0xD5
-0xE6 (230)     0xE6           0xB5
-0xE7 (231)     0xE8           0xFE
-0xE8 (232)     0xE8           0xDE
-0xE9 (233)     0xE9           0xDA
-0xEA (234)     0xEA           0xDB
-0xEB (235)     0xEB           0xD9
-0xEC (236)     0xED           0xFD
-0xED (237)     0xED           0xDD
-0xEE (238)     0xEE           0xAF
-0xEF (239)     0xEF           0xB4
-0xF0 (240)     0xF0           0xAD
-0xF1 (241)     0xF1           0xB1
-0xF2 (242)     0xF2           0x17 0x20
-0xF3 (243)     0xF3           0xBE
-0xF4 (244)     0xF4           0xB6
-0xF5 (245)     0xF5           0xA7
-0xF6 (246)     0xF6           0xF7
-0xF7 (247)     0xF7           0xB8
-0xF8 (248)     0xF8           0xB0
-0xF9 (249)     0xF9           0xA8
-0xFA (250)     0xFA           0xB7
-0xFB (251)     0xFB           0xB9
-0xFC (252)     0xFC           0xB3
-0xFD (253)     0xFD           0xB2
-0xFE (254)     0xFE           0xA0 0x25
-0xFF (255)     0xFF           0xA0
-
-
-Page 0
-0x80 (128)     0x00
-0x81 (129)     0x00
-0x82 (130)     0x00
-0x83 (131)     0x00
-0x84 (132)     0x00
-0x85 (133)     0x00
-0x86 (134)     0x00
-0x87 (135)     0x00
-0x88 (136)     0x00
-0x89 (137)     0x00
-0x8A (138)     0x00
-0x8B (139)     0x00
-0x8C (140)     0x00
-0x8D (141)     0x00
-0x8E (142)     0x00
-0x8F (143)     0x00
-0x90 (144)     0x00
-0x91 (145)     0x00
-0x92 (146)     0x00
-0x93 (147)     0x00
-0x94 (148)     0x00
-0x95 (149)     0x00
-0x96 (150)     0x00
-0x97 (151)     0x00
-0x98 (152)     0x00
-0x99 (153)     0x00
-0x9A (154)     0x00
-0x9B (155)     0x00
-0x9C (156)     0x00
-0x9D (157)     0x00
-0x9E (158)     0x00
-0x9F (159)     0x92
-0xA0 (160)     0xFF
-0xA1 (161)     0xAD
-0xA2 (162)     0xBD
-0xA3 (163)     0x9C
-0xA4 (164)     0xCF
-0xA5 (165)     0xBE
-0xA6 (166)     0xDD
-0xA7 (167)     0xF5
-0xA8 (168)     0xF9
-0xA9 (169)     0xB8
-0xAA (170)     0x00
-0xAB (171)     0xAE
-0xAC (172)     0xAA
-0xAD (173)     0xF0
-0xAE (174)     0x00
-0xAF (175)     0xEE
-0xB0 (176)     0xF8
-0xB1 (177)     0xF1
-0xB2 (178)     0xFD
-0xB3 (179)     0xFC
-0xB4 (180)     0xEF
-0xB5 (181)     0xE6
-0xB6 (182)     0xF4
-0xB7 (183)     0xFA
-0xB8 (184)     0xF7
-0xB9 (185)     0xFB
-0xBA (186)     0x00
-0xBB (187)     0xAF
-0xBC (188)     0xAC
-0xBD (189)     0xAB
-0xBE (190)     0xF3
-0xBF (191)     0x00
-0xC0 (192)     0xB7
-0xC1 (193)     0xB5
-0xC2 (194)     0xB6
-0xC3 (195)     0xC7
-0xC4 (196)     0x8E
-0xC5 (197)     0x8F
-0xC6 (198)     0x92
-0xC7 (199)     0x80
-0xC8 (200)     0xD4
-0xC9 (201)     0x90
-0xCA (202)     0xD2
-0xCB (203)     0xD3
-0xCC (204)     0xDE
-0xCD (205)     0xD6
-0xCE (206)     0xD7
-0xCF (207)     0xD8
-0xD0 (208)     0x00
-0xD1 (209)     0xA5
-0xD2 (210)     0xE3
-0xD3 (211)     0xE0
-0xD4 (212)     0xE2
-0xD5 (213)     0xE5
-0xD6 (214)     0x99
-0xD7 (215)     0x9E
-0xD8 (216)     0x9D
-0xD9 (217)     0xEB
-0xDA (218)     0xE9
-0xDB (219)     0xEA
-0xDC (220)     0x9A
-0xDD (221)     0xED
-0xDE (222)     0xE8
-0xDF (223)     0xE1
-0xE0 (224)     0x85, 0xA1
-0xE1 (225)     0xA0
-0xE2 (226)     0x83
-0xE3 (227)     0xC6
-0xE4 (228)     0x84
-0xE5 (229)     0x86
-0xE6 (230)     0x91
-0xE7 (231)     0x87
-0xE8 (232)     0x8A
-0xE9 (233)     0x82
-0xEA (234)     0x88
-0xEB (235)     0x89
-0xEC (236)     0x8D
-0xED (237)     0x00
-0xEE (238)     0x8C
-0xEF (239)     0x8B
-0xF0 (240)     0xD0
-0xF1 (241)     0xA4
-0xF2 (242)     0x95
-0xF3 (243)     0xA2
-0xF4 (244)     0x93
-0xF5 (245)     0xE4
-0xF6 (246)     0x94
-0xF7 (247)     0xF6
-0xF8 (248)     0x9B
-0xF9 (249)     0x97
-0xFA (250)     0xA3
-0xFB (251)     0x96
-0xFC (252)     0x81
-0xFD (253)     0xEC
-0xFE (254)     0xE7
-0xFF (255)     0x98
-
diff -u --recursive --new-file v2.0.33/linux/Documentation/networking/depca.txt linux/Documentation/networking/depca.txt
--- v2.0.33/linux/Documentation/networking/depca.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/depca.txt	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,92 @@
+
+DE10x
+=====
+
+Memory Addresses:
+
+	SW1	SW2	SW3	SW4
+64K	on	on	on	on	d0000	dbfff
+	off	on	on	on	c0000	cbfff
+	off	off	on	on	e0000	ebfff
+
+32K	on	on	off	on	d8000	dbfff
+	off	on	off	on	c8000	cbfff
+	off	off	off	on	e8000	ebfff
+
+DBR ROM	on	on			dc000	dffff
+	off	on			cc000	cffff
+	off	off			ec000	effff
+
+Note  that the 2K  mode   is set  by   SW3/SW4  on/off or  off/off.  Address
+assignment is through the RBSA register.
+
+I/O Address:
+	SW5
+0x300	on
+0x200	off
+
+Remote Boot:
+	SW6
+Disable	on
+Enable	off
+
+Remote Boot Timeout:
+	SW7
+2.5min	on
+30s	off
+
+IRQ:
+	SW8	SW9	SW10	SW11	SW12
+2	on	off	off	off	off
+3	off	on	off	off	off
+4	off	off	on	off	off
+5	off	off	off	on	off
+7	off	off	off	off	on
+
+DE20x
+=====
+
+Memory Size:
+
+	SW3	SW4
+64K	on	on
+32K	off	on
+2K	on 	off
+2K	off	off
+
+Start Addresses:
+
+	SW1	SW2	SW3	SW4
+64K	on	on	on	on	c0000	cffff
+	on	off	on	on	d0000	dffff
+	off	on	on	on	e0000	effff
+
+32K	on	on	off	off	c8000	cffff
+	on	off	off	off	d8000	dffff
+	off	on	off	off	e8000	effff
+
+Illegal	off	off	 -	 -	  -	  -
+
+I/O Address:
+	SW5
+0x300	on
+0x200	off
+
+Remote Boot:
+	SW6
+Disable	on
+Enable	off
+
+Remote Boot Timeout:
+	SW7
+2.5min	on
+30s	off
+
+IRQ:
+	SW8	SW9	SW10	SW11	SW12
+5	on	off	off	off	off
+9	off	on	off	off	off
+10	off	off	on	off	off
+11	off	off	off	on	off
+15	off	off	off	off	on
+
diff -u --recursive --new-file v2.0.33/linux/Documentation/networking/ip_dynaddr.txt linux/Documentation/networking/ip_dynaddr.txt
--- v2.0.33/linux/Documentation/networking/ip_dynaddr.txt	Wed Sep 17 12:00:48 1997
+++ linux/Documentation/networking/ip_dynaddr.txt	Wed Jun  3 15:17:46 1998
@@ -1,10 +1,10 @@
-IP dynamic address hack-port v0.03
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+IP dynamic address hack-port v0.03-rst
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 This stuff allows diald ONESHOT connections to get established by
 dynamically changing packet source address (and socket's if local procs).
 It is implemented for TCP diald-box connections(1) and IP_MASQuerading(2).
 
-If enabled[*] and forwarding interface has changed:
+If enabled[*] and forwarding interface address has changed:
   1)  Socket (and packet) source address is rewritten ON RETRANSMISSIONS
       while in SYN_SENT state (diald-box processes).
   2)  Out-bounded MASQueraded source address changes ON OUTPUT (when
@@ -16,14 +16,39 @@
 going up. So, the *same* (local AND masqueraded) connections requests that
 bring the link up will be able to get established.
 
+If you enable the RST-provoking mode, then the source address will
+be changed, even if the socket is established. This means we send
+an incorrect packet out, which causes the remote host to kill our
+socket. This is the desired behaviour, because such a socket is
+doomed anyway, and the earlier it dies, the better.  This prevents
+the dial-on-demand connection from being kept up by a dead connection,
+and tells the application that the connection was lost.
+
 [*] At boot, by default no address rewriting is attempted. 
-  To enable:
+
+The values for the ip_dynaddr sysctl are:
+
+  1:  To enable:
+  2:  To enable verbosity:
+  4:  To enable RST-provoking:
+
+Flags can be combined by adding them. Common settings
+would be:
+
+  To switch off special handling of dynamic addresses (default)
+     # echo 0 > /proc/sys/net/ipv4/ip_dynaddr
+  To enable rewriting in quiet mode:
      # echo 1 > /proc/sys/net/ipv4/ip_dynaddr
-  To enable verbose mode:
+  To enable rewriting in verbose mode:
+     # echo 3 > /proc/sys/net/ipv4/ip_dynaddr
+  (for backwards compatibility you can also use)
      # echo 2 > /proc/sys/net/ipv4/ip_dynaddr
-  To disable (default)
-     # echo 0 > /proc/sys/net/ipv4/ip_dynaddr
+  To enable quiet RST-provoking mode:
+     # echo 5 > /proc/sys/net/ipv4/ip_dynaddr
+  To enable verbose RST-provoking mode:
+     # echo 7 > /proc/sys/net/ipv4/ip_dynaddr
 
 Enjoy!
 
 -- Juanjo  <jjciarla@raiz.uncu.edu.ar>
+(with RST-provoking mode by Erik Corry <erik@arbat.com>)
diff -u --recursive --new-file v2.0.33/linux/Documentation/networking/tlan.FAQ linux/Documentation/networking/tlan.FAQ
--- v2.0.33/linux/Documentation/networking/tlan.FAQ	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/tlan.FAQ	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,28 @@
+1.	Q. Ifconfig reports "10Mbs Ethernet" for my 10/100Mbs card.  How do
+	   I get my card to run in 100Mbs mode?
+
+	A. The "10Mbs Ethernet" is poorly named.  What this is really saying
+	   is that this device is some kind of Ethernet device (ie, uses
+	   ethernet style frames at the link layer).  Recent versions of
+	   ifconfig report this as simply "Ethernet".
+
+	   The TLAN driver is designed to autodetect 10Mbs vs. 100Mbs
+	   connections, and choose the higher speed.  The most sure way
+	   to determine what speed you are running at is to look at the
+	   100Mbs LED on the card, if your device has one.
+
+
+2.	Q. My network card is using the same interrupt as my SCSI card.
+
+	A. Some Compaqs set all PCI devices to the same interrupt by default.
+	   You can either change the interrupt used by one of the device
+	   with your Compaq configuration utility, or you can have the TLAN
+	   driver use the same type of interrupt handler:
+
+	   a. For module based use, add 'sa_int=1' to the command line, eg.:
+		insmod tlan.o sa_int=1
+
+	   b. For compiled in kernel, set the 0x2 bit in the third part
+	      for the boot parameter for that device, eg.:
+		ether=0,0,0x2,0,eth0
+
diff -u --recursive --new-file v2.0.33/linux/Documentation/networking/tlan.README linux/Documentation/networking/tlan.README
--- v2.0.33/linux/Documentation/networking/tlan.README	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/tlan.README	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,130 @@
+Caldera TLAN driver for Linux, version 0.42
+README
+
+
+I.  Supported Devices.
+
+    Only PCI devices will work with this driver.
+
+    Supported:
+    Vendor ID	Device ID	Name
+    0e11	ae32		Compaq Netelligent 10/100 TX
+    0e11	ae34		Compaq Netelligent 10 T
+    0e11	ae35		Compaq Integrated NetFlex 3/P
+    0e11	ae43		Compaq ProLiant Integrated Netelligent 10/100 TX
+    0e11	ae40		Compaq Dual Port Netelligent 10/100 TX
+    0e11	b011		Compaq Deskpro 4000 5233MMX
+    0e11	f130		Compaq NetFlex 3/P
+    0e11	f150		Compaq NetFlex 3/P
+    108d	0014		Olicom OC-2326	
+
+    Caveats:
+    
+    I don't believe 100BaseTX daughterboards will work.  I am interested
+    in any reports.
+    
+
+II.  Building the Driver.
+
+    The TLAN driver may be compiled into the kernel, or it may be compiled
+    as a module separately, or in the kernel.  A patch is included for
+    2.0.29 (which also works for 2.0.30, 2.0.31, and 2.0.32).
+
+    To compile it as part of the kernel:
+        1. Download and untar the TLAN driver package.
+	2. If your kernel is 2.1.45 or later, you do not need to patch the
+           kernel sources.  Copy the tlan.c and tlan.h to drivers/net in
+           the kernel source tree.
+        3. Otherwise, apply the appropriate patch for your kernel.  For
+	   example:
+
+	       cd /usr/src/linux
+               patch -p1 < kernel.2.0.29
+
+        4. Copy the files tlan.c and tlan.h from the TLAN package to the
+           directory drivers/net in the Linux kernel source tree.
+        5. Configure your kernel for the TLAN driver.  Answer 'Y' when
+           prompted to ask about experimental code (the first question).
+           Then answer 'Y' when prompted if to include TI ThunderLAN
+           support.  If you want the driver compiled as a module, answer 'M'
+           instead of 'Y'.
+        6. Make the kernel and, if necessary, the modules.
+    
+    To compile the TLAN driver independently:
+        1. Download and untar the TLAN driver package.
+        2. Change to the tlan directory.
+        3. If you are NOT using a versioned kernel (ie, want an non-
+           versioned module), edit the Makefile, and comment out the
+           line:
+                 MODVERSIONS = -DMODVERSIONS
+        4. Run 'make'.
+
+
+III.  Driver Options
+	1. You can append debug=x to the end of the insmod line to get
+           debug messages, where x is a bit field where the bits mean
+	   the following:
+	   
+	   0x01		Turn on general debugging messages.
+	   0x02		Turn on receive debugging messages.
+	   0x04		Turn on transmit debugging messages.
+	   0x08		Turn on list debugging messsages.
+
+	2. You can append aui=1 to the end of the insmod line to cause
+           the adapter to use the AUI interface instead of the 10 Base T
+           interface.  This is also what to do if you want to use the BNC
+	   connector on a TLAN based device.  (Setting this option on a
+	   device that does not have an AUI/BNC connector will probably
+	   cause it to not function correctly.)
+
+	3. If the driver is built into the kernel, you can use the 3rd
+	   and 4th parameters to set aui and debug respectively.  For
+	   example:
+
+	   ether=0,0,0x1,0x7,eth0
+
+	   This sets aui to 0x1 and debug to 0x7, assuming eth0 is a
+	   supported TLAN device.
+
+	   The bits in the third byte are assigned as follows:
+
+		0x01 = aui
+		0x02 = use SA_INTERRUPT flag when reserving the irq.
+
+
+IV.  Things to try if you have problems.
+	1. Make sure your card's PCI id is among those listed in
+	   section I, above.
+	1. Make sure routing is correct.
+	2. If you are using a 2.1.x kernel, try to duplicate the
+	   problem on a 2.0.x (preferably 2.0.29 or 2.0.30) kernel.
+	3. Set debug to 7, either in tlan.c or through insmod as in
+	   section III.1 above.
+	4. Make sure klog is running so the kernel messages are
+	   being recorded somewhere.
+	5. Run the following sequence of programs in order (you
+	   may want to do this within an xterm, as background
+	   traffic may cause a lot of TLAN RECEIVED: messages
+	   on the console):
+
+	   ifconfig eth0 your.ip.address netmask your.net.mask up
+	   route add -net local.net.address eth0
+	   ifconfig
+	   ping some.computer.on.local.net
+	   ifconfig eth0 down
+
+	6. Mail the log of what occurred to me.  Also include the
+	   kernel version and what media/connector type (eg,
+	   10 BaseT/RJ45, 100 BaseTX/RJ45, Thinnet/BNC, etc).
+
+
+
+Please e-mail me with any comments, successes, or failures.  Thanks.
+
+There is also a tlan mailing list which you can join by sending "subscribe tlan"
+in the body of an email to majordomo@vuser.vu.union.edu.  I will announce new
+releases of the TLAN driver there.
+
+James
+james.banks@caldera.com
+
diff -u --recursive --new-file v2.0.33/linux/Documentation/riscom8.txt linux/Documentation/riscom8.txt
--- v2.0.33/linux/Documentation/riscom8.txt	Fri Apr 26 02:12:36 1996
+++ linux/Documentation/riscom8.txt	Wed Jun  3 15:17:46 1998
@@ -1,5 +1,5 @@
 	This is the README for RISCom/8 multi-port serial driver
-	(C) 1994-1996 D.Gorodchanin (begemot@bgm.rosrpint.net)
+	(C) 1994-1996 D.Gorodchanin (pgmdsg@ibi.com)
 	See file LICENSE for terms and conditions.
 
 NOTE: English is not my native language. 
diff -u --recursive --new-file v2.0.33/linux/Documentation/rtc.txt linux/Documentation/rtc.txt
--- v2.0.33/linux/Documentation/rtc.txt	Mon May  6 22:18:50 1996
+++ linux/Documentation/rtc.txt	Wed Jun  3 15:17:46 1998
@@ -65,6 +65,35 @@
 
 						Paul Gortmaker
 
+Update in version 1.09
+======================
+
+Epoch handling is added.  Epoch is the number which should be added to the
+value of the clock's year register to get the actual year.  The default
+Linux epoch is therefore 1900.
+
+Epochs are especially useful on Alphas where different operating systems
+use different epochs, and Linux wants to be compatible with all of them.
+They may eventually be helpful on Intel architecture as well, where a
+value of an RTC register cannot exceed 99 due to BCD tradition originated
+from DOS.
+
+When the epoch is set to 1900, the new code behaves exactly like the old
+one with respect to the BCD wrapping: values 00 - 69 are treated as if
+they were 100 - 169.  That means that after the 2000th year epoch 1900
+will be the same as epoch 2000.
+
+Two new ioctls are introduced to read and set the epoch, RTC_EPOCH_READ
+and RTC_EPOCH_SET.  They can be used in exactly the same manner as
+RTC_IRQP_READ and RTC_IRQP_SET, so they are not included in the example
+program below.
+
+On Alphas an epoch autodetection is performed.  Currently 3 epochs
+are recognised: Linux (1900), Digital UNIX (1952) and Windows NT (1980).
+
+Nikita Schmidt	<cetus@snowball.ucd.ie>
+
+
 -------------------- 8< ---------------- 8< -----------------------------
 
 /*
diff -u --recursive --new-file v2.0.33/linux/MAINTAINERS linux/MAINTAINERS
--- v2.0.33/linux/MAINTAINERS	Fri Sep  5 20:43:58 1997
+++ linux/MAINTAINERS	Wed Jun  3 15:17:46 1998
@@ -82,7 +82,7 @@
 
 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
 P:	Paul Gortmaker
-M	gpg109@rsphy1.anu.edu.au
+M:	gpg109@rsphy1.anu.edu.au
 L:	linux-net@vger.rutgers.edu
 S:	Maintained
 
@@ -98,6 +98,12 @@
 L:	linux-net@vger.rutgers.edu
 S:	Maintained
 
+TLAN NETWORK DRIVER
+P:	James Banks
+M:	james.banks@caldera.com
+L:	linux-net@vger.rutgers.edu
+S:	Supported
+
 DIGI RIGHTSWITCH NETWORK DRIVER
 P:	Rick Richardson
 M:	rick@dgii.com
@@ -342,7 +348,7 @@
 
 RISCOM8 DRIVER:
 P:	Dmitry Gorodchanin
-M:	begemot@bgm.rosprint.net
+M:	pgmdsg@ibi.com
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
@@ -416,6 +422,12 @@
 P:	H. Peter Anvin
 M:	hpa@zytor.com
 L:	linux-kernel@vger.rutgers.edu
+S:	Maintained
+
+WD7000 SCSI DRIVER
+P:	Miroslav Zagorac
+M:	zaga@fly.cc.fer.hr
+L:	linux-scsi@vger.rutgers.edu
 S:	Maintained
 
 REST:
diff -u --recursive --new-file v2.0.33/linux/Makefile linux/Makefile
--- v2.0.33/linux/Makefile	Tue Mar 10 13:19:08 1998
+++ linux/Makefile	Wed Jun  3 15:17:46 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 33
+SUBLEVEL = 34
 
 ARCH = i386
 
@@ -201,6 +201,9 @@
 
 $(TOPDIR)/include/linux/version.h: include/linux/version.h
 $(TOPDIR)/include/linux/compile.h: include/linux/compile.h
+
+ksymoops: 
+	$(MAKE) -C scripts ksymoops
 
 newversion:
 	@if [ ! -f .version ]; then \
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/Makefile linux/arch/alpha/Makefile
--- v2.0.33/linux/arch/alpha/Makefile	Mon Aug  5 00:13:50 1996
+++ linux/arch/alpha/Makefile	Wed Jun  3 15:17:46 1998
@@ -26,6 +26,21 @@
 
 CFLAGS := $(CFLAGS) -mno-fp-regs
 
+# determine if we can use the BWX instructions with GAS
+$(shell rm -f /tmp/GAS_VER)
+#$(shell $(AS) --version >& /tmp/GAS_VER)
+$(shell $(AS) --version > /tmp/GAS_VER 2>&1)
+OLD_GAS := $(shell if cat /tmp/GAS_VER | grep 'version 2.7' > /dev/null; then echo yes; else echo no; fi)
+
+ifneq ($(OLD_GAS),yes)
+ CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWX_USABLE
+
+# if PYXIS, then enable use of BWIO space
+ ifeq ($(CONFIG_ALPHA_PYXIS),y)
+  CFLAGS := $(CFLAGS) -DBWIO_ENABLED
+ endif
+endif
+
 HEAD := arch/alpha/kernel/head.o
 
 SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib \
@@ -57,3 +72,6 @@
 
 archdep:
 	@$(MAKEBOOT) dep
+
+bootpfile:
+	@$(MAKEBOOT) bootpfile
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile
--- v2.0.33/linux/arch/alpha/boot/Makefile	Mon Aug  5 00:13:50 1996
+++ linux/arch/alpha/boot/Makefile	Wed Jun  3 15:17:46 1998
@@ -26,6 +26,7 @@
 	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
 OBJECTS = head.o main.o
+BPOBJECTS = head.o bootp.o
 TARGETS = vmlinux.gz tools/objstrip # also needed by aboot & milo
 VMLINUX = $(TOPDIR)/vmlinux
 OBJSTRIP = tools/objstrip
@@ -44,6 +45,9 @@
 	( cat tools/lxboot tools/bootlx vmlinux.nh ) > bootimage
 	tools/mkbb bootimage tools/lxboot
 
+bootpfile:	tools/bootph vmlinux.nh
+	( cat tools/bootph vmlinux.nh ) > bootpfile
+
 srmboot:	bootdevice bootimage
 	dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1
 	tools/mkbb $(BOOTDEV) tools/lxboot
@@ -59,6 +63,8 @@
 #
 main.o: ksize.h
 
+bootp.o: ksize.h
+
 ksize.h: $(OBJSTRIP) vmlinux.nh
 	echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@
 
@@ -82,6 +88,9 @@
 tools/bootlx: bootloader $(OBJSTRIP)
 	$(OBJSTRIP) -vb bootloader tools/bootlx
 
+tools/bootph: bootpheader $(OBJSTRIP)
+	$(OBJSTRIP) -vb bootpheader tools/bootph
+
 $(OBJSTRIP): $(OBJSTRIP).c
 	$(HOSTCC) $(OBJSTRIP).c -o $(OBJSTRIP)
 
@@ -95,8 +104,15 @@
 		-o bootloader && strip bootloader || \
 		(rm -f bootloader && exit 1)
 
+bootpheader: $(BPOBJECTS)
+	$(LD) $(LINKFLAGS) \
+		$(BPOBJECTS) \
+		$(LIBS) \
+		-o bootpheader && strip bootpheader || \
+		(rm -f bootpheader && exit 1)
+
 clean:
 	rm -f $(TARGETS) bootloader bootimage vmlinux.nh \
-		tools/mkbb tools/bootlx tools/lxboot
+		tools/mkbb tools/bootlx tools/lxboot ksize.h
 
 dep:
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c
--- v2.0.33/linux/arch/alpha/boot/bootp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/boot/bootp.c	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,239 @@
+/*
+ * arch/alpha/boot/bootp.c
+ *
+ * Copyright (C) 1997 Jay Estabrook
+ *
+ * This file is used for creating a bootp file for the Linux/AXP kernel
+ *
+ * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+
+#include <asm/system.h>
+#include <asm/console.h>
+#include <asm/hwrpb.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <stdarg.h>
+
+#include "ksize.h"
+
+extern int vsprintf(char *, const char *, va_list);
+extern unsigned long switch_to_osf_pal(unsigned long nr,
+	struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
+	unsigned long vptb, unsigned long *kstk);
+
+int printk(const char * fmt, ...)
+{
+	va_list args;
+	int i, j, written, remaining, num_nl;
+	static char buf[1024];
+	char * str;
+
+	va_start(args, fmt);
+	i = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	/* expand \n into \r\n: */
+
+	num_nl = 0;
+	for (j = 0; j < i; ++j) {
+	    if (buf[j] == '\n')
+	    	++num_nl;
+	}
+	remaining = i + num_nl;
+	for (j = i - 1; j >= 0; --j) {
+	    buf[j + num_nl] = buf[j];
+	    if (buf[j] == '\n') {
+	    	--num_nl;
+		buf[j + num_nl] = '\r';
+	    }
+	}
+
+	str = buf;
+	do {
+	    written = puts(str, remaining);
+	    remaining -= written;
+	    str += written;
+	} while (remaining > 0);
+	return i;
+}
+
+#define hwrpb (*INIT_HWRPB)
+
+/*
+ * Find a physical address of a virtual object..
+ *
+ * This is easy using the virtual page table address.
+ */
+struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb)
+{
+	unsigned long address = (unsigned long) pcb;
+	unsigned long result;
+
+	result = vptb[address >> 13];
+	result >>= 32;
+	result <<= 13;
+	result |= address & 0x1fff;
+	return (struct pcb_struct *) result;
+}	
+
+/*
+ * This function moves into OSF/1 pal-code, and has a temporary
+ * PCB for that. The kernel proper should replace this PCB with
+ * the real one as soon as possible.
+ *
+ * The page table muckery in here depends on the fact that the boot
+ * code has the L1 page table identity-map itself in the second PTE
+ * in the L1 page table. Thus the L1-page is virtually addressable
+ * itself (through three levels) at virtual address 0x200802000.
+ *
+ * As we don't want it there anyway, we also move the L1 self-map
+ * up as high as we can, so that the last entry in the L1 page table
+ * maps the page tables.
+ *
+ * As a result, the OSF/1 pal-code will instead use a virtual page table
+ * map located at 0xffffffe00000000.
+ */
+#define pcb_va ((struct pcb_struct *) 0x20000000)
+#define old_vptb (0x0000000200000000UL)
+#define new_vptb (0xfffffffe00000000UL)
+void pal_init(void)
+{
+	unsigned long i, rev, sum;
+	unsigned long *L1, *l;
+	struct percpu_struct * percpu;
+	struct pcb_struct * pcb_pa;
+
+	/* Find the level 1 page table and duplicate it in high memory */
+	L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */
+	L1[1023] = L1[1];
+
+	percpu = (struct percpu_struct *)
+			(hwrpb.processor_offset + (unsigned long) &hwrpb),
+		
+	pcb_va->ksp = 0;
+	pcb_va->usp = 0;
+	pcb_va->ptbr = L1[1] >> 32;
+	pcb_va->asn = 0;
+	pcb_va->pcc = 0;
+	pcb_va->unique = 0;
+	pcb_va->flags = 1;
+	pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va);
+	printk("Switching to OSF PAL-code .. ");
+	/*
+	 * a0 = 2 (OSF)
+	 * a1 = return address, but we give the asm the vaddr of the PCB
+	 * a2 = physical addr of PCB
+	 * a3 = new virtual page table pointer
+	 * a4 = KSP (but we give it 0, asm sets it)
+	 */
+	i = switch_to_osf_pal(
+		2,
+		pcb_va,
+		pcb_pa,
+		new_vptb,
+		0);
+	if (i) {
+		printk("failed, code %ld\n", i);
+		halt();
+	}
+	rev = percpu->pal_revision = percpu->palcode_avail[2];
+
+	hwrpb.vptb = new_vptb;
+
+	/* update checksum: */
+	sum = 0;
+	for (l = (unsigned long *) &hwrpb;
+	     l < (unsigned long *) &hwrpb.chksum;
+	     ++l)
+		sum += *l;
+	hwrpb.chksum = sum;
+
+	printk("Ok (rev %lx)\n", rev);
+	/* remove the old virtual page-table mapping */
+	L1[1] = 0;
+	flush_tlb_all();
+}
+
+static inline long load(unsigned long dst,
+			unsigned long src,
+			unsigned long count)
+{
+	extern void * memcpy(void *, const void *, size_t);
+
+	memcpy((void *)dst, (void *)src, count);
+	return count;
+}
+
+/*
+ * Start the kernel.
+ */
+static void runkernel(void)
+{
+	__asm__ __volatile__(
+		"bis %1,%1,$30\n\t"
+		"bis %0,%0,$26\n\t"
+		"ret ($26)"
+		: /* no outputs: it doesn't even return */
+		: "r" (START_ADDR),
+		  "r" (PAGE_SIZE + INIT_STACK));
+}
+
+extern char _end;
+#define KERNEL_ORIGIN \
+	((((unsigned long)&_end) + 511) & ~511)
+
+void start_kernel(void)
+{
+	static long i;
+	static int nbytes;
+	static char envval[256];
+	char envbuf[256];
+
+	printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
+
+	if (hwrpb.pagesize != 8192) {
+		printk("Expected 8kB pages, got %ldkB\n",
+		       hwrpb.pagesize >> 10);
+		return;
+	}
+	pal_init();
+
+	nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
+			  envbuf, sizeof(envbuf));
+	if (nbytes < 0 || nbytes >= sizeof(envbuf)) {
+		nbytes = 0;
+	}
+
+	envbuf[nbytes] = '\0';
+	memcpy(envval, envbuf, nbytes+1);
+	printk("Loading the kernel...'%s'\n", envval);
+
+	/* NOTE: *no* callbacks or printouts from here on out!!! */
+
+	/*
+	 * HACK alert:
+	 *
+	 * assume direct copy will fail due to overlap of virtual source
+	 * and physical destination, so move it way high physical first,
+	 * then move it back to its final resting place...
+	 *
+	 * this way could fail, too, but it works on the platforms *I* have
+	 */
+	i = load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
+        i = load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
+
+	strcpy((char*)ZERO_PAGE, envval);
+
+	runkernel();
+
+	for (i = 0 ; i < 0x100000000 ; i++)
+		/* nothing */;
+	halt();
+}
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.0.33/linux/arch/alpha/config.in	Mon Aug  5 00:13:50 1996
+++ linux/arch/alpha/config.in	Wed Jun  3 15:17:46 1998
@@ -6,8 +6,12 @@
 
 # clear all implied options (don't want default values for those):
 unset CONFIG_CROSSCOMPILE CONFIG_NATIVE
-unset CONFIG_PCI CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS
+unset CONFIG_PCI CONFIG_ALPHA_EISA
+unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA CONFIG_ALPHA_T2
+unset CONFIG_ALPHA_PYXIS
+unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5
 unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
+unset CONFIG_ALPHA_SRM CONFIG_ALPHA_SRM_SETUP
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
@@ -43,49 +47,123 @@
 	 EB64+		CONFIG_ALPHA_EB64P		\
 	 EB164		CONFIG_ALPHA_EB164		\
 	 PC164		CONFIG_ALPHA_PC164		\
+	 LX164		CONFIG_ALPHA_LX164		\
+	 SX164		CONFIG_ALPHA_SX164		\
 	 Jensen		CONFIG_ALPHA_JENSEN		\
 	 Noname		CONFIG_ALPHA_NONAME		\
+	 Takara		CONFIG_ALPHA_TAKARA		\
 	 Mikasa		CONFIG_ALPHA_MIKASA		\
+	 Noritake	CONFIG_ALPHA_NORITAKE		\
 	 Alcor		CONFIG_ALPHA_ALCOR		\
+	 Miata		CONFIG_ALPHA_MIATA		\
+	 Sable		CONFIG_ALPHA_SABLE		\
+	 AlphaBook1	CONFIG_ALPHA_BOOK1		\
+	 Ruffian	CONFIG_ALPHA_RUFFIAN		\
 	 Platform2000	CONFIG_ALPHA_P2K" Cabriolet
+
+if [ "$CONFIG_ALPHA_BOOK1" = "y" ]
+then
+	define_bool CONFIG_ALPHA_NONAME y
+fi
 if [ "$CONFIG_ALPHA_NONAME" = "y" -o "$CONFIG_ALPHA_EB66" = "y" \
 	-o "$CONFIG_ALPHA_EB66P" = "y" -o "$CONFIG_ALPHA_P2K" = "y" ]
 then
 	define_bool CONFIG_PCI y
+	define_bool CONFIG_ALPHA_EV4 y
 	define_bool CONFIG_ALPHA_LCA y
 fi
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
-	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
-	-o "$CONFIG_ALPHA_XL" = "y" ]
+	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_XL" = "y" ]
 then
 	define_bool CONFIG_PCI y
+	define_bool CONFIG_ALPHA_EV4 y
 	define_bool CONFIG_ALPHA_APECS y
 fi
 if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
-	-o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" ]
+	-o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" \
+	-o "$CONFIG_ALPHA_TAKARA" = "y" ]
 then
 	define_bool CONFIG_PCI y
 	define_bool CONFIG_ALPHA_EV5 y
 	define_bool CONFIG_ALPHA_CIA y
+fi
+if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ]
+then
+	bool 'Pinnacle or Primo CPU daughtercard?' CONFIG_ALPHA_PRIMO
+	if [ "$CONFIG_ALPHA_PRIMO" = "y" ]
+	then
+		define_bool CONFIG_ALPHA_EV5 y
+		define_bool CONFIG_ALPHA_CIA y
+else
+		define_bool CONFIG_ALPHA_EV4 y
+		define_bool CONFIG_ALPHA_APECS y
+	fi
+	define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_ALPHA_SABLE" = "y" ]
+then
+	bool 'EV5 or EV56 CPU daughtercard?' CONFIG_ALPHA_GAMMA
+	if [ "$CONFIG_ALPHA_GAMMA" = "y" ]
+	then
+		define_bool CONFIG_ALPHA_EV5 y
 else
+		define_bool CONFIG_ALPHA_EV4 y
+	fi
+	define_bool CONFIG_PCI y
+	define_bool CONFIG_ALPHA_T2 y
+fi
+if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \
+	 -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ]
+then
+	define_bool CONFIG_PCI y
+	define_bool CONFIG_ALPHA_EV5 y
+	define_bool CONFIG_ALPHA_PYXIS y
+fi
+if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
+then
+	define_bool CONFIG_ALPHA_EV4 y
+fi
+if [ "$CONFIG_ALPHA_EV4" = "y" ]
+then
 	# EV45 and older do not support all rounding modes in hw:
 	define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
 fi
 
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
 	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
-	-o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" ]
+	-o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \
+	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \
+	-o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
+	-o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ]
 then
-	bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
+  bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    if [ "$CONFIG_ALPHA_SRM" = "y" ]; then
+      bool '  Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP
+    fi
+  fi
+fi
+if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
+	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ]
+then
+	define_bool CONFIG_ALPHA_EISA y
 fi
 if [ "$CONFIG_ALPHA_XL" = "y" ]
 then
 	define_bool CONFIG_ALPHA_AVANTI y
 fi
 
+bool 'Kernel GDB support' CONFIG_KGDB
+if [ "$CONFIG_KGDB" = "y" ]; then
+  bool 'Kernel tracing support?' CONFIG_KGDB_TRACING
+fi
+
 bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'TGA Console Support' CONFIG_TGA_CONSOLE
+  if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then
+    bool 'VGA Console Support' CONFIG_VGA_CONSOLE
+  fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
   fi
@@ -94,6 +172,7 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
 endmenu
 
 source drivers/block/Config.in
@@ -163,3 +242,7 @@
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
 endmenu
+
+if [ "$CONFIG_TGA_CONSOLE" = "n" ]; then
+  define_bool CONFIG_VGA_CONSOLE y
+fi
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.0.33/linux/arch/alpha/defconfig	Fri Sep  5 20:43:58 1997
+++ linux/arch/alpha/defconfig	Wed Jun  3 15:17:46 1998
@@ -36,12 +36,16 @@
 CONFIG_ALPHA_EV5=y
 CONFIG_ALPHA_CIA=y
 CONFIG_ALPHA_SRM=y
+CONFIG_KGDB=y
+CONFIG_KGDB_TRACING=n
 # CONFIG_SERIAL_ECHO is not set
 CONFIG_TGA_CONSOLE=y
+CONFIG_VGA_CONSOLE=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_EM86=y
 
 #
 # Floppy, IDE, and other block devices
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.0.33/linux/arch/alpha/kernel/Makefile	Mon Jun  3 20:06:37 1996
+++ linux/arch/alpha/kernel/Makefile	Wed Jun  3 15:17:46 1998
@@ -16,7 +16,12 @@
 
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
-	    bios32.o ptrace.o time.o apecs.o lca.o cia.o ksyms.o
+	    bios32.o ptrace.o time.o apecs.o lca.o cia.o t2.o pyxis.o \
+	    ksyms.o smc.o
+
+ifdef CONFIG_KGDB
+O_OBJS += kgdb.o
+endif
 
 all: kernel.o head.o
 
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/apecs.c linux/arch/alpha/kernel/apecs.c
--- v2.0.33/linux/arch/alpha/kernel/apecs.c	Mon Jul  8 22:08:18 1996
+++ linux/arch/alpha/kernel/apecs.c	Wed Jun  3 15:17:46 1998
@@ -20,7 +20,7 @@
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern int alpha_sys_type;
+
 /*
  * BIOS32-style PCI interface:
  */
@@ -33,13 +33,16 @@
 # define DBG(args)
 #endif
 
-#define vulp	volatile unsigned long *
 #define vuip	volatile unsigned int  *
 
 static volatile unsigned int apecs_mcheck_expected = 0;
 static volatile unsigned int apecs_mcheck_taken = 0;
-static unsigned long apecs_jd, apecs_jd1, apecs_jd2;
+static unsigned int apecs_jd, apecs_jd1, apecs_jd2;
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int APECS_DMA_WIN_BASE = APECS_DMA_WIN_BASE_DEFAULT;
+unsigned int APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -142,15 +145,15 @@
 	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
 	/* reset status register to avoid losing errors: */
-	stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
-	*((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
+	stat0 = *((vuip)APECS_IOC_DCSR);
+	*((vuip)APECS_IOC_DCSR) = stat0;
 	mb();
 	DBG(("conf_read: APECS DCSR was 0x%x\n", stat0));
 	/* if Type1 access, must set HAE #2 */
 	if (type1) {
-		haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
+		haxr2 = *((vuip)APECS_IOC_HAXR2);
 		mb();
-		*((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
+		*((vuip)APECS_IOC_HAXR2) = haxr2 | 1;
 		DBG(("conf_read: TYPE1 access\n"));
 	}
 
@@ -159,7 +162,7 @@
 	apecs_mcheck_taken = 0;
 	mb();
 	/* access configuration space: */
-	value = *((volatile unsigned int *)addr);
+	value = *((vuip)addr);
 	mb();
 	mb();
 	if (apecs_mcheck_taken) {
@@ -179,7 +182,7 @@
 	draina();
 
 	/* now look for any errors */
-	stat0 = *((unsigned int *)APECS_IOC_DCSR);
+	stat0 = *((vuip)APECS_IOC_DCSR);
 	DBG(("conf_read: APECS DCSR after read 0x%x\n", stat0));
 	if (stat0 & 0xffe0U) { /* is any error bit set? */
 		/* if not NDEV, print status */
@@ -188,7 +191,7 @@
 		}
 
 		/* reset error status: */
-		*((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
+		*((vuip)APECS_IOC_DCSR) = stat0;
 		mb();
 		wrmces(0x7);			/* reset machine check */
 		value = 0xffffffff;
@@ -197,7 +200,7 @@
 
 	/* if Type1 access, must reset HAE #2 so normal IO space ops work */
 	if (type1) {
-		*((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
+		*((vuip)APECS_IOC_HAXR2) = haxr2 & ~1;
 		mb();
 	}
 	restore_flags(flags);
@@ -224,22 +227,22 @@
 	cli();
 
 	/* reset status register to avoid losing errors: */
-	stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
-	*((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
+	stat0 = *((vuip)APECS_IOC_DCSR);
+	*((vuip)APECS_IOC_DCSR) = stat0;
 	mb();
 
 	/* if Type1 access, must set HAE #2 */
 	if (type1) {
-		haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
+		haxr2 = *((vuip)APECS_IOC_HAXR2);
 		mb();
-		*((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
+		*((vuip)APECS_IOC_HAXR2) = haxr2 | 1;
 	}
 
 	draina();
 	apecs_mcheck_expected = 1;
 	mb();
 	/* access configuration space: */
-	*((volatile unsigned int *)addr) = value;
+	*((vuip)addr) = value;
 	mb();
 	mb();
 	apecs_mcheck_expected = 0;
@@ -254,7 +257,7 @@
 	draina();
 
 	/* now look for any errors */
-	stat0 = *((unsigned int *)APECS_IOC_DCSR);
+	stat0 = *((vuip)APECS_IOC_DCSR);
 	if (stat0 & 0xffe0U) { /* is any error bit set? */
 		/* if not NDEV, print status */
 		if (!(stat0 & 0x0800)) {
@@ -262,7 +265,7 @@
 		}
 
 		/* reset error status: */
-		*((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
+		*((vuip)APECS_IOC_DCSR) = stat0;
 		mb();
 		wrmces(0x7);			/* reset machine check */
 	}
@@ -270,7 +273,7 @@
 
 	/* if Type1 access, must reset HAE #2 so normal IO space ops work */
 	if (type1) {
-		*((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
+		*((vuip)APECS_IOC_HAXR2) = haxr2 & ~1;
 		mb();
 	}
 	restore_flags(flags);
@@ -417,6 +420,38 @@
 	*(vuip)APECS_IOC_TB2R = 0;
 
 #else  /* CONFIG_ALPHA_XL */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	/* check window 1 for enabled and mapped to 0 */
+	if ((*(vuip)APECS_IOC_PB1R & (1U<<19)) && (*(vuip)APECS_IOC_TB1R == 0))
+	{
+	  APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB1R & 0xfff00000U;
+	  APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM1R & 0xfff00000U;
+	  APECS_DMA_WIN_SIZE += 0x00100000U;
+#if 0
+	  printk("apecs_init: using Window 1 settings\n");
+	  printk("apecs_init: PB1R 0x%x PM1R 0x%x TB1R 0x%x\n",
+     		 *(vuip)APECS_IOC_PB1R,
+		 *(vuip)APECS_IOC_PM1R,
+		 *(vuip)APECS_IOC_TB1R);
+#endif
+     	}
+	else	/* check window 2 for enabled and mapped to 0 */
+	if ((*(vuip)APECS_IOC_PB2R & (1U<<19)) && (*(vuip)APECS_IOC_TB2R == 0))
+	{
+	  APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB2R & 0xfff00000U;
+	  APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM2R & 0xfff00000U;
+	  APECS_DMA_WIN_SIZE += 0x00100000U;
+#if 0
+     	  printk("apecs_init: using Window 2 settings\n");
+	  printk("apecs_init: PB2R 0x%x PM2R 0x%x TB2R 0x%x\n",
+		 *(vuip)APECS_IOC_PB2R,
+		 *(vuip)APECS_IOC_PM2R,
+		 *(vuip)APECS_IOC_TB2R);
+#endif
+     	}
+	else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+	{
 	/*
 	 * Set up the PCI->physical memory translation windows.
 	 * For now, window 2 is disabled.  In the future, we may
@@ -428,9 +463,11 @@
 	*(vuip)APECS_IOC_PB1R  = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U);
 	*(vuip)APECS_IOC_PM1R  = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U;
 	*(vuip)APECS_IOC_TB1R  = 0;
+	}
 #endif /* CONFIG_ALPHA_XL */
 
 #ifdef CONFIG_ALPHA_CABRIOLET
+#if 0
 	/*
 	 * JAE: HACK!!! for now, hardwire if configured...
 	 * davidm: Older miniloader versions don't set the clockfrequency
@@ -448,10 +485,13 @@
 	    unsigned long *l, sum;
 
 	    sum = 0;
-	    for (l = (unsigned long *) hwrpb; l < (unsigned long *) &hwrpb->chksum; ++l)
+	    for (l = (unsigned long *) hwrpb;
+		 l < (unsigned long *) &hwrpb->chksum;
+		 ++l)
 	      sum += *l;
 	    hwrpb->chksum = sum;
 	}
+#endif
 #endif /* CONFIG_ALPHA_CABRIOLET */
 
        /*
@@ -462,10 +502,10 @@
         */
        {
 #if 0
-         unsigned int haxr2 = *((unsigned int *)APECS_IOC_HAXR2); mb();
+         unsigned int haxr2 = *((vuip)APECS_IOC_HAXR2); mb();
          if (haxr2) printk("apecs_init: HAXR2 was 0x%x\n", haxr2);
 #endif
-         *((unsigned int *)APECS_IOC_HAXR2) = 0; mb();
+         *((vuip)APECS_IOC_HAXR2) = 0; mb();
        }
 
 
@@ -474,15 +514,15 @@
 
 int apecs_pci_clr_err(void)
 {
-	apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
+	apecs_jd = *((vuip)APECS_IOC_DCSR);
 	if (apecs_jd & 0xffe0L) {
-		apecs_jd1 = *((unsigned long *)APECS_IOC_SEAR);
-		*((unsigned long *)APECS_IOC_DCSR) = apecs_jd | 0xffe1L;
-		apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
+		apecs_jd1 = *((vuip)APECS_IOC_SEAR);
+		*((vuip)APECS_IOC_DCSR) = apecs_jd | 0xffe1L;
+		apecs_jd = *((vuip)APECS_IOC_DCSR);
 		mb();
 	}
-	*((unsigned long *)APECS_IOC_TBIA) = APECS_IOC_TBIA;
-	apecs_jd2 = *((unsigned long *)APECS_IOC_TBIA);
+	*((vuip)APECS_IOC_TBIA) = APECS_IOC_TBIA;
+	apecs_jd2 = *((vuip)APECS_IOC_TBIA);
 	mb();
 	return 0;
 }
@@ -526,8 +566,8 @@
 #define MCHK_NO_DEVSEL 0x205L
 #define MCHK_NO_TABT 0x204L
 	if (apecs_mcheck_expected &&
-	    (((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_DEVSEL) ||
-	     ((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_TABT))
+	    (((unsigned int)mchk_header->code == MCHK_NO_DEVSEL) ||
+	     ((unsigned int)mchk_header->code == MCHK_NO_TABT))
 	    )
 	{
 #else
@@ -550,19 +590,21 @@
 		printk("apecs_machine_check: HW correctable (0x%lx)\n", vector);
 	}
 	else {
-		printk("APECS machine check:\n");
-		printk("  vector=0x%lx la_ptr=0x%lx\n",
+		printk(KERN_CRIT "APECS machine check:\n");
+		printk(KERN_CRIT "  vector=0x%lx la_ptr=0x%lx\n",
 		       vector, la_ptr);
-		printk("  pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+		printk(KERN_CRIT
+		       "  pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
 		       regs->pc, mchk_header->size, mchk_header->proc_offset,
 		       mchk_header->sys_offset);
-		printk("  expected %d DCSR 0x%lx PEAR 0x%lx\n",
+		printk(KERN_CRIT "  expected %d DCSR 0x%lx PEAR 0x%lx\n",
 		       apecs_mcheck_expected, mchk_sysdata->epic_dcsr,
 		       mchk_sysdata->epic_pear);
 
 		ptr = (unsigned long *)la_ptr;
 		for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
-		    printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+		    printk(KERN_CRIT " +%lx %lx %lx\n",
+			   i*sizeof(long), ptr[i], ptr[i+1]);
 		}
 #if 0
 		/* doesn't work with MILO */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.0.33/linux/arch/alpha/kernel/bios32.c	Sun Feb  2 04:59:20 1997
+++ linux/arch/alpha/kernel/bios32.c	Wed Jun  3 15:17:46 1998
@@ -57,7 +57,7 @@
 #include <asm/hwrpb.h>
 #include <asm/io.h>
 #include <asm/segment.h>
-
+#include <asm/dma.h>
 
 #define KB		1024
 #define MB		(1024*KB)
@@ -73,6 +73,8 @@
 
 
 /*
+ * PCI_MODIFY
+ *
  * Temporary internal macro.  If this 0, then do not write to any of
  * the PCI registers, merely read them (i.e., use configuration as
  * determined by SRM).  The SRM seem do be doing a less than perfect
@@ -89,34 +91,72 @@
  * the graphics card---there have been some rumor that the #9 BIOS
  * incorrectly resets that address to 0...).
  */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+#define PCI_MODIFY		0
+static struct pci_dev *irq_dev_to_reset[16];
+static unsigned char irq_to_reset[16];
+static int irq_reset_count = 0;
+static struct pci_dev *io_dev_to_reset[16];
+static unsigned char io_reg_to_reset[16];
+static unsigned int io_to_reset[16];
+static int io_reset_count = 0;
+#else /* SRM_SETUP */
 #define PCI_MODIFY		1
+#endif /* SRM_SETUP */
 
 extern struct hwrpb_struct *hwrpb;
 
-
 #if PCI_MODIFY
 
 /* NOTE: we can't just blindly use 64K for machines with EISA busses; they
    may also have PCI-PCI bridges present, and then we'd configure the bridge
    incorrectly */
-#if 0
-static unsigned int	io_base	 = 64*KB;	/* <64KB are (E)ISA ports */
+/* NOTE also that we may need this stuff for SRM_SETUP also, since certain
+   SRM consoles screw up and allocate I/O space addresses > 64K behind
+   PCI-to_PCI bridges, which can't pass addresses larger than 64K... */
+#if defined(CONFIG_ALPHA_EISA)
+static unsigned int	io_base	 = 0x9000;	/* start above 8th slot */
 #else
-static unsigned int	io_base	 = 0xb000;
+static unsigned int	io_base	 = 0x8000;
 #endif
 
 #if defined(CONFIG_ALPHA_XL)
 /*
-   an AVANTI *might* be an XL, and an XL has only 27 bits of ISA address
-   that get passed through the PCI<->ISA bridge chip. Because this causes
-   us to set the PCI->Mem window bases lower than normal, we've gotta allocate
-   PCI bus devices' memory addresses *above* the PCI<->memory mapping windows,
-   so that CPU memory DMA addresses issued by a bus device don't conflict
-   with bus memory addresses, like frame buffer memory for graphics cards.
+   An XL is AVANTI (APECS) family, *but* it has only 27 bits of ISA address
+   that get passed through the PCI<->ISA bridge chip. Although this causes
+   us to set the PCI->Mem window bases lower than normal, we still allocate
+   PCI bus devices' memory addresses *below* the low DMA mapping window,
+   and hope they fit below 64Mb (to avoid conflicts), and so that they can
+   be accessed via SPARSE space.
+
+   We accept the risk that a broken Myrinet card will be put into a true XL
+   and thus can more easily run into the problem described below.
+*/
+static unsigned int	mem_base = 16*MB + 2*MB; /* 16M to 64M-1 is avail */
+
+#elif defined(CONFIG_ALPHA_LCA) || defined(CONFIG_ALPHA_APECS)
+/*
+   We try to make this address *always* have more than 1 bit set.
+   this is so that devices like the broken Myrinet card will always have
+   a PCI memory address that will never match a IDSEL address in
+   PCI Config space, which can cause problems with early rev cards.
+
+   However, APECS and LCA have only 34 bits for physical addresses, thus
+   limiting PCI bus memory addresses for SPARSE access to be less than 128Mb.
+*/
+static unsigned int	mem_base = 64*MB + 2*MB;
+
+#else
+/*
+   We try to make this address *always* have more than 1 bit set.
+   this is so that devices like the broken Myrinet card will always have
+   a PCI memory address that will never match a IDSEL address in
+   PCI Config space, which can cause problems with early rev cards.
+
+   Because CIA and PYXIS and T2 have more bits for physical addresses,
+   they support an expanded range of SPARSE memory addresses.
 */
-static unsigned int	mem_base = 1024*MB;
-#else /* CONFIG_ALPHA_XL */
-static unsigned int	mem_base = 16*MB;	/* <16MB is ISA memory */
+static unsigned int	mem_base = 128*MB + 16*MB;
 #endif /* CONFIG_ALPHA_XL */
 
 /*
@@ -128,7 +168,7 @@
 	struct pci_bus *bus;
 	unsigned short cmd;
 
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+#if defined(CONFIG_ALPHA_EISA)
 	/*
 	 * HACK: the PCI-to-EISA bridge does not seem to identify
 	 *       itself as a bridge... :-(
@@ -139,6 +179,18 @@
         }
 #endif
 
+	/*
+	 * we don't have code that will init the CYPRESS bridge correctly
+	 * so we do the next best thing, and depend on the previous
+	 * console code to do the right thing, and ignore it here... :-\
+	 */
+	if ((dev->vendor == 0x1080) && (dev->device == 0xC693)) {
+#if 0
+	  printk("disable_dev: ignoring CYPRESS bridge...\n");
+#endif
+	  return;
+	}
+
 	bus = dev->bus;
 	pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
 
@@ -160,7 +212,7 @@
 	unsigned int base, mask, size, reg;
 	unsigned int alignto;
 
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+#if defined(CONFIG_ALPHA_EISA)
 	/*
 	 * HACK: the PCI-to-EISA bridge does not seem to identify
 	 *       itself as a bridge... :-(
@@ -171,10 +223,36 @@
         }
 #endif
 
+	/*
+	 * we don't have code that will init the CYPRESS bridge correctly
+	 * so we do the next best thing, and depend on the previous
+	 * console code to do the right thing, and ignore it here... :-\
+	 */
+	if ((dev->vendor == 0x1080) && (dev->device == 0xC693)) {
+#if 0
+	  printk("layout_dev: ignoring CYPRESS bridge...\n");
+#endif
+	  return;
+	}
+
 	bus = dev->bus;
 	pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
 
 	for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+
+#ifdef NOT_NOW
+	  if ((dev->vendor == 0x1080) && (dev->device == 0xC693) &&
+	      ((PCI_FUNC(dev->devfn) == 1) || (PCI_FUNC(dev->devfn) == 2)))
+	  { /* if primary or secondary IDE on the CYPRESS bridge */
+	      if ((reg == PCI_BASE_ADDRESS_0) || (reg == PCI_BASE_ADDRESS_1)) {
+#if 0
+		  printk("layout_dev: ignoring CYPRESS IDE base reg 0/1\n");
+#endif
+		  continue; /* ignore first two registers */
+	      }
+	  }
+#endif /* NOT_NOW */
+
 		/*
 		 * Figure out how much space and of what type this
 		 * device wants.
@@ -182,6 +260,10 @@
 		pcibios_write_config_dword(bus->number, dev->devfn, reg,
 					   0xffffffff);
 		pcibios_read_config_dword(bus->number, dev->devfn, reg, &base);
+#if 0
+printk("layout_dev: slot %d fn %d off 0x%x base 0x%x\n",
+       PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), reg, base);
+#endif
 		if (!base) {
 			/* this base-address register is unused */
 			continue;
@@ -201,11 +283,23 @@
 			mask = (~base << 1) | 0x1;
 			size = (mask & base) & 0xffffffff;
 			/* align to multiple of size of minimum base */
+#if 0
 			alignto = MAX(0x400, size) ;
+#else
+			/*
+			   If we align to 0x800 bounds, we probably avoid
+			   having devices in any 0xzCzz range, which is
+			   where the DE4X5 driver probes for EISA cards.
+			   Adaptecs, especially, resent such intrusions. :-(
+			*/
+			alignto = MAX(0x800, size) ;
+#endif
 			base = ALIGN(io_base, alignto );
 			io_base = base + size;
 			pcibios_write_config_dword(bus->number, dev->devfn, 
 						   reg, base | 0x1);
+			DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%x (0x%x)\n",
+				  dev->device, base, size));
 		} else {
 			unsigned int type;
 			/*
@@ -266,7 +360,7 @@
 			base = ALIGN(mem_base, alignto);
 			if (size > 7 * 16*MB) {
 				printk("bios32 WARNING: slot %d, function %d "
-				       "requests  %dB of contiguous address "
+				       "requests 0x%x bytes of contig address "
 				       " space---don't use sparse memory "
 				       " accesses on this device!!\n",
 				       PCI_SLOT(dev->devfn),
@@ -277,7 +371,8 @@
 					base += 16*MB;
 					base  = ALIGN(base, alignto);
 				}
-				if (base / (128*MB) != (base + size) / (128*MB)) {
+				if (base / (128*MB) != (base + size) / (128*MB))
+				{
 					base &= ~(128*MB - 1);
 					base += (128 + 16)*MB;
 					base  = ALIGN(base, alignto);
@@ -286,13 +381,15 @@
 			mem_base = base + size;
 			pcibios_write_config_dword(bus->number, dev->devfn,
 						   reg, base);
+			DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%x (0x%x)\n",
+				  dev->device, base, size));
 		}
-        }
+	} /* end for-loop */
 	/* enable device: */
 	if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
 	    dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
-	    dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
-	    dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+	    dev->class >>  8 == PCI_CLASS_STORAGE_IDE ||
+	    dev->class >> 16 == PCI_BASE_CLASS_DISPLAY)
 	{
 		/*
 		 * All of these (may) have I/O scattered all around
@@ -305,21 +402,24 @@
 
 	pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND,
 				  cmd | PCI_COMMAND_MASTER);
-	DBG_DEVS(("layout_dev: bus %d  slot 0x%x  VID 0x%x  DID 0x%x  class 0x%x\n",
-		  bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
+
+	DBG_DEVS(("layout_dev: bus %d slot %d VID 0x%x DID 0x%x class 0x%x cmd 0x%x\n",
+		  bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device,
+		  dev->class, cmd|PCI_COMMAND_MASTER));
 }
 
 
-static void layout_bus(struct pci_bus *bus)
+static int layout_bus(struct pci_bus *bus)
 {
 	unsigned int l, tio, bio, tmem, bmem;
 	struct pci_bus *child;
 	struct pci_dev *dev;
+	int found_vga = 0;
 
 	DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
 
 	if (!bus->devices && !bus->children)
-	  return;
+	  return 0;
 
 	/*
 	 * Align the current bases on appropriate boundaries (4K for
@@ -338,7 +438,11 @@
 	 * decoders are programmed consistently.
 	 */
 	for (dev = bus->devices; dev; dev = dev->sibling) {
-		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+		if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+#ifdef CONFIG_ALPHA_BOOK1
+                    || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
+		    ) {
 		        disable_dev(dev) ;
 		}
 	}
@@ -349,9 +453,15 @@
 	DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
 
 	for (dev = bus->devices; dev; dev = dev->sibling) {
-		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+		if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+#ifdef CONFIG_ALPHA_BOOK1
+		    || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
+		    ) {
 			layout_dev(dev);
 		}
+		if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+			found_vga = 1;
 	}
 	/*
 	 * Recursively allocate space for all of the sub-buses:
@@ -359,7 +469,7 @@
 	DBG_DEVS(("layout_bus: starting bus %d children\n", bus->number));
 
     	for (child = bus->children; child; child = child->next) {
-		layout_bus(child);
+		found_vga += layout_bus(child);
         }
 	/*
 	 * Align the current bases on 4K and 1MB boundaries:
@@ -375,7 +485,8 @@
 		 */
 		pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
 					  0x1c, &l);
-		l = (l & 0xffff0000) | ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000);
+		l = (l & 0xffff0000) | ((bio >> 8) & 0x00f0) | 
+		    ((tio - 1) & 0xf000);
 		pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
 					   0x1c, l);
 		/*
@@ -391,10 +502,13 @@
 		pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
 					   0x24, 0x0000ffff);
 		/*
-		 * Tell bridge that there is an ISA bus in the system:
+		 * Tell bridge that there is an ISA bus in the system,
+		 * and (possibly) a VGA as well.
 		 */
+		l = 0x00040000; /* ISA present */
+		if (found_vga) l |= 0x00080000; /* VGA present */
 		pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
-					   0x3c, 0x00040000);
+					   0x3c, l);
 		/*
 		 * Clear status bits, enable I/O (for downstream I/O),
 		 * turn on master enable (for upstream I/O), turn on
@@ -404,6 +518,7 @@
 		pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
 					   0x4, 0xffff0007);
 	}
+	return found_vga;
 }
 
 #endif /* !PCI_MODIFY */
@@ -501,9 +616,9 @@
 }
 
 /* 
- * A small note about bridges and interrupts.    The DECchip 21050 (and later chips)
- * adheres to the PCI-PCI bridge specification.   This says that the interrupts on
- * the other side of a bridge are swizzled in the following manner:
+ * A small note about bridges and interrupts. The DC 21050 (and later chips)
+ * adheres to the PCI-PCI bridge specification. This says that the interrupts
+ * on the other side of a bridge are swizzled in the following manner:
  *
  * Dev    Interrupt   Interrupt 
  *        Pin on      Pin on 
@@ -541,13 +656,86 @@
         return (((pin-1) + slot) % 4) + 1 ;
 }
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* look for mis-configured devices' IO space addresses behind bridges */
+static void check_behind_io(struct pci_dev *dev)
+{
+	struct pci_bus *bus = dev->bus;
+	unsigned int reg, orig_base, new_base, found_one = 0;
+
+	for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+		/* read the current setting, check for I/O space and >= 64K */
+		pcibios_read_config_dword(bus->number, dev->devfn, reg, &orig_base);
+		if (!orig_base || !(orig_base & PCI_BASE_ADDRESS_SPACE_IO))
+			continue; /* unused or non-IO */
+		if (orig_base < 64*1024) {
+#if 1
+printk("check_behind_io: ALREADY OK! bus %d slot %d base 0x%x\n",
+       bus->number, PCI_SLOT(dev->devfn), orig_base);
+#endif
+			if (orig_base & ~1)
+			  continue; /* OK! */
+			orig_base = 0x12001; /* HACK! FIXME!! */
+		}
+
+		/* HACK ALERT! for now, just subtract 32K from the
+		   original address, which should give us addresses
+		   in the range 0x8000 and up */
+		new_base = orig_base - 0x8000;
+#if 1
+printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n",
+       bus->number, PCI_SLOT(dev->devfn), orig_base, new_base);
+#endif
+		pcibios_write_config_dword(bus->number, dev->devfn,
+					   reg, new_base);
+
+		io_dev_to_reset[io_reset_count] = dev;
+		io_reg_to_reset[io_reset_count] = reg;
+		io_to_reset[io_reset_count] = orig_base;
+		io_reset_count++;
+		found_one++;
+	} /* end for-loop */
+
+	/* if any were modified, gotta hack the bridge IO limits too... */
+	if (found_one) {
+	    if (bus->self) {
+		struct pci_dev *bridge = bus->self;
+		unsigned int l;
+		/*
+		 * Set up the top and bottom of the PCI I/O segment
+		 * for this bus.
+		 */
+		pcibios_read_config_dword(bridge->bus->number,
+					  bridge->devfn, 0x1c, &l);
+#if 1
+printk("check_behind_io: ALERT! bus %d slot %d oldLIM 0x%x\n",
+       bus->number, PCI_SLOT(bridge->devfn), l);
+#endif
+		l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */
+		pcibios_write_config_dword(bridge->bus->number,
+					   bridge->devfn, 0x1c, l);
+		pcibios_write_config_dword(bridge->bus->number,
+					   bridge->devfn,
+					   0x3c, 0x00040000);
+		pcibios_write_config_dword(bridge->bus->number,
+					   bridge->devfn,
+					   0x4, 0xffff0007);
+	    } else
+	        printk("check_behind_io: WARNING! bus->self NULL\n");
+	}
+}
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+
 /*
  * Most evaluation boards share most of the fixup code, which is isolated here.
  * This function is declared "inline" as only one platform will ever be selected
  * in any given kernel.  If that platform doesn't need this code, we don't want
  * it around as dead code.
  */
-static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
+static inline void common_fixup(
+	long min_idsel,
+	long max_idsel,
+	long irqs_per_slot,
 				char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot],
 				long ide_base)
 {
@@ -559,37 +747,122 @@
 	 * Go through all devices, fixing up irqs as we see fit:
 	 */
 	for (dev = pci_devices; dev; dev = dev->next) {
-	        if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+		if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+#if defined(CONFIG_ALPHA_EISA)
 		    /* PCEB (PCI to EISA bridge) does not identify
 		       itself as a bridge... :-( */
 		    && !((dev->vendor==0x8086) && (dev->device==0x482))
 #endif
+#ifdef CONFIG_ALPHA_BOOK1
+                    || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
 		    ) {
 		        dev->irq = 0;
 			/*
-			 * This device is not on the primary bus, we need to figure out which
-			 * interrupt pin it will come in on.   We know which slot it will come
-			 * in on 'cos that slot is where the bridge is.   Each time the interrupt
-			 * line passes through a PCI-PCI bridge we must apply the swizzle function
+			 * This device is not on the primary bus,
+			 * we need to figure out which
+			 * interrupt pin it will come in on.
+			 * We know which slot it will come
+			 * in on 'cuz that slot is where the bridge is.
+			 * Each time the interrupt
+			 * line passes through a PCI-PCI bridge
+			 * we must apply the swizzle function
 			 * (see the inline static routine above).
 			 */
 			if (dev->bus->number != 0) {
-			        struct pci_dev *curr = dev ;
-				/* read the pin and do the PCI-PCI bridge interrupt pin swizzle */
-				pcibios_read_config_byte(dev->bus->number, dev->devfn,
-							 PCI_INTERRUPT_PIN, &pin);
+				/* read the pin and do the PCI-PCI bridge
+				   interrupt pin swizzle */
+				pcibios_read_config_byte(dev->bus->number,
+							 dev->devfn,
+							 PCI_INTERRUPT_PIN,
+							 &pin);
 				/* cope with 0 */
 				if (pin == 0) pin = 1 ;
-				/* follow the chain of bridges, swizzling as we go */
+				/* follow the chain of bridges,
+				   swizzling as we go */
+#if defined(CONFIG_ALPHA_MIATA)
+				/* check first for the built-in bridge */
+				if ((PCI_SLOT(dev->bus->self->devfn) == 8) ||
+				    (PCI_SLOT(dev->bus->self->devfn) == 20)) {
+				  slot = PCI_SLOT(dev->devfn) + 9;
+#if 0
+				  printk("MIATA: bus 1 slot %d pin %d irq %d "
+					 "min_idsel %d\n",
+					 PCI_SLOT(dev->devfn), pin,
+					 irq_tab[slot - min_idsel][pin],
+					 min_idsel);
+#endif
+				}
+				else /* must be a card-based bridge */
+				{
+				  struct pci_dev *curr = dev ;
 				do {
+				  if ((PCI_SLOT(curr->bus->self->devfn) == 8) ||
+				      (PCI_SLOT(curr->bus->self->devfn) == 20))
+				    {
+				      slot = PCI_SLOT(curr->devfn) + 5;
+				      break;
+				    }
 				        /* swizzle */
-				        pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)) ;
+				    pin = bridge_swizzle(
+						  pin, PCI_SLOT(curr->devfn)) ;
+				    /* move up the chain of bridges */
+				    curr = curr->bus->self ;
+				    /* slot of the next bridge. */
+				    slot = PCI_SLOT(curr->devfn);
+				  } while (curr->bus->self) ;
+				}
+#elif defined(CONFIG_ALPHA_NORITAKE)
+				/* check first for the built-in bridge */
+				if (PCI_SLOT(dev->bus->self->devfn) == 8) {
+				  slot = PCI_SLOT(dev->devfn) + 15; /* WAG! */
+#if 0
+				  printk("NORITAKE: bus 1 slot %d pin %d "
+					 "irq %d min_idsel %d\n",
+					 PCI_SLOT(dev->devfn), pin,
+					 irq_tab[slot - min_idsel][pin],
+					 min_idsel);
+#endif
+				}
+				else /* must be a card-based bridge */
+				{
+				  struct pci_dev *curr = dev ;
+				  do {
+				    if (PCI_SLOT(curr->bus->self->devfn) == 8) {
+				      slot = PCI_SLOT(curr->devfn) + 15;
+				      break;
+				    }
+				    /* swizzle */
+				    pin = bridge_swizzle(
+						pin, PCI_SLOT(curr->devfn)) ;
+				    /* move up the chain of bridges */
+				    curr = curr->bus->self ;
+				    /* slot of the next bridge. */
+				    slot = PCI_SLOT(curr->devfn);
+				  } while (curr->bus->self) ;
+				}
+#else /* not MIATA or NORITAKE */
+				{
+				  struct pci_dev *curr = dev ;
+				  do {
+					/* swizzle */
+					pin = bridge_swizzle(
+						  pin, PCI_SLOT(curr->devfn)) ;
 					/* move up the chain of bridges */
 					curr = curr->bus->self ;
 				} while (curr->bus->self) ;
 				/* The slot is the slot of the last bridge. */
 				slot = PCI_SLOT(curr->devfn) ;
+				}
+#endif /* not MIATA or NORITAKE */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+				/*
+				  must make sure that SRM didn't screw up
+				  and allocate an address > 64K for I/O
+				  space behind a PCI-PCI bridge
+				*/
+				check_behind_io(dev);
+#endif /* CONFIG_ALPHA_SRM_SETUP */
 			} else {
 			        /* work out the slot */
 		                slot = PCI_SLOT(dev->devfn) ;
@@ -601,28 +874,193 @@
 			}
 			if (irq_tab[slot - min_idsel][pin] != -1)
 			        dev->irq = irq_tab[slot - min_idsel][pin];
-#if PCI_MODIFY
-			/* tell the device: */
+
+#ifdef CONFIG_ALPHA_SRM
+			{
+			  unsigned char irq_orig;
+			  /* read the original SRM-set IRQ and tell */
+			  pcibios_read_config_byte(dev->bus->number,
+						    dev->devfn,
+						    PCI_INTERRUPT_LINE,
+						    &irq_orig);
+			  if (irq_orig != dev->irq) {
+			    printk("common_fixup: bus %d slot 0x%x "
+				   "SRM IRQ 0x%x changed to 0x%x\n",
+				   dev->bus->number,PCI_SLOT(dev->devfn),
+				   irq_orig, dev->irq);
+#ifdef CONFIG_ALPHA_SRM_SETUP
+			    irq_dev_to_reset[irq_reset_count] = dev;
+			    irq_to_reset[irq_reset_count] = irq_orig;
+			    irq_reset_count++;
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+			  }
+			}
+#endif /* SRM */
+
+			/* always tell the device, so the driver knows */
 			pcibios_write_config_byte(dev->bus->number, dev->devfn,
 						  PCI_INTERRUPT_LINE, dev->irq);
-#endif
+
+	DBG_DEVS(("common_fixup: bus %d  slot 0x%x  VID 0x%x  DID 0x%x\n"
+		  "              int_slot 0x%x  pin 0x%x  irq 0x%x\n",
+		  dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor,
+		  dev->device, slot, pin, dev->irq));
+
 			/*
 			 * if it's a VGA, enable its BIOS ROM at C0000
 			 */
 			if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
-			  pcibios_write_config_dword(dev->bus->number,
+			  /* but if its a Cirrus 543x/544x DISABLE it, */
+			  /* since enabling ROM disables the memory... */
+			  if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) &&
+			      (dev->device >= 0x00a0) &&
+			      (dev->device <= 0x00ac)) {
+				  pcibios_write_config_dword(
+					dev->bus->number,
+					dev->devfn,
+					PCI_ROM_ADDRESS,
+					0x00000000);
+			  } else {
+				  pcibios_write_config_dword(
+					dev->bus->number,
 						     dev->devfn,
 						     PCI_ROM_ADDRESS,
 						     0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
 			}
 		}
+			/*
+			 * if it's a SCSI, disable its BIOS ROM
+			 */
+			if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) {
+			  pcibios_write_config_dword(dev->bus->number,
+						     dev->devfn,
+						     PCI_ROM_ADDRESS,
+						     0x0000000);
+			}
+#ifdef NOT_NOW
+			if ((dev->vendor == 0x1080) && (dev->device == 0xC693)
+			 && (PCI_FUNC(dev->devfn) == 1))
+			{
+#if 0
+{
+int i; unsigned char b; unsigned short w; unsigned int d;
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w);
+ printk("common_fixup: CYPRESS fn 1: PCI CMD reg = 0x%x\n", w);
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 6, &w);
+ printk("common_fixup: CYPRESS fn 1: PCI STS reg = 0x%x\n", w);
+ for (i = 0x10; i <= 0x14; i+=4) {
+   pcibios_read_config_dword(dev->bus->number, dev->devfn, i, &d);
+   printk("common_fixup: CYPRESS fn 1: PCI register offset 0x%x = 0x%x\n",i,d);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x20, &d);
+ printk("common_fixup: CYPRESS fn 1: PCI register offset 0x20 = 0x%x\n", d);
+ for (i = 0x3c; i <= 0x3d; i++) {
+   pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &b);
+   printk("common_fixup: CYPRESS fn 1: PCI register offset 0x%x = 0x%x\n",i,b);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x40, &d);
+ printk("common_fixup: CYPRESS fn 1: PCI register offset 0x40 = 0x%x\n",d);
+}
+#endif
+			}
+			if ((dev->vendor == 0x1080) && (dev->device == 0xC693)
+			 && (PCI_FUNC(dev->devfn) == 2))
+			{
+#if 0
+{
+int i; unsigned char b; unsigned short w; unsigned int d;
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w);
+ printk("common_fixup: CYPRESS fn 2: PCI CMD reg = 0x%x\n", w);
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 6, &w);
+ printk("common_fixup: CYPRESS fn 2: PCI STS reg = 0x%x\n", w);
+ for (i = 0x10; i <= 0x14; i+=4) {
+   pcibios_read_config_dword(dev->bus->number, dev->devfn, i, &d);
+   printk("common_fixup: CYPRESS fn 2: PCI register offset 0x%x = 0x%x\n",i,d);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x20, &d);
+ printk("common_fixup: CYPRESS fn 2: PCI register offset 0x20 = 0x%x\n", d);
+ for (i = 0x3c; i <= 0x3d; i++) {
+   pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &b);
+   printk("common_fixup: CYPRESS fn 2: PCI register offset 0x%x = 0x%x\n",i,b);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x40, &d);
+ printk("common_fixup: CYPRESS fn 2: PCI register offset 0x40 = 0x%x\n",d);
+}
+#endif
+			}
+#endif /* NOT_NOW */
+		} else { /* it *is* a bridge... */
+#ifdef NOT_NOW
+			/*
+			 * if it's CYPRESS PCI-ISA bridge, disable IDE
+			 *  interrupt routing through PCI (ie do through PIC)
+			 */
+			if ((dev->vendor == 0x1080) && (dev->device == 0xC693)
+			 && (PCI_FUNC(dev->devfn) == 0))
+			{
+#if 0
+{
+int i; unsigned char d; unsigned short w;
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w);
+ printk("common_fixup: CYPRESS fn 0: PCI CMD reg = 0x%x\n", w);
+ for (i = 0x40; i < 0x50; i++) {
+   pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &d);
+   printk("common_fixup: CYPRESS fn 0: PCI register offset 0x%x = 0x%x\n",
+	  i, d);
+ }
+ for (i=1; i <= 5; i++) {
+   outb(i, 0x22);
+   printk("CY control reg %d: 0x%02x\n", i, inb(0x23));
+ }
+}
+#endif
+#if 0
+			  pcibios_write_config_word(dev->bus->number,
+						    dev->devfn, 0x04, 0x0007);
 
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x40, 0x80);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x41, 0x80);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x42, 0x80);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x43, 0x80);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x44, 0x27);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x45, 0xe0);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x48, 0xf0);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x49, 0x40);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x4a, 0x00);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x4b, 0x80);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x4c, 0x80);
+			  pcibios_write_config_byte(dev->bus->number,
+						    dev->devfn, 0x4d, 0x70);
+#endif
+			  outb(0, DMA1_RESET_REG);
+			  outb(0, DMA2_RESET_REG);
+			  outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
+			  outb(0, DMA2_MASK_REG);
+#if 0
+			  outb(0, DMA1_CLR_MASK_REG);
+			  outb(0, DMA2_CLR_MASK_REG);
+#endif
+			}
+#endif /* NOT_NOW */
+		}
 	}
 	if (ide_base) {
 		enable_ide(ide_base);
 	}
 }
 
+
 /*
  * The EB66+ is very similar to the EB66 except that it does not have
  * the on-board NCR and Tulip chips.  In the code below, I have used
@@ -639,6 +1077,7 @@
 static inline void eb66p_fixup(void)
 {
 	char irq_tab[5][5] = {
+          /*INT  INTA  INTB  INTC   INTD */
 		{16+0, 16+0, 16+5,  16+9, 16+13},	/* IdSel 6,  slot 0, J25 */
 		{16+1, 16+1, 16+6, 16+10, 16+14},	/* IdSel 7,  slot 1, J26 */
 		{  -1,   -1,   -1,    -1,    -1},	/* IdSel 8,  SIO         */
@@ -650,7 +1089,7 @@
 
 
 /*
- * The PC164 has 19 PCI interrupts, four from each of the four PCI
+ * The PC164/LX164 have 19 PCI interrupts, four from each of the four PCI
  * slots, the SIO, PCI/IDE, and USB.
  * 
  * Each of the interrupts can be individually masked. This is
@@ -693,12 +1132,9 @@
 
 static inline void alphapc164_fixup(void)
 {
-	extern int SMCInit(void);
+	extern void SMC93X_Init(void);
 	char irq_tab[7][5] = {
-	  /*
-	   *      int   intA  intB   intC   intD
-	   *      ----  ----  ----   ----   ----
-	   */
+          /*INT   INTA  INTB   INTC   INTD */
 		{ 16+2, 16+2, 16+9,  16+13, 16+17},	/* IdSel  5,  slot 2, J20 */
 		{ 16+0, 16+0, 16+7,  16+11, 16+15},	/* IdSel  6,  slot 0, J29 */
 		{ 16+1, 16+1, 16+8,  16+12, 16+16},	/* IdSel  7,  slot 1, J26 */
@@ -710,7 +1146,7 @@
 
 	common_fixup(5, 11, 5, irq_tab, 0);
 
-	SMCInit();
+	SMC93X_Init();
 }
 
 /*
@@ -729,6 +1165,7 @@
 static inline void cabriolet_fixup(void)
 {
 	char irq_tab[5][5] = {
+          /*INT   INTA  INTB  INTC   INTD */
 		{ 16+2, 16+2, 16+7, 16+11, 16+15},      /* IdSel 5,  slot 2, J21 */
 		{ 16+0, 16+0, 16+5,  16+9, 16+13},      /* IdSel 6,  slot 0, J19 */
 		{ 16+1, 16+1, 16+6, 16+10, 16+14},      /* IdSel 7,  slot 1, J20 */
@@ -785,6 +1222,7 @@
 static inline void eb66_and_eb64p_fixup(void)
 {
 	char irq_tab[5][5] = {
+          /*INT  INTA  INTB  INTC   INTD */
 		{16+7, 16+7, 16+7, 16+7,  16+7},	/* IdSel 5,  slot ?, ?? */
 		{16+0, 16+0, 16+2, 16+4,  16+9},	/* IdSel 6,  slot ?, ?? */
 		{16+1, 16+1, 16+3, 16+8, 16+10},	/* IdSel 7,  slot ?, ?? */
@@ -796,7 +1234,7 @@
 
 
 /*
- * Fixup configuration for MIKASA (NORITAKE is different)
+ * Fixup configuration for MIKASA
  *
  * Summary @ 0x536:
  * Bit      Meaning
@@ -848,6 +1286,86 @@
 }
 
 /*
+ * Fixup configuration for NORITAKE
+ *
+ * Summary @ 0x542, summary register #1:
+ * Bit      Meaning
+ * 0        All valid ints from summary regs 2 & 3
+ * 1        QLOGIC ISP1020A SCSI
+ * 2        Interrupt Line A from slot 0
+ * 3        Interrupt Line B from slot 0
+ * 4        Interrupt Line A from slot 1
+ * 5        Interrupt line B from slot 1
+ * 6        Interrupt Line A from slot 2
+ * 7        Interrupt Line B from slot 2
+ * 8        Interrupt Line A from slot 3
+ * 9        Interrupt Line B from slot 3
+ *10        Interrupt Line A from slot 4
+ *11        Interrupt Line B from slot 4
+ *12        Interrupt Line A from slot 5
+ *13        Interrupt Line B from slot 5
+ *14        Interrupt Line A from slot 6
+ *15        Interrupt Line B from slot 6
+ *
+ * Summary @ 0x544, summary register #2:
+ * Bit      Meaning
+ * 0        OR of all unmasked ints in SR #2
+ * 1        OR of secondary bus ints
+ * 2        Interrupt Line C from slot 0
+ * 3        Interrupt Line D from slot 0
+ * 4        Interrupt Line C from slot 1
+ * 5        Interrupt line D from slot 1
+ * 6        Interrupt Line C from slot 2
+ * 7        Interrupt Line D from slot 2
+ * 8        Interrupt Line C from slot 3
+ * 9        Interrupt Line D from slot 3
+ *10        Interrupt Line C from slot 4
+ *11        Interrupt Line D from slot 4
+ *12        Interrupt Line C from slot 5
+ *13        Interrupt Line D from slot 5
+ *14        Interrupt Line C from slot 6
+ *15        Interrupt Line D from slot 6
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot     Device
+ *  7       Intel PCI-EISA bridge chip
+ *  8       DEC PCI-PCI bridge chip
+ * 11       PCI on board slot 0
+ * 12       PCI on board slot 1
+ * 13       PCI on board slot 2
+ *   
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and 
+ * above for PCI interrupts.  The IRQ relates to which bit the interrupt
+ * comes in on.  This makes interrupt processing much easier.
+ */
+static inline void noritake_fixup(void)
+{
+	char irq_tab[15][5] = {
+	  /*INT    INTA   INTB   INTC   INTD */
+	  /* note: IDSELs 16, 17, and 25 are CORELLE only */
+          { 16+1,  16+1,  16+1,  16+1,  16+1},  /* IdSel 16,  QLOGIC */
+	  {   -1,    -1,    -1,    -1,    -1},	/* IdSel 17,  S3 Trio64 */
+	  {   -1,    -1,    -1,    -1,    -1},	/* IdSel 18,  PCEB */
+	  {   -1,    -1,    -1,    -1,    -1},	/* IdSel 19,  PPB  */
+	  {   -1,    -1,    -1,    -1,    -1},	/* IdSel 20,  ???? */
+	  {   -1,    -1,    -1,    -1,    -1},	/* IdSel 21,  ???? */
+	  { 16+2,  16+2,  16+3,  32+2,  32+3},	/* IdSel 22,  slot 0 */
+	  { 16+4,  16+4,  16+5,  32+4,  32+5},	/* IdSel 23,  slot 1 */
+	  { 16+6,  16+6,  16+7,  32+6,  32+7},	/* IdSel 24,  slot 2 */
+	  { 16+8,  16+8,  16+9,  32+8,  32+9},	/* IdSel 25,  slot 3 */
+	  /* the following 5 are actually on PCI bus 1, across the bridge */
+          { 16+1,  16+1,  16+1,  16+1,  16+1},  /* IdSel 16,  QLOGIC */
+          { 16+8,  16+8,  16+9,  32+8,  32+9},  /* IdSel 17,  slot 3 */
+          {16+10, 16+10, 16+11, 32+10, 32+11},  /* IdSel 18,  slot 4 */
+          {16+12, 16+12, 16+13, 32+12, 32+13},  /* IdSel 19,  slot 5 */
+          {16+14, 16+14, 16+15, 32+14, 32+15},  /* IdSel 20,  slot 6 */
+	};
+	common_fixup(5, 19, 5, irq_tab, 0);
+}
+
+/*
  * Fixup configuration for ALCOR
  *
  * Summary @ GRU_INT_REQ:
@@ -892,8 +1410,10 @@
  */
 static inline void alcor_fixup(void)
 {
-	char irq_tab[6][5] = {
+	char irq_tab[7][5] = {
 	  /*INT    INTA   INTB   INTC   INTD */
+	  /* note: IDSEL 17 is XLT only */
+	  {16+13, 16+13, 16+13, 16+13, 16+13},	/* IdSel 17,  TULIP  */
 	  { 16+8,  16+8,  16+9, 16+10, 16+11},	/* IdSel 18,  slot 0 */
 	  {16+16, 16+16, 16+17, 16+18, 16+19},	/* IdSel 19,  slot 3 */
 	  {16+12, 16+12, 16+13, 16+14, 16+15},	/* IdSel 20,  slot 4 */
@@ -901,9 +1421,10 @@
 	  { 16+0,  16+0,  16+1,  16+2,  16+3},	/* IdSel 22,  slot 2 */
 	  { 16+4,  16+4,  16+5,  16+6,  16+7},	/* IdSel 23,  slot 1 */
 	};
-	common_fixup(7, 12, 5, irq_tab, 0);
+	common_fixup(6, 12, 5, irq_tab, 0);
 }
 
+#if 0
 /*
  * Fixup configuration for ALPHA XLT (EV5/EV56)
  *
@@ -959,7 +1480,303 @@
 	};
 	common_fixup(6, 12, 5, irq_tab, 0);
 }
+#endif /* 0 */
 
+/*
+ * Fixup configuration for ALPHA SABLE (2100) - 2100A is different ??
+ *
+ * Summary Registers (536/53a/53c):
+ * Bit      Meaning
+ *-----------------
+ * 0        PCI slot 0
+ * 1        NCR810 (builtin)
+ * 2        TULIP (builtin)
+ * 3        mouse
+ * 4        PCI slot 1
+ * 5        PCI slot 2
+ * 6        keyboard
+ * 7        floppy
+ * 8        COM2
+ * 9        parallel port
+ *10        EISA irq 3
+ *11        EISA irq 4
+ *12        EISA irq 5
+ *13        EISA irq 6
+ *14        EISA irq 7
+ *15        COM1
+ *16        EISA irq 9
+ *17        EISA irq 10
+ *18        EISA irq 11
+ *19        EISA irq 12
+ *20        EISA irq 13
+ *21        EISA irq 14
+ *22        NC
+ *23        IIC
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot     Device
+ *  0       TULIP
+ *  1       SCSI
+ *  2       PCI-EISA bridge
+ *  3       none
+ *  4       none
+ *  5       none
+ *  6       PCI on board slot 0
+ *  7       PCI on board slot 1
+ *  8       PCI on board slot 2
+ *   
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and 
+ * above for PCI interrupts.  The IRQ relates to which bit the interrupt
+ * comes in on.  This makes interrupt processing much easier.
+ */
+/* NOTE: the IRQ assignments below are arbitrary, but need to be consistent
+   with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables
+   in irq.c
+ */
+static inline void sable_fixup(void)
+{
+        char irq_tab[9][5] = {
+          /*INT    INTA   INTB   INTC   INTD */
+          { 32+0,  32+0,  32+0,  32+0,  32+0},  /* IdSel 0,  TULIP  */
+          { 32+1,  32+1,  32+1,  32+1,  32+1},  /* IdSel 1,  SCSI   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 2,  SIO   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 3,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 4,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 5,  none   */
+          { 32+2,  32+2,  32+2,  32+2,  32+2},  /* IdSel 6,  slot 0 */
+          { 32+3,  32+3,  32+3,  32+3,  32+3},  /* IdSel 7,  slot 1 */
+          { 32+4,  32+4,  32+4,  32+4,  32+4},  /* IdSel 8,  slot 2 */
+        };
+        common_fixup(0, 8, 5, irq_tab, 0);
+}
+
+/*
+ * Fixup configuration for MIATA (EV56+PYXIS)
+ *
+ * Summary @ PYXIS_INT_REQ:
+ * Bit      Meaning
+ * 0        Fan Fault
+ * 1        NMI
+ * 2        Halt/Reset switch
+ * 3        none
+ * 4        CID0 (Riser ID)
+ * 5        CID1 (Riser ID)
+ * 6        Interval timer
+ * 7        PCI-ISA Bridge
+ * 8        Ethernet
+ * 9        EIDE (deprecated, ISA 14/15 used)
+ *10        none
+ *11        USB
+ *12        Interrupt Line A from slot 4
+ *13        Interrupt Line B from slot 4
+ *14        Interrupt Line C from slot 4
+ *15        Interrupt Line D from slot 4
+ *16        Interrupt Line A from slot 5
+ *17        Interrupt line B from slot 5
+ *18        Interrupt Line C from slot 5
+ *19        Interrupt Line D from slot 5
+ *20        Interrupt Line A from slot 1
+ *21        Interrupt Line B from slot 1
+ *22        Interrupt Line C from slot 1
+ *23        Interrupt Line D from slot 1
+ *24        Interrupt Line A from slot 2
+ *25        Interrupt Line B from slot 2
+ *26        Interrupt Line C from slot 2
+ *27        Interrupt Line D from slot 2
+ *27        Interrupt Line A from slot 3
+ *29        Interrupt Line B from slot 3
+ *30        Interrupt Line C from slot 3
+ *31        Interrupt Line D from slot 3
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot     Device
+ *  3       DC21142 Ethernet
+ *  4       EIDE CMD646
+ *  5       none
+ *  6       USB
+ *  7       PCI-ISA bridge
+ *  8       PCI-PCI Bridge      (SBU Riser)
+ *  9       none
+ * 10       none
+ * 11       PCI on board slot 4 (SBU Riser)
+ * 12       PCI on board slot 5 (SBU Riser)
+ *
+ *  These are behind the bridge, so I'm not sure what to do...
+ *
+ * 13       PCI on board slot 1 (SBU Riser)
+ * 14       PCI on board slot 2 (SBU Riser)
+ * 15       PCI on board slot 3 (SBU Riser)
+ *   
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and 
+ * above for PCI interrupts.  The IRQ relates to which bit the interrupt
+ * comes in on.  This makes interrupt processing much easier.
+ */
+static inline void miata_fixup(void)
+{
+	extern int es1888_init(void);
+	extern void SMC669_Init(void); /* might be a MiataGL */
+        char irq_tab[18][5] = {
+          /*INT    INTA   INTB   INTC   INTD */
+          {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8},  /* IdSel 14,  DC21142/3 */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 15,  EIDE   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 16,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 17,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 18,  PCI-ISA */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 19,  PCI-PCI old */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 20,  none    */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 21,  none    */
+          {16+12, 16+12, 16+13, 16+14, 16+15},  /* IdSel 22,  slot 4 */
+          {16+16, 16+16, 16+17, 16+18, 16+19},  /* IdSel 23,  slot 5 */
+	  /* the following 7 are actually on PCI bus 1, across the bridge */
+	  {16+11, 16+11, 16+11, 16+11, 16+11},  /* IdSel 24,  QLISP on GL  */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 25,  none    */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 26,  none    */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 27,  none    */
+          {16+20, 16+20, 16+21, 16+22, 16+23},  /* IdSel 28,  slot 1 */
+          {16+24, 16+24, 16+25, 16+26, 16+27},  /* IdSel 29,  slot 2 */
+          {16+28, 16+28, 16+29, 16+30, 16+31},  /* IdSel 30,  slot 3 */
+	  /* this bridge is on the main bus of the later original MIATA */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 31,  PCI-PCI new */
+        };
+	common_fixup(3, 20, 5, irq_tab, 0);
+	SMC669_Init(); /* might be a MiataGL, so try to find one of these */
+	es1888_init();
+}
+
+/*
+ * Fixup configuration for SX164 (PCA56+PYXIS)
+ *
+ * Summary @ PYXIS_INT_REQ:
+ * Bit      Meaning
+ * 0        RSVD
+ * 1        NMI
+ * 2        Halt/Reset switch
+ * 3        MBZ
+ * 4        RAZ
+ * 5        RAZ
+ * 6        Interval timer (RTC)
+ * 7        PCI-ISA Bridge
+ * 8        Interrupt Line A from slot 3
+ * 9        Interrupt Line A from slot 2
+ *10        Interrupt Line A from slot 1
+ *11        Interrupt Line A from slot 0
+ *12        Interrupt Line B from slot 3
+ *13        Interrupt Line B from slot 2
+ *14        Interrupt Line B from slot 1
+ *15        Interrupt line B from slot 0
+ *16        Interrupt Line C from slot 3
+ *17        Interrupt Line C from slot 2
+ *18        Interrupt Line C from slot 1
+ *19        Interrupt Line C from slot 0
+ *20        Interrupt Line D from slot 3
+ *21        Interrupt Line D from slot 2
+ *22        Interrupt Line D from slot 1
+ *23        Interrupt Line D from slot 0
+ *
+ * IdSel	
+ *   5	 32 bit PCI option slot 2
+ *   6	 64 bit PCI option slot 0
+ *   7	 64 bit PCI option slot 1
+ *   8	 Cypress I/O
+ *   9	 32 bit PCI option slot 3
+ * 
+ */
+
+static inline void sx164_fixup(void)
+{
+	extern void SMC669_Init(void);
+	char irq_tab[5][5] = {
+          /*INT    INTA   INTB   INTC   INTD */
+	  { 16+ 9, 16+ 9, 16+13, 16+17, 16+21},	/* IdSel 5 slot 2 J17 */
+	  { 16+11, 16+11, 16+15, 16+19, 16+23},	/* IdSel 6 slot 0 J19 */
+	  { 16+10, 16+10, 16+14, 16+18, 16+22},	/* IdSel 7 slot 1 J18 */
+	  {    -1,    -1,    -1,    -1,    -1},	/* IdSel 8 SIO        */
+	  { 16+ 8, 16+ 8, 16+12, 16+16, 16+20}	/* IdSel 9 slot 3 J15 */
+	};
+
+	common_fixup(5, 9, 5, irq_tab, 0);
+
+	SMC669_Init();
+}
+
+static inline void ruffian_fixup(void)
+{
+	struct pci_dev *dev;
+
+	/*
+	 * Go through all devices
+	 */
+	for (dev = pci_devices; dev; dev = dev->next) {
+		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+			/*
+			 * if it's a VGA, enable its BIOS ROM at C0000
+			 */
+			if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+			  /* but if its a Cirrus 543x/544x DISABLE it, */
+			  /* since enabling ROM disables the memory... */
+			   if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) &&
+			       (dev->device >= 0x00a0) &&
+			       (dev->device <= 0x00ac)) {
+				  pcibios_write_config_dword(
+					dev->bus->number,
+					dev->devfn,
+					PCI_ROM_ADDRESS,
+					0x00000000);
+			  } else {
+				  pcibios_write_config_dword(
+					dev->bus->number,
+					dev->devfn,
+					PCI_ROM_ADDRESS,
+					0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
+			  }
+			}
+			/*
+			 * if it's a SCSI, disable its BIOS ROM
+			 */
+			if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) {
+			  pcibios_write_config_dword(dev->bus->number,
+						     dev->devfn,
+						     PCI_ROM_ADDRESS,
+						     0x0000000);
+			}
+		}
+	}
+}
+
+/*
+ * The Takara has PCI devices 1, 2, and 3 configured to slots 20,
+ * 19, and 18 respectively, in the default configuration. They can
+ * also be jumpered to slots 8, 7, and 6 respectively, which is fun
+ * because the SIO ISA bridge can also be slot 7. However, the SIO
+ * doesn't explicitly generate PCI-type interrupts, so we can
+ * assign it whatever the hell IRQ we like and it doesn't matter.
+ */
+static inline void takara_fixup(void)
+{
+	char irq_tab[15][5] = {
+	    { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
+	    { 16+2, 16+2, 16+2, 16+2, 16+2},   /* slot  7 == device 2 */
+	    { 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot  8 == device 1 */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot  9 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 10 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 11 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 12 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 13 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 14 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 15 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 16 == nothing */
+	    {   -1,   -1,   -1,   -1,   -1},   /* slot 17 == nothing */
+	    { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot 18 == device 3 */
+	    { 16+2, 16+2, 16+2, 16+2, 16+2},   /* slot 19 == device 2 */
+	    { 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot 20 == device 1 */
+	};
+
+	common_fixup(6, 20, 5, irq_tab, 0x26e);
+}
 
 /*
  * Fixup configuration for all boards that route the PCI interrupts
@@ -1029,7 +1846,12 @@
 	 *  they are co-indicated when the platform type "Noname" is
 	 *  selected... :-(
 	 */
+#ifdef CONFIG_ALPHA_BOOK1
+        /* for the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15 */
+        const unsigned int route_tab = 0x0e0f0a0a;
+#else /* CONFIG_ALPHA_BOOK1 */
 	const unsigned int route_tab = 0x0b0a0f09;
+#endif  /* CONFIG_ALPHA_BOOK1 */
 #else /* CONFIG_ALPHA_NONAME */
 	const unsigned int route_tab = 0x0b0a090f;
 #endif /* CONFIG_ALPHA_NONAME */
@@ -1044,7 +1866,11 @@
 	 */
 	level_bits = 0;
 	for (dev = pci_devices; dev; dev = dev->next) {
-	        if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE)
+		if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE)
+#ifdef CONFIG_ALPHA_BOOK1
+                    && (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
+                    )
 			continue;
 		dev->irq = 0;
 		if (dev->bus->number != 0) {
@@ -1076,16 +1902,17 @@
 
 		if (slot < 6 || slot >= 6 + sizeof(pirq_tab)/sizeof(pirq_tab[0])) {
 			printk("bios32.sio_fixup: "
-			       "weird, found device %04x:%04x in non-existent slot %d!!\n",
+			       "weird, found device %04x:%04x "
+			       "in non-existent slot %d!!\n",
 			       dev->vendor, dev->device, slot);
 			continue;
 		}
 		pirq = pirq_tab[slot - 6][pin];
 
 		DBG_DEVS(("sio_fixup: bus %d  slot 0x%x  VID 0x%x  DID 0x%x\n"
-			  "           int_slot 0x%x  int_pin 0x%x,  pirq 0x%x\n",
-			  dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device,
-			  slot, pin, pirq));
+			  "           int_slot 0x%x  pin 0x%x  pirq 0x%x\n",
+			  dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor,
+			  dev->device, slot, pin, pirq));
 		/*
 		 * if it's a VGA, enable its BIOS ROM at C0000
 		 */
@@ -1107,15 +1934,51 @@
 
 		dev->irq = (route_tab >> (8 * pirq)) & 0xff;
 
+#ifndef CONFIG_ALPHA_BOOK1
+                /* do not set *ANY* level triggers for AlphaBook1 */
 		/* must set the PCI IRQs to level triggered */
 		level_bits |= (1 << dev->irq);
+#endif /* !CONFIG_ALPHA_BOOK1 */
 
 #if PCI_MODIFY
 		/* tell the device: */
 		pcibios_write_config_byte(dev->bus->number, dev->devfn,
 					  PCI_INTERRUPT_LINE, dev->irq);
 #endif
+
+#ifdef CONFIG_ALPHA_BOOK1
+                /*
+                 * on the AlphaBook1, the PCMCIA chip (Cirrus 6729)
+                 * is sensitive to PCI bus bursts, so we must DISABLE
+                 * burst mode for the NCR 8xx SCSI... :-(
+		 *
+		 * Note that the NCR810 SCSI driver must preserve the
+		 *  setting of the bit in order for this to work. At the
+		 *  moment (2.0.29), ncr53c8xx.c does NOT do this, but
+		 *  53c7,8xx.c DOES...
+                 */
+                if ((dev->vendor == PCI_VENDOR_ID_NCR) &&
+                    ((dev->device == PCI_DEVICE_ID_NCR_53C810) ||
+                     (dev->device == PCI_DEVICE_ID_NCR_53C815) ||
+                     (dev->device == PCI_DEVICE_ID_NCR_53C820) ||
+                     (dev->device == PCI_DEVICE_ID_NCR_53C825)
+                     )) {
+		    unsigned int io_port;
+		    unsigned char ctest4;
+
+                    pcibios_read_config_dword(dev->bus->number, dev->devfn,
+                                              PCI_BASE_ADDRESS_0, &io_port);
+                    io_port &= PCI_BASE_ADDRESS_IO_MASK;
+                    ctest4 = inb(io_port+0x21);
+                    if (!(ctest4 & 0x80)) {
+		        printk("AlphaBook1 NCR init: setting burst disable\n");
+                        outb(ctest4 | 0x80, io_port+0x21);
+                    }
 	}
+#endif /* CONFIG_ALPHA_BOOK1 */
+
+	} /* end for devs */
+
 	/*
 	 * Now, make all PCI interrupts level sensitive.  Notice:
 	 * these registers must be accessed byte-wise.  inw()/outw()
@@ -1125,21 +1988,43 @@
 	 *  so that the only bits getting set are for devices actually found.
 	 * Note that we do preserve the remainder of the bits, which we hope
 	 *  will be set correctly by ARC/SRM.
+	 *
+	 * Note: we at least preserve any level-set bits on AlphaBook1
 	 */
 	level_bits |= ((inb(0x4d0) | (inb(0x4d1) << 8)) & 0x71ff);
 	outb((level_bits >> 0) & 0xff, 0x4d0);
 	outb((level_bits >> 8) & 0xff, 0x4d1);
+
+#ifdef CONFIG_ALPHA_BOOK1
+        {
+	  unsigned char orig, config;
+	  /* on the AlphaBook1, make sure that register PR1 indicates 1Mb mem */
+	  outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5  */
+	  outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */
+	  outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */
+	  if ((config & 0xc0) != 0xc0) {
+            printk("AlphaBook1 VGA init: setting 1Mb memory\n");
+            config |= 0xc0;
+            outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */
+	  }
+	  outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */
+        }
+#endif /* CONFIG_ALPHA_BOOK1 */
+
+#ifndef CONFIG_ALPHA_BOOK1
+        /* do not do IDE init for AlphaBook1 */
 	enable_ide(0x26e);
+#endif /* !CONFIG_ALPHA_BOOK1 */
 }
 
 
 #ifdef CONFIG_TGA_CONSOLE
-extern void tga_console_init(void);
+extern void tga_console_find(void);
 #endif /* CONFIG_TGA_CONSOLE */
 
 unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
 {
-#if PCI_MODIFY
+#if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN)
 	/*
 	 * Scan the tree, allocating PCI memory and I/O space.
 	 */
@@ -1153,7 +2038,7 @@
 	sio_fixup();
 #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164)
 	cabriolet_fixup();
-#elif defined(CONFIG_ALPHA_PC164)
+#elif defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
 	alphapc164_fixup();
 #elif defined(CONFIG_ALPHA_EB66P)
 	eb66p_fixup();
@@ -1163,16 +2048,26 @@
 	eb66_and_eb64p_fixup();
 #elif defined(CONFIG_ALPHA_MIKASA)
 	mikasa_fixup();
-#elif defined(CONFIG_ALPHA_ALCOR)
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
 	alcor_fixup();
-#elif defined(CONFIG_ALPHA_XLT)
-	xlt_fixup();
+#elif defined(CONFIG_ALPHA_SABLE)
+	sable_fixup();
+#elif defined(CONFIG_ALPHA_MIATA)
+	miata_fixup();
+#elif defined(CONFIG_ALPHA_NORITAKE)
+	noritake_fixup();
+#elif defined(CONFIG_ALPHA_SX164)
+	sx164_fixup();
+#elif defined(CONFIG_ALPHA_TAKARA)
+	takara_fixup();
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+	ruffian_fixup();
 #else
 #	error You must tell me what kind of platform you want.
 #endif
 
 #ifdef CONFIG_TGA_CONSOLE
-        tga_console_init();
+        tga_console_find();
 #endif /* CONFIG_TGA_CONSOLE */
 
 	return mem_start;
@@ -1282,262 +2177,117 @@
 	}
         return err;
 }
-#ifdef CONFIG_ALPHA_PC164
-
-/* device "activate" register contents */
-#define DEVICE_ON		1
-#define DEVICE_OFF		0
-
-/* configuration on/off keys */
-#define CONFIG_ON_KEY		0x55
-#define CONFIG_OFF_KEY		0xaa
-
-/* configuration space device definitions */
-#define FDC			0
-#define IDE1			1
-#define IDE2			2
-#define PARP			3
-#define SER1			4
-#define SER2			5
-#define RTCL			6
-#define KYBD			7
-#define AUXIO			8
-
-/* Chip register offsets from base */
-#define CONFIG_CONTROL		0x02
-#define INDEX_ADDRESS		0x03
-#define LOGICAL_DEVICE_NUMBER	0x07
-#define DEVICE_ID		0x20
-#define DEVICE_REV		0x21
-#define POWER_CONTROL		0x22
-#define POWER_MGMT		0x23
-#define OSC			0x24
-
-#define ACTIVATE		0x30
-#define ADDR_HI			0x60
-#define ADDR_LO			0x61
-#define INTERRUPT_SEL		0x70
-#define INTERRUPT_SEL_2		0x72 /* KYBD/MOUS only */
-#define DMA_CHANNEL_SEL		0x74 /* FDC/PARP only */
-
-#define FDD_MODE_REGISTER	0x90
-#define FDD_OPTION_REGISTER	0x91
-
-/* values that we read back that are expected ... */
-#define VALID_DEVICE_ID		2
-
-/* default device addresses */
-#define KYBD_INTERRUPT		1
-#define MOUS_INTERRUPT		12
-#define COM2_BASE		0x2f8
-#define COM2_INTERRUPT		3
-#define COM1_BASE		0x3f8
-#define COM1_INTERRUPT		4
-#define PARP_BASE		0x3bc
-#define PARP_INTERRUPT		7
-
-#define SMC_DEBUG 0
-
-unsigned long SMCConfigState( unsigned long baseAddr )
-{
-    unsigned char devId;
-    unsigned char devRev;
-
-    unsigned long configPort;
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    configPort = indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )configPort + 1 );
-
-    outb(CONFIG_ON_KEY, configPort);
-    outb(CONFIG_ON_KEY, configPort);
-    outb(DEVICE_ID, indexPort);
-    devId = inb(dataPort);
-    if ( devId == VALID_DEVICE_ID ) {
-        outb(DEVICE_REV, indexPort);
-        devRev = inb(dataPort);
-    }
-    else {
-        baseAddr = 0;
-    }
-    return( baseAddr );
-}
-
-void SMCRunState( unsigned long baseAddr )
-{
-    outb(CONFIG_OFF_KEY, baseAddr);
-}
-
-unsigned long SMCDetectUltraIO(void)
-{
-    unsigned long baseAddr;
-
-    baseAddr = 0x3F0;
-    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
-        return( baseAddr );
-    }
-    baseAddr = 0x370;
-    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
-        return( baseAddr );
-    }
-    return( ( unsigned long )0 );
-}
-
-void SMCEnableDevice( unsigned long baseAddr,
-		      unsigned long device,
-		      unsigned long portaddr,
-		      unsigned long interrupt)
-{
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
 
-    outb(LOGICAL_DEVICE_NUMBER, indexPort);
-    outb(device, dataPort);
-
-    outb(ADDR_LO, indexPort);
-    outb(( portaddr & 0xFF ), dataPort);
-
-    outb(ADDR_HI, indexPort);
-    outb(( ( portaddr >> 8 ) & 0xFF ), dataPort);
-
-    outb(INTERRUPT_SEL, indexPort);
-    outb(interrupt, dataPort);
-
-    outb(ACTIVATE, indexPort);
-    outb(DEVICE_ON, dataPort);
-}
+#if (defined(CONFIG_ALPHA_PC164) || \
+     defined(CONFIG_ALPHA_LX164) || \
+     defined(CONFIG_ALPHA_SX164) || \
+     defined(CONFIG_ALPHA_EB164) || \
+     defined(CONFIG_ALPHA_EB66P) || \
+     defined(CONFIG_ALPHA_CABRIOLET)) && defined(CONFIG_ALPHA_SRM)
 
-void SMCEnableKYBD( unsigned long baseAddr )
+/*
+  on the above machines, under SRM console, we must use the CSERVE PALcode
+  routine to manage the interrupt mask for us, otherwise, the kernel/HW get
+  out of sync with what the PALcode thinks it needs to deliver/ignore
+ */
+void
+cserve_update_hw(unsigned long irq, unsigned long mask)
 {
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
-    outb(LOGICAL_DEVICE_NUMBER, indexPort);
-    outb(KYBD, dataPort);
-
-    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
-    outb(KYBD_INTERRUPT, dataPort);
+    extern void cserve_ena(unsigned long);
+    extern void cserve_dis(unsigned long);
 
-    outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */
-    outb(MOUS_INTERRUPT, dataPort);
-
-    outb(ACTIVATE, indexPort);
-    outb(DEVICE_ON, dataPort);
+    if (mask & (1UL << irq))
+	/* disable */
+	cserve_dis(irq - 16);
+    else
+      /* enable */
+	cserve_ena(irq - 16);
+    return;
+}
+#endif /* (PC164 || LX164 || SX164 || EB164 || CABRIO) && SRM */
+
+#ifdef CONFIG_ALPHA_MIATA
+
+/* init the built-in ES1888 sound chip (SB16 compatible) */
+int es1888_init(void)
+{
+    /* sequence of IO reads to init the audio controller */
+    inb(0x0229);
+    inb(0x0229);
+    inb(0x0229);
+    inb(0x022b);
+    inb(0x0229);
+    inb(0x022b);
+    inb(0x0229);
+    inb(0x0229);
+    inb(0x022b);
+    inb(0x0229);
+    inb(0x0220); /* this sets the base address to 0x220 */
+
+    /* sequence to set DMA channels */
+    outb(0x01, 0x0226); /* reset */
+    inb(0x0226); /* pause */
+    outb(0x00, 0x0226); /* release reset */
+    while (!(inb(0x022e) & 0x80)) /* wait for bit 7 to assert*/
+        continue;
+    inb(0x022a); /* pause */
+    outb(0xc6, 0x022c); /* enable extended mode */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0xb1, 0x022c); /* setup for write to Interrupt CR */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0x14, 0x022c); /* set IRQ 5 */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0xb2, 0x022c); /* setup for write to DMA CR */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0x18, 0x022c); /* set DMA channel 1 */
+
+    return 0;
 }
 
-void SMCEnableFDC( unsigned long baseAddr )
-{
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    unsigned char oldValue;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+#endif /* CONFIG_ALPHA_MIATA */
 
-    outb(LOGICAL_DEVICE_NUMBER, indexPort);
-    outb(FDC, dataPort);
-
-    outb(FDD_MODE_REGISTER, indexPort);
-    oldValue = inb(dataPort);
-
-    oldValue |= 0x0E;                   /* Enable burst mode */
-    outb(oldValue, dataPort);
-
-    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
-    outb(0x06, dataPort );
-
-    outb(DMA_CHANNEL_SEL, indexPort);  /* DMA channel select */
-    outb(0x02, dataPort);
-
-    outb(ACTIVATE, indexPort);
-    outb(DEVICE_ON, dataPort);
-}
-
-#if SMC_DEBUG
-void SMCReportDeviceStatus( unsigned long baseAddr )
+#ifdef CONFIG_ALPHA_SRM_SETUP
+void reset_for_srm(void)
 {
-    unsigned long indexPort;
-    unsigned long dataPort;
-    unsigned char currentControl;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
-    outb(POWER_CONTROL, indexPort);
-    currentControl = inb(dataPort);
-
-    if ( currentControl & ( 1 << FDC ) )
-        printk( "\t+FDC Enabled\n" );
-    else
-        printk( "\t-FDC Disabled\n" );
-
-    if ( currentControl & ( 1 << IDE1 ) )
-        printk( "\t+IDE1 Enabled\n" );
-    else
-        printk( "\t-IDE1 Disabled\n" );
-
-    if ( currentControl & ( 1 << IDE2 ) )
-        printk( "\t+IDE2 Enabled\n" );
-    else
-        printk( "\t-IDE2 Disabled\n" );
-
-    if ( currentControl & ( 1 << PARP ) )
-        printk( "\t+PARP Enabled\n" );
-    else
-        printk( "\t-PARP Disabled\n" );
-
-    if ( currentControl & ( 1 << SER1 ) )
-        printk( "\t+SER1 Enabled\n" );
-    else
-        printk( "\t-SER1 Disabled\n" );
-
-    if ( currentControl & ( 1 << SER2 ) )
-        printk( "\t+SER2 Enabled\n" );
-    else
-        printk( "\t-SER2 Disabled\n" );
+	extern void scrreset(void);
+	struct pci_dev *dev;
+	int i;
 
-    printk( "\n" );
-}
+	/* reset any IRQs that we changed */
+	for (i = 0; i < irq_reset_count; i++) {
+	    dev = irq_dev_to_reset[i];
+
+	    pcibios_write_config_byte(dev->bus->number, dev->devfn,
+				      PCI_INTERRUPT_LINE, irq_to_reset[i]);
+#if 1
+	    printk("reset_for_srm: bus %d slot 0x%x "
+		   "SRM IRQ 0x%x changed back from 0x%x\n",
+		   dev->bus->number, PCI_SLOT(dev->devfn),
+		   irq_to_reset[i], dev->irq);
 #endif
+	}
 
-int SMCInit(void)
-{
-    unsigned long SMCUltraBase;
-
-    if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) {
-        printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
-		SMCUltraBase );
-#if SMC_DEBUG
-        SMCReportDeviceStatus( SMCUltraBase );
-#endif
-        SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT );
-        SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT );
-        SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT );
-	/* on PC164, IDE on the SMC is not enabled; CMD646 (PCI) on MB */
-        SMCEnableKYBD( SMCUltraBase );
-        SMCEnableFDC( SMCUltraBase );
-#if SMC_DEBUG
-        SMCReportDeviceStatus( SMCUltraBase );
+	/* reset any IO addresses that we changed */
+	for (i = 0; i < io_reset_count; i++) {
+	    dev = io_dev_to_reset[i];
+
+	    pcibios_write_config_byte(dev->bus->number, dev->devfn,
+				      io_reg_to_reset[i], io_to_reset[i]);
+#if 1
+	    printk("reset_for_srm: bus %d slot 0x%x "
+		   "SRM IO restored to 0x%x\n",
+		   dev->bus->number, PCI_SLOT(dev->devfn),
+		   io_to_reset[i]);
 #endif
-        SMCRunState( SMCUltraBase );
-        return( 1 );
-    }
-    else {
-#if SMC_DEBUG
-        printk( "No SMC FDC37C93X Ultra I/O Controller found\n" );
-#endif
-        return( 0 );
-    }
 }
 
-#endif /* CONFIG_ALPHA_PC164 */
+	/* reset the visible screen to the top of display memory */
+	scrreset();
+}
+#endif /* CONFIG_ALPHA_SRM_SETUP */
 
 #endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/cia.c linux/arch/alpha/kernel/cia.c
--- v2.0.33/linux/arch/alpha/kernel/cia.c	Sat Jun  8 01:24:57 1996
+++ linux/arch/alpha/kernel/cia.c	Wed Jun  3 15:17:46 1998
@@ -20,26 +20,51 @@
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern int alpha_sys_type;
+
+/*
+ * Machine check reasons.  Defined according to PALcode sources
+ * (osf.h and platform.h).
+ */
+#define MCHK_K_TPERR		0x0080
+#define MCHK_K_TCPERR		0x0082
+#define MCHK_K_HERR		0x0084
+#define MCHK_K_ECC_C		0x0086
+#define MCHK_K_ECC_NC		0x0088
+#define MCHK_K_OS_BUGCHECK	0x008A
+#define MCHK_K_PAL_BUGCHECK	0x0090
+
 /*
  * BIOS32-style PCI interface:
  */
 
 #ifdef CONFIG_ALPHA_CIA
 
-#ifdef DEBUG 
-# define DBG(args)	printk args
+/* #define DEBUG_MCHECK */
+/* #define DEBUG_CONFIG */
+/* #define DEBUG_DUMP_REGS */
+
+#ifdef DEBUG_MCHECK
+# define DBGM(args)	printk args
 #else
-# define DBG(args)
+# define DBGM(args)
+#endif
+#ifdef DEBUG_CONFIG
+# define DBGC(args)	printk args
+#else
+# define DBGC(args)
 #endif
 
-#define vulp	volatile unsigned long *
 #define vuip	volatile unsigned int  *
 
 static volatile unsigned int CIA_mcheck_expected = 0;
 static volatile unsigned int CIA_mcheck_taken = 0;
-static unsigned long CIA_jd, CIA_jd1, CIA_jd2;
+static unsigned int CIA_jd;
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int CIA_DMA_WIN_BASE = CIA_DMA_WIN_BASE_DEFAULT;
+unsigned int CIA_DMA_WIN_SIZE = CIA_DMA_WIN_SIZE_DEFAULT;
+unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -88,7 +113,7 @@
 {
 	unsigned long addr;
 
-	DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
+	DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
 	     bus, device_fn, where, pci_addr, type1));
 
 	if (bus == 0) {
@@ -97,7 +122,8 @@
 		/* type 0 configuration cycle: */
 
 		if (device > 20) {
-			DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", device));
+			DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n",
+			     device));
 			return -1;
 		}
 
@@ -109,7 +135,7 @@
 		addr = (bus << 16) | (device_fn << 8) | (where);
 	}
 	*pci_addr = addr;
-	DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
 	return 0;
 }
 
@@ -120,22 +146,25 @@
 	unsigned int stat0, value;
 	unsigned int cia_cfg = 0; /* to keep gcc quiet */
 
+	value = 0xffffffffU;
+	mb();
+
 	save_flags(flags);	/* avoid getting hit by machine check */
 	cli();
 
-	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+	DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
 	/* reset status register to avoid losing errors: */
-	stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR);
-	*((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0;
+	stat0 = *((vuip)CIA_IOC_CIA_ERR);
+	*((vuip)CIA_IOC_CIA_ERR) = stat0;
 	mb();
-	DBG(("conf_read: CIA ERR was 0x%x\n", stat0));
+	DBGC(("conf_read: CIA ERR was 0x%x\n", stat0));
 	/* if Type1 access, must set CIA CFG */
 	if (type1) {
-		cia_cfg = *((unsigned int *)CIA_IOC_CFG);
+		cia_cfg = *((vuip)CIA_IOC_CFG);
+		*((vuip)CIA_IOC_CFG) = cia_cfg | 1;
 		mb();
-		*((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1;
-		DBG(("conf_read: TYPE1 access\n"));
+		DBGC(("conf_read: TYPE1 access\n"));
 	}
 
 	mb();
@@ -144,7 +173,7 @@
 	CIA_mcheck_taken = 0;
 	mb();
 	/* access configuration space: */
-	value = *((volatile unsigned int *)addr);
+	value = *((vuip)addr);
 	mb();
 	mb();
 	if (CIA_mcheck_taken) {
@@ -154,39 +183,14 @@
 	}
 	CIA_mcheck_expected = 0;
 	mb();
-	/*
-	 * david.rusling@reo.mts.dec.com.  This code is needed for the
-	 * EB64+ as it does not generate a machine check (why I don't
-	 * know).  When we build kernels for one particular platform
-	 * then we can make this conditional on the type.
-	 */
-#if 0
-	draina();
-
-	/* now look for any errors */
-	stat0 = *((unsigned int *)CIA_IOC_CIA_ERR);
-	DBG(("conf_read: CIA ERR after read 0x%x\n", stat0));
-	if (stat0 & 0x8280U) { /* is any error bit set? */
-		/* if not NDEV, print status */
-		if (!(stat0 & 0x0080)) {
-			printk("CIA.c:conf_read: got stat0=%x\n", stat0);
-		}
-
-		/* reset error status: */
-		*((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0;
-		mb();
-		wrmces(0x7);			/* reset machine check */
-		value = 0xffffffff;
-	}
-#endif
 
 	/* if Type1 access, must reset IOC CFG so normal IO space ops work */
 	if (type1) {
-		*((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1;
+		*((vuip)CIA_IOC_CFG) = cia_cfg & ~1;
 		mb();
 	}
 
-	DBG(("conf_read(): finished\n"));
+	DBGC(("conf_read(): finished\n"));
 
 	restore_flags(flags);
 	return value;
@@ -203,60 +207,36 @@
 	cli();
 
 	/* reset status register to avoid losing errors: */
-	stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR);
-	*((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0;
+	stat0 = *((vuip)CIA_IOC_CIA_ERR);
+	*((vuip)CIA_IOC_CIA_ERR) = stat0;
 	mb();
-	DBG(("conf_write: CIA ERR was 0x%x\n", stat0));
+	DBGC(("conf_write: CIA ERR was 0x%x\n", stat0));
 	/* if Type1 access, must set CIA CFG */
 	if (type1) {
-		cia_cfg = *((unsigned int *)CIA_IOC_CFG);
+		cia_cfg = *((vuip)CIA_IOC_CFG);
+		*((vuip)CIA_IOC_CFG) = cia_cfg | 1;
 		mb();
-		*((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1;
-		DBG(("conf_read: TYPE1 access\n"));
+		DBGC(("conf_write: TYPE1 access\n"));
 	}
 
 	draina();
 	CIA_mcheck_expected = 1;
 	mb();
 	/* access configuration space: */
-	*((volatile unsigned int *)addr) = value;
+	*((vuip)addr) = value;
 	mb();
 	mb();
-	CIA_mcheck_expected = 0;
-	mb();
-	/*
-	 * david.rusling@reo.mts.dec.com.  This code is needed for the
-	 * EB64+ as it does not generate a machine check (why I don't
-	 * know).  When we build kernels for one particular platform
-	 * then we can make this conditional on the type.
-	 */
-#if 0
-	draina();
 
-	/* now look for any errors */
-	stat0 = *((unsigned int *)CIA_IOC_CIA_ERR);
-	DBG(("conf_write: CIA ERR after write 0x%x\n", stat0));
-	if (stat0 & 0x8280U) { /* is any error bit set? */
-		/* if not NDEV, print status */
-		if (!(stat0 & 0x0080)) {
-			printk("CIA.c:conf_read: got stat0=%x\n", stat0);
-		}
-
-		/* reset error status: */
-		*((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0;
+	CIA_mcheck_expected = 0;
 		mb();
-		wrmces(0x7);			/* reset machine check */
-		value = 0xffffffff;
-	}
-#endif
 
 	/* if Type1 access, must reset IOC CFG so normal IO space ops work */
 	if (type1) {
-		*((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1;
+		*((vuip)CIA_IOC_CFG) = cia_cfg & ~1;
 		mb();
 	}
 
-	DBG(("conf_write(): finished\n"));
+	DBGC(("conf_write(): finished\n"));
 	restore_flags(flags);
 }
 
@@ -377,16 +357,135 @@
 
 unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
 {
-        unsigned int cia_err ;
+        unsigned int cia_tmp;
+
+#ifdef DEBUG_DUMP_REGS
+	{
+          unsigned int temp;
+#if 1
+	  temp = *((vuip)CIA_IOC_CIA_REV); mb();
+          printk("CIA_init: CIA_REV was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_PCI_LAT); mb();
+          printk("CIA_init: CIA_PCI_LAT was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_CIA_CTRL); mb();
+          printk("CIA_init: CIA_CTRL was 0x%x\n", temp);
+	  temp = *((vuip)0xfffffc8740000140UL); mb();
+          printk("CIA_init: CIA_CTRL1 was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_HAE_MEM); mb();
+          printk("CIA_init: CIA_HAE_MEM was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_HAE_IO); mb();
+          printk("CIA_init: CIA_HAE_IO was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_CFG); mb();
+          printk("CIA_init: CIA_CFG was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_CACK_EN); mb();
+          printk("CIA_init: CIA_CACK_EN was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_CFG); mb();
+          printk("CIA_init: CIA_CFG was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_CIA_DIAG); mb();
+          printk("CIA_init: CIA_DIAG was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_DIAG_CHECK); mb();
+          printk("CIA_init: CIA_DIAG_CHECK was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_PERF_MONITOR); mb();
+          printk("CIA_init: CIA_PERF_MONITOR was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_PERF_CONTROL); mb();
+          printk("CIA_init: CIA_PERF_CONTROL was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_CIA_ERR); mb();
+          printk("CIA_init: CIA_ERR was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_CIA_STAT); mb();
+          printk("CIA_init: CIA_STAT was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_MCR); mb();
+          printk("CIA_init: CIA_MCR was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_ERR_MASK); mb();
+          printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp);
+#endif
+	  temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb();
+          printk("CIA_init: W0_BASE was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb();
+          printk("CIA_init: W1_BASE was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb();
+          printk("CIA_init: W2_BASE was 0x%x\n", temp);
+	  temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb();
+          printk("CIA_init: W3_BASE was 0x%x\n", temp);
+	}
+#endif /* DEBUG_DUMP_REGS */
 
         /* 
 	 * Set up error reporting.
 	 */
-	cia_err = *(vuip)CIA_IOC_CIA_ERR ;
-	cia_err |= (0x1 << 7) ;   /* master abort */
-	*(vuip)CIA_IOC_CIA_ERR = cia_err ;
+	cia_tmp = *(vuip)CIA_IOC_CIA_ERR;
+	cia_tmp |= 0x180 ;   /* master, target abort */
+	*(vuip)CIA_IOC_CIA_ERR = cia_tmp ;
 	mb() ;
 
+	cia_tmp = *(vuip)CIA_IOC_CIA_CTRL;
+	cia_tmp |= 0x400;   /* turn on FILL_ERR to get mchecks */
+	*(vuip)CIA_IOC_CIA_CTRL = cia_tmp ;
+	mb() ;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	/* check window 0 for enabled and mapped to 0 */
+	if (((*(vuip)CIA_IOC_PCI_W0_BASE & 3) == 1) &&
+	    (*(vuip)CIA_IOC_PCI_T0_BASE == 0))
+	{
+	  CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W0_BASE & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W0_MASK & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("cia_init: using Window 0 settings\n");
+	  printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)CIA_IOC_PCI_W0_BASE,
+		 *(vuip)CIA_IOC_PCI_W0_MASK,
+		 *(vuip)CIA_IOC_PCI_T0_BASE);
+#endif
+	}
+	else  /* check window 1 for enabled and mapped to 0 */
+	if (((*(vuip)CIA_IOC_PCI_W1_BASE & 3) == 1) &&
+	    (*(vuip)CIA_IOC_PCI_T1_BASE == 0))
+	{
+	  CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W1_BASE & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W1_MASK & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("cia_init: using Window 1 settings\n");
+	  printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)CIA_IOC_PCI_W1_BASE,
+		 *(vuip)CIA_IOC_PCI_W1_MASK,
+		 *(vuip)CIA_IOC_PCI_T1_BASE);
+#endif
+	}
+	else  /* check window 2 for enabled and mapped to 0 */
+	if (((*(vuip)CIA_IOC_PCI_W2_BASE & 3) == 1) &&
+	    (*(vuip)CIA_IOC_PCI_T2_BASE == 0))
+	{
+	  CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W2_BASE & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W2_MASK & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("cia_init: using Window 2 settings\n");
+	  printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)CIA_IOC_PCI_W2_BASE,
+		 *(vuip)CIA_IOC_PCI_W2_MASK,
+		 *(vuip)CIA_IOC_PCI_T2_BASE);
+#endif
+	}
+	else  /* check window 3 for enabled and mapped to 0 */
+	if (((*(vuip)CIA_IOC_PCI_W3_BASE & 3) == 1) &&
+	    (*(vuip)CIA_IOC_PCI_T3_BASE == 0))
+	{
+	  CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W3_BASE & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W3_MASK & 0xfff00000U;
+	  CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("cia_init: using Window 3 settings\n");
+	  printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)CIA_IOC_PCI_W3_BASE,
+		 *(vuip)CIA_IOC_PCI_W3_MASK,
+		 *(vuip)CIA_IOC_PCI_T3_BASE);
+#endif
+	}
+	else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+	{
 	/*
 	 * Set up the PCI->physical memory translation windows.
 	 * For now, windows 1,2 and 3 are disabled.  In the future, we may
@@ -401,6 +500,7 @@
 	*(vuip)CIA_IOC_PCI_W1_BASE = 0x0 ;
 	*(vuip)CIA_IOC_PCI_W2_BASE = 0x0 ;
 	*(vuip)CIA_IOC_PCI_W3_BASE = 0x0 ;
+	}
 
 	/*
 	 * check ASN in HWRPB for validity, report if bad
@@ -412,17 +512,44 @@
 	}
 
         /*
-         * Finally, clear the CIA_CFG register, which gets used
+         *  Next, clear the CIA_CFG register, which gets used
          *  for PCI Config Space accesses. That is the way
          *  we want to use it, and we do not want to depend on
          *  what ARC or SRM might have left behind...
          */
         {
+          unsigned int cia_cfg = *((vuip)CIA_IOC_CFG); mb();
+          if (cia_cfg) {
+	      printk("CIA_init: CFG was 0x%x\n", cia_cfg);
+	      *((vuip)CIA_IOC_CFG) = 0; mb();
+	  }
+        }
+ 
+        {
+          unsigned int cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM);
+          unsigned int cia_hae_io = *((vuip)CIA_IOC_HAE_IO);
 #if 0
-          unsigned int cia_cfg = *((unsigned int *)CIA_IOC_CFG); mb();
-          if (cia_cfg) printk("CIA_init: CFG was 0x%x\n", cia_cfg);
+	  printk("CIA_init: HAE_MEM was 0x%x\n", cia_hae_mem);
+	  printk("CIA_init: HAE_IO was 0x%x\n", cia_hae_io);
 #endif
-          *((unsigned int *)CIA_IOC_CFG) = 0; mb();
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	  /*
+	    sigh... For the SRM setup, unless we know apriori what the HAE
+	    contents will be, we need to setup the arbitrary region bases
+	    so we can test against the range of addresses and tailor the
+	    region chosen for the SPARSE memory access.
+
+	    see include/asm-alpha/cia.h for the SPARSE mem read/write
+	  */
+	  cia_sm_base_r1 = (cia_hae_mem      ) & 0xe0000000UL; /* region 1 */
+	  cia_sm_base_r2 = (cia_hae_mem << 16) & 0xf8000000UL; /* region 2 */
+	  cia_sm_base_r3 = (cia_hae_mem << 24) & 0xfc000000UL; /* region 3 */
+#else /* SRM_SETUP */
+	  *((vuip)CIA_IOC_HAE_MEM) = 0; mb();
+	  cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM);
+	  *((vuip)CIA_IOC_HAE_IO) = 0; mb();
+	  cia_hae_io = *((vuip)CIA_IOC_HAE_IO);
+#endif /* SRM_SETUP */
         }
  
 	return mem_start;
@@ -430,9 +557,9 @@
 
 int cia_pci_clr_err(void)
 {
-	CIA_jd = *((unsigned int *)CIA_IOC_CIA_ERR);
-	DBG(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
-	*((unsigned long *)CIA_IOC_CIA_ERR) = 0x0080;
+	CIA_jd = *((vuip)CIA_IOC_CIA_ERR);
+	DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
+	*((vuip)CIA_IOC_CIA_ERR) = 0x0180;
 	mb();
 	return 0;
 }
@@ -440,41 +567,45 @@
 void cia_machine_check(unsigned long vector, unsigned long la_ptr,
 			 struct pt_regs * regs)
 {
-#if 0
-        printk("CIA machine check ignored\n") ;
-#else
 	struct el_common *mchk_header;
+	struct el_procdata *mchk_procdata;
 	struct el_CIA_sysdata_mcheck *mchk_sysdata;
+	unsigned long * ptr;
+	const char * reason;
+	char buf[128];
+	long i;
 
 	mchk_header = (struct el_common *)la_ptr;
-
+	mchk_procdata =
+		(struct el_procdata *)(la_ptr + mchk_header->proc_offset);
 	mchk_sysdata = 
 	  (struct el_CIA_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
 
-	DBG(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
-	DBG(("                     pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+	DBGM(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
+	DBGM(("                     pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
 	     regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset));
-	DBG(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
+	DBGM(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
 	     CIA_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear));
-#ifdef DEBUG
+#ifdef DEBUG_MCHECK
 	{
 	    unsigned long *ptr;
 	    int i;
 
 	    ptr = (unsigned long *)la_ptr;
 	    for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
-		printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+			printk(" +%lx %lx %lx\n", i*sizeof(long),
+			       ptr[i], ptr[i+1]);
 	    }
 	}
-#endif /* DEBUG */
+#endif /* DEBUG_MCHECK */
 	/*
 	 * Check if machine check is due to a badaddr() and if so,
 	 * ignore the machine check.
 	 */
 	mb();
 	mb();
-	if (CIA_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
-		DBG(("CIA machine check expected\n"));
+	if (CIA_mcheck_expected) {
+		DBGM(("CIA machine check expected\n"));
 		CIA_mcheck_expected = 0;
 		CIA_mcheck_taken = 1;
 		mb();
@@ -483,12 +614,58 @@
 		cia_pci_clr_err();
 		wrmces(0x7);
 		mb();
+		return;
+	}
+
+	switch ((unsigned int) mchk_header->code) {
+	      case MCHK_K_TPERR:	reason = "tag parity error"; break;
+	      case MCHK_K_TCPERR:	reason = "tag control parity error"; break;
+	      case MCHK_K_HERR:		reason = "generic hard error"; break;
+	      case MCHK_K_ECC_C:	reason = "correctable ECC error"; break;
+	      case MCHK_K_ECC_NC:	reason = "uncorrectable ECC error"; break;
+	      case MCHK_K_OS_BUGCHECK:	reason = "OS-specific PAL bugcheck"; break;
+	      case MCHK_K_PAL_BUGCHECK:	reason = "callsys in kernel mode"; break;
+	      case 0x96: reason = "i-cache read retryable error"; break;
+	      case 0x98: reason = "processor detected hard error"; break;
+
+		/* system specific (these are for Alcor, at least): */
+	      case 0x203: reason = "system detected uncorrectable ECC error"; break;
+	      case 0x205: reason = "parity error detected by CIA"; break;
+	      case 0x207: reason = "non-existent memory error"; break;
+	      case 0x209: reason = "PCI SERR detected"; break;
+	      case 0x20b: reason = "PCI data parity error detected"; break;
+	      case 0x20d: reason = "PCI address parity error detected"; break;
+	      case 0x20f: reason = "PCI master abort error"; break;
+	      case 0x211: reason = "PCI target abort error"; break;
+	      case 0x213: reason = "scatter/gather PTE invalid error"; break;
+	      case 0x215: reason = "flash ROM write error"; break;
+	      case 0x217: reason = "IOA timeout detected"; break;
+	      case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
+	      case 0x21b: reason = "EISA fail-safe timer timeout"; break;
+	      case 0x21d: reason = "EISA bus time-out"; break;
+	      case 0x21f: reason = "EISA software generated NMI"; break;
+	      case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
+	      default:
+		sprintf(buf, "reason for machine-check unknown (0x%x)",
+			(unsigned int) mchk_header->code);
+		reason = buf;
+		break;
+	}
+	wrmces(rdmces());	/* reset machine check pending flag */
+	mb();
+
+	printk(KERN_CRIT "  CIA machine check: %s%s\n",
+	       reason, mchk_header->retry ? " (retryable)" : "");
+	printk(KERN_CRIT "   vector=0x%lx la_ptr=0x%lx pc=0x%lx\n",
+	       vector, la_ptr, regs->pc);
+
+	/* dump the logout area to give all info: */
+
+	ptr = (unsigned long *)la_ptr;
+	for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+	    printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+		   i*sizeof(long), ptr[i], ptr[i+1]);
 	}
-#if 1
-	else
-	  printk("CIA machine check NOT expected\n") ;
-#endif
-#endif
 }
 
 #endif /* CONFIG_ALPHA_CIA */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.0.33/linux/arch/alpha/kernel/entry.S	Thu Nov 21 03:41:46 1996
+++ linux/arch/alpha/kernel/entry.S	Wed Jun  3 15:17:46 1998
@@ -4,6 +4,7 @@
  * kernel entry-points
  */
 
+#include <linux/config.h>
 #include <asm/system.h>
 
 #define halt	.long PAL_halt
@@ -22,7 +23,7 @@
 /*
  * stack offsets
  */
-#define SP_OFF		160
+#define SP_OFF		184
 
 #define SWITCH_STACK_SIZE 320
 
@@ -47,9 +48,11 @@
  * regs 9-15 preserved by C code
  * regs 16-18 saved by PAL-code
  * regs 29-30 saved and set up by PAL-code
+ * JRP - Save regs 16-18 in a special area of the stack, so that
+ * the palcode-provided values are available to the signal handler.
  */
 #define SAVE_ALL			\
-	subq	$30,160,$30;		\
+	subq	$30,184,$30;		\
 	stq	$0,0($30);		\
 	stq	$1,8($30);		\
 	stq	$2,16($30);		\
@@ -71,7 +74,10 @@
 	stq	$28,144($30);		\
 	lda	$2,hae;			\
 	ldq	$2,HAE_CACHE($2);	\
-	stq	$2,152($30)
+	stq	$2,152($30);		\
+	stq	$16,160($30);		\
+	stq	$17,168($30);		\
+	stq	$18,176($30)
 
 #define RESTORE_ALL			\
 	lda	$8,hae;			\
@@ -107,11 +113,11 @@
 	ldq	$26,128($30);		\
 	ldq	$27,136($30);		\
 	ldq	$28,144($30);		\
-	addq	$30,160,$30
+	addq	$30,184,$30
 
 .text
 .set noat
-#ifdef __linux__
+#if defined(__linux__) && !defined(__ELF__)
   .set singlegp
 #endif
 
@@ -160,6 +166,36 @@
 .globl	entIF
 .ent	entIF
 entIF:
+#ifdef CONFIG_KGDB
+	bne	$16,1f		/* not a bpt trap -> */
+	/*
+	 * Call kgdb if it's enabled and if "current" is not being
+	 * traced or if we get a bpt in kernel mode (the architecture
+	 * manual defines the values of $17 and $18 as "unpredictable",
+	 * so they are fair game).
+	 */
+	lda	$17,kgdb_enabled
+	ldl	$17,0($17)
+	beq	$17,1f		/* kgdb not enabled -> */
+
+#ifndef CONFIG_ALPHA_CABRIOLET
+	/*
+	 * MILO on Cabriolet doesn't seem to setup the PS in the
+	 * PALframe correctly. (davidm@azstarnet.com)
+	 */
+	ldq	$18,0($30)	/* get ps */
+	and	$18,8,$18
+	beq	$18,entKGDB
+#endif
+
+	lda	$17,current_set
+	ldq	$17,0($17)
+	bis	$31,PF_PTRACED,$18
+	ldq	$17,TASK_FLAGS($17)
+	and	$17,$18,$17
+	beq	$17,entKGDB
+1:
+#endif
 	SAVE_ALL
 	lda	$27,do_entIF
 	lda	$26,ret_from_sys_call
@@ -759,3 +795,127 @@
 	.quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname
 	.quad sys_nanosleep, sys_mremap, do_entSys, do_entSys, do_entSys
 	.quad sys_pciconfig_read, sys_pciconfig_write, do_entSys, do_entSys, do_entSys
+
+
+#ifdef CONFIG_KGDB
+
+#define KGDB_STACK_SIZE	(8*1024)
+
+	.lcomm	kgdb_stack_bottom, KGDB_STACK_SIZE
+
+/*
+ * The following is the nasty part of entering KGDB.  GDB assumes that
+ * it can access the memory below the interrupted thread's stack
+ * pointer (SP).  This means that the stub cannot run on this stack
+ * (interrupts could overwrite changes made by GDB).  Similarly, we do
+ * not want to bother the GDB user with the call chain leading from
+ * the interrupt handler to this function.  That is, the SP reported
+ * to GDB should be the thread's SP at the point it was interrupted.  We
+ * achieve all this by switching to KGDB's own stack before saving any
+ * registers (of course, the PAL-generated frame is already on the stack and
+ * we copy that part explicitly).  GDB does whatever it wants to the
+ * thread's stack; and when it continues execution, we restore the
+ * registers from the private stack and return from the interrupt.
+ *
+ * This is not re-entrant---gdb on the host probably would get confused
+ * anyway, but we probably ought to detect that case at the least...
+ */
+.align 3
+.globl	entKGDB
+.ent	entKGDB
+entKGDB:
+	lda	$16,kgdb_stack_bottom
+	lda	$16,(KGDB_STACK_SIZE-48)($16)
+	bis	$31,$30,$17	/* save real sp in a1 */
+	bis	$31,$16,$30	/* update sp atomically! */
+	SAVE_ALL		/* save regular stuff */
+	/*
+	 * Only now can we disable interrupts (swpipl may step on
+	 * t0,t8..t11, and a0):
+	 */
+	bis	$31,7,$16
+	call_pal PAL_swpipl
+
+	/* copy PAL frame to kgdb stack: */
+
+	ldq	$1,0($17)
+	ldq	$2,8($17)
+	ldq	$3,16($17)
+	ldq	$4,24($17)
+	ldq	$5,32($17)
+	ldq	$6,40($17)
+
+	stq	$1,0+184($30)
+	stq	$2,8+184($30)
+	stq	$3,16+184($30)
+	stq	$4,24+184($30)
+	stq	$5,32+184($30)
+	stq	$6,40+184($30)
+
+	/* allocate space for and save caller saved regs as well as orig sp: */
+
+	lda	$30,-320($30)
+	addq	$17,48,$17	/* pop PAL frame */
+	stq	$17,0($30)	/* save original sp */
+
+	stq	 $9,0x08($30); stq $10,0x10($30); stq $11,0x18($30)
+	stq	$12,0x20($30); stq $13,0x28($30); stq $14,0x30($30)
+	stq	$15,0x38($30)
+
+	stt	$f0,0x40($30);   stt $f1,0x48($30);   stt $f2,0x50($30);   stt $f3,0x58($30)
+	stt	$f4,0x60($30);   stt $f5,0x68($30);   stt $f6,0x70($30);   stt $f7,0x78($30)
+	stt	$f8,0x80($30);   stt $f9,0x88($30);   stt $f10,0x90($30);  stt $f11,0x98($30)
+	stt	$f12,0xa0($30);  stt $f13,0xa8($30);  stt $f14,0xb0($30);  stt $f15,0xb8($30)
+	stt	$f16,0xc0($30);  stt $f17,0xc8($30);  stt $f18,0xd0($30);  stt $f19,0xd8($30)
+	stt	$f20,0xe0($30);  stt $f21,0xe8($30);  stt $f22,0xf0($30);  stt $f23,0xf8($30)
+	stt	$f24,0x100($30); stt $f25,0x108($30); stt $f26,0x110($30); stt $f27,0x118($30)
+	stt	$f28,0x120($30); stt $f29,0x128($30); stt $f30,0x130($30); stt $f31,0x138($30)
+
+	bis	$31,$30,$16
+
+	lda	$27,kgdb_handle_exception
+	jsr	$26,($27),kgdb_handle_exception
+
+	ldq	$17,0($30)	/* load new sp and caller-saved registers */
+
+	ldq	 $9,0x08($30); ldq $10,0x10($30); ldq $11,0x18($30)
+	ldq	$12,0x20($30); ldq $13,0x28($30); ldq $14,0x30($30)
+	ldq	$15,0x38($30)
+
+	ldt	$f0,0x40($30);   ldt $f1,0x48($30);   ldt $f2,0x50($30);   ldt $f3,0x58($30)
+	ldt	$f4,0x60($30);   ldt $f5,0x68($30);   ldt $f6,0x70($30);   ldt $f7,0x78($30)
+	ldt	$f8,0x80($30);   ldt $f9,0x88($30);   ldt $f10,0x90($30);  ldt $f11,0x98($30)
+	ldt	$f12,0xa0($30);  ldt $f13,0xa8($30);  ldt $f14,0xb0($30);  ldt $f15,0xb8($30)
+	ldt	$f16,0xc0($30);  ldt $f17,0xc8($30);  ldt $f18,0xd0($30);  ldt $f19,0xd8($30)
+	ldt	$f20,0xe0($30);  ldt $f21,0xe8($30);  ldt $f22,0xf0($30);  ldt $f23,0xf8($30)
+	ldt	$f24,0x100($30); ldt $f25,0x108($30); ldt $f26,0x110($30); ldt $f27,0x118($30)
+	ldt	$f28,0x120($30); ldt $f29,0x128($30); ldt $f30,0x130($30); ldt $f31,0x138($30)
+	lda	$30,320($30)	/* pop extra register frame */
+
+	/*
+	 * Copy PAL frame from kgdb stack to new stack so we can rti
+	 * to it:
+	 */
+	ldq	$1,0+184($30)
+	ldq	$2,8+184($30)
+	ldq	$3,16+184($30)
+	ldq	$4,24+184($30)
+	ldq	$5,32+184($30)
+	ldq	$6,40+184($30)
+
+	subq	$17,48,$17	/* alloc space for PAL frame on new stack */
+
+	stq	$1,0($17)
+	stq	$2,8($17)
+	stq	$3,16($17)
+	stq	$4,24($17)
+	stq	$5,32($17)
+	stq	$6,40($17)
+
+	RESTORE_ALL
+	bis	$31,$17,$30	/* establish new sp */
+	rti
+
+.end entKGDB
+
+#endif /* CONFIG_KGDB */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.0.33/linux/arch/alpha/kernel/head.S	Mon Jul  1 10:06:05 1996
+++ linux/arch/alpha/kernel/head.S	Wed Jun  3 15:17:46 1998
@@ -92,6 +92,50 @@
 	ret	($26)
 	.end wrmces
 
+	.align 3
+	.globl  whami
+	.ent    whami
+whami:
+	call_pal PAL_whami
+	ret     ($26)
+	.end whami
+ 
+	.align 3
+	.globl  wripir
+	.ent    wripir
+wripir:
+	call_pal PAL_wripir
+	ret     ($26)
+	.end wripir
+
+	.align 3
+	.globl	cserve_ena
+	.ent	cserve_ena
+cserve_ena:
+	lda	$30,-0x08($30)
+	stq	$17,0($30)
+	bis	$16,$16,$17
+	lda	$16,52($31)
+	call_pal PAL_cserve
+	ldq	$17,0($30)
+	lda	$30,0x08($30)
+	ret	($26)
+	.end	cserve_ena
+
+	.align 3
+	.globl	cserve_dis
+	.ent	cserve_dis
+cserve_dis:
+	lda	$30,-0x08($30)
+	stq	$17,0($30)
+	bis	$16,$16,$17
+	lda	$16,53($31)
+	call_pal PAL_cserve
+	ldq	$17,0($30)
+	lda	$30,0x08($30)
+	ret	($26)
+	.end	cserve_dis
+
 	#
 	# The following two functions don't need trapb/excb instructions
 	# around the mf_fpcr/mt_fpcr instructions because (a) the kernel
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.0.33/linux/arch/alpha/kernel/irq.c	Mon Oct 13 08:28:55 1997
+++ linux/arch/alpha/kernel/irq.c	Wed Jun  3 15:17:46 1998
@@ -27,6 +27,7 @@
 #include <asm/dma.h>
 
 extern void timer_interrupt(struct pt_regs * regs);
+extern void cserve_update_hw(unsigned long, unsigned long);
 
 #if NR_IRQS > 64
 #  error Unable to handle more than 64 irq levels.
@@ -42,7 +43,8 @@
  *	 0.. 7	first (E)ISA PIC (irq level 0..7)
  *	 8..15	second (E)ISA PIC (irq level 8..15)
  *   Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT):
- *	16..47	PCI interrupts 0..31 (int at GRU_INT_MASK)
+ *    or PYXIS (e.g. Miata, PC164-LX)
+ *	16..47	PCI interrupts 0..31 (xxx_INT_MASK reg)
  *   Mikasa:
  *	16..31	PCI interrupts 0..15 (short at I/O port 536)
  *   Other systems (not Mikasa) with 16 PCI interrupt lines:
@@ -50,13 +52,43 @@
  *	24..31	PCI interrupts 8..15 (char at I/O port 27)
  *   Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164):
  *	16..32	PCI interrupts 0..31 (int at I/O port 804)
+ *   Takara:
+ *      16..19  PCI interrupts A thru D
+ *   For SABLE, which is really baroque, we manage 40 IRQ's, but the
+ *   hardware really only supports 24, not via normal ISA PIC,
+ *   but cascaded custom 8259's, etc.
+ *	 0-7  (char at 536)
+ *	 8-15 (char at 53a)
+ *	16-23 (char at 53c)
  */
 static unsigned long irq_mask = ~0UL;
 
+#ifdef CONFIG_ALPHA_SABLE
+/* note that the vector reported by the SRM PALcode corresponds to the
+   interrupt mask bits, but we have to manage via more normal IRQs */
+static char sable_irq_to_mask[NR_IRQS] = {
+	-1,  6, -1,  8, 15, 12,  7,  9, /* pseudo PIC  0-7  */
+	-1, 16, 17, 18,  3, -1, 21, 22, /* pseudo PIC  8-15 */
+	-1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7  */
+	-1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */
+	 2,  1,  0,  4,  5, -1, -1, -1, /* pseudo PCI */
+	};
+#define IRQ_TO_MASK(irq) (sable_irq_to_mask[(irq)])
+static char sable_mask_to_irq[NR_IRQS] = {
+	34, 33, 32, 12, 35, 36,  1,  6, /* mask 0-7  */
+	 3,  7, -1, -1,  5, -1, -1,  4, /* mask 8-15  */
+	 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23  */
+	};
+#else /* CONFIG_ALPHA_SABLE */
+#define IRQ_TO_MASK(irq) (irq)
+#endif /* CONFIG_ALPHA_SABLE */
 
 /*
  * Update the hardware with the irq mask passed in MASK.  The function
  * exploits the fact that it is known that only bit IRQ has changed.
+ *
+ * There deliberately isn't a case in here for the Takara since it
+ * wouldn't work anyway because the interrupt controller is bizarre.
  */
 static void update_hw(unsigned long irq, unsigned long mask)
 {
@@ -65,32 +97,111 @@
 	mask |= 0x7ff00000UL << 16;
 #endif
 	switch (irq) {
-#if NR_IRQS == 48
-	      default:
+
+#ifdef CONFIG_ALPHA_SABLE
+  /* SABLE does everything different, so we manage it that way... :-( */
+  /* the "irq" argument is really the mask bit number */
+	case 0 ... 7:
+	  outb(mask, 0x537);
+	  break;
+	case 8 ... 15:
+	  outb(mask >> 8, 0x53b);
+	  break;
+	case 16 ... 23:
+	  outb(mask >> 16, 0x53d);
+	  break;
+#else /* SABLE */
+
+#if defined(CONFIG_ALPHA_NORITAKE)
+	  /* note inverted sense of mask bits: */
+	case 16 ... 31:
+	  outw(~(mask >> 16), 0x54a);
+	  break;
+	case 32 ... 47:
+	  outw(~(mask >> 32), 0x54c);
+	  break;
+#endif /* NORITAKE */
+
+#if defined(CONFIG_ALPHA_MIATA)
+	case 16 ... 47:
+	  { unsigned long temp;
+	  /* note inverted sense of mask bits: */
+	  /* make CERTAIN none of the bogus ints get enabled */
+	  *(unsigned long *)PYXIS_INT_MASK =
+	    ~((long)mask >> 16) & ~0x400000000000063bUL; mb();
+	  temp = *(unsigned long *)PYXIS_INT_MASK;
+	  break;
+	  }
+#endif /* MIATA */
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+	case 16 ... 47:
+	  { unsigned long temp;
+	  /* note inverted sense of mask bits: */
+	  /* make CERTAIN none of the bogus ints get enabled */
+	  *(unsigned long *)PYXIS_INT_MASK =
+	    ~((long)mask >> 16) & 0x00000000ffffffbfUL; mb();
+	  temp = *(unsigned long *)PYXIS_INT_MASK;
+	  break;
+	  }
+#endif /* RUFFIAN */
+
+#if defined(CONFIG_ALPHA_SX164)
+	case 16 ... 39:
+#if defined(CONFIG_ALPHA_SRM)
+	  cserve_update_hw(irq, mask);
+	  break;
+#else
+	  { unsigned long temp;
+	  /* make CERTAIN none of the bogus ints get enabled */
+	  *(unsigned long *)PYXIS_INT_MASK =
+	      ~((long)mask >> 16) & ~0x000000000000003bUL; mb();
+	  temp = *(unsigned long *)PYXIS_INT_MASK;
+	  break;
+	  }
+#endif /* SRM */
+#endif /* SX164 */
+
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+	case 16 ... 47:
 		/* note inverted sense of mask bits: */
 		*(unsigned int *)GRU_INT_MASK = ~(mask >> 16); mb();
 		break;
+#endif /* ALCOR || XLT */
 
-#elif NR_IRQS == 33
-	      default:
-		outl(mask >> 16, 0x804);
+#if defined(CONFIG_ALPHA_CABRIOLET) || \
+    defined(CONFIG_ALPHA_EB66P)     || \
+    defined(CONFIG_ALPHA_EB164)     || \
+    defined(CONFIG_ALPHA_PC164)     || \
+    defined(CONFIG_ALPHA_LX164)
+#if defined(CONFIG_ALPHA_SRM)
+      case 16 ... 34:
+	cserve_update_hw(irq, mask);
+        break;
+#else /* SRM */
+      case 16 ... 34:
+	outl(irq_mask >> 16, 0x804);
 		break;
+#endif /* SRM */
+#endif /* CABRIO || EB66P || EB164 || PC164 || LX164 */
 
-#elif defined(CONFIG_ALPHA_MIKASA)
-	      default:
+#if defined(CONFIG_ALPHA_MIKASA)
+	case 16 ... 31:
 		outw(~(mask >> 16), 0x536); /* note invert */
 		break;
+#endif /* MIKASA */
 
-#elif NR_IRQS == 32
+#if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 	      case 16 ... 23:
 		outb(mask >> 16, 0x26);
 		break;
-
-	      default:
+	case 24 ... 31:
 		outb(mask >> 24, 0x27);
 		break;
-#endif
+#endif /* EB66 || EB64P */
+
 		/* handle ISA irqs last---fast devices belong on PCI... */
+	/* this is common for all except SABLE! */
 
 	      case  0 ... 7:	/* ISA PIC1 */
 		outb(mask, 0x21);
@@ -99,7 +210,10 @@
 	      case  8 ...15:	/* ISA PIC2 */
 		outb(mask >> 8, 0xA1);
 		break;
-	}
+
+#endif /* SABLE */
+
+	} /* end switch (irq) */
 }
 
 static inline void mask_irq(unsigned long irq)
@@ -120,7 +234,7 @@
 
 	save_flags(flags);
 	cli();
-	mask_irq(irq_nr);
+	mask_irq(IRQ_TO_MASK(irq_nr));
 	restore_flags(flags);
 }
 
@@ -130,7 +244,7 @@
 
 	save_flags(flags);
 	cli();
-	unmask_irq(irq_nr);
+	unmask_irq(IRQ_TO_MASK(irq_nr));
 	restore_flags(flags);
 }
 
@@ -164,7 +278,32 @@
 
 static inline void ack_irq(int irq)
 {
+#ifdef CONFIG_ALPHA_SABLE
+  /* note that the "irq" here is really the mask bit number */
+	switch (irq) {
+	case 0 ... 7:
+	  outb(0xE0 | (irq - 0), 0x536);
+	  outb(0xE0 | 1, 0x534); /* slave 0 */
+	  break;
+	case 8 ... 15:
+	  outb(0xE0 | (irq - 8), 0x53a);
+	  outb(0xE0 | 3, 0x534); /* slave 1 */
+	  break;
+	case 16 ... 24:
+	  outb(0xE0 | (irq - 16), 0x53c);
+	  outb(0xE0 | 4, 0x534); /* slave 2 */
+	  break;
+	}
+#else /* CONFIG_ALPHA_SABLE */
 	if (irq < 16) {
+#if defined(CONFIG_ALPHA_RUFFIAN)
+		/* ack pyxis ISA interrupt */
+		*(unsigned long *)PYXIS_INT_REQ = (0x01UL << 7);
+		if (irq > 7) {
+			outb(0x20,0xa0);
+		}
+		outb(0x20,0x20);
+#else /* RUFFIAN */
 		/* ACK the interrupt making it the lowest priority */
 		/*  First the slave .. */
 		if (irq > 7) {
@@ -178,7 +317,16 @@
 		*(int *)GRU_INT_CLEAR = 0x80000000; mb();
 		*(int *)GRU_INT_CLEAR = 0x00000000; mb();
 #endif /* ALCOR || XLT */
+#endif /* RUFFIAN */  
 	}
+#if defined(CONFIG_ALPHA_RUFFIAN)
+        else {
+	  /* ack pyxis int */
+	  *(unsigned long *)PYXIS_INT_REQ = (1UL << (irq-16));
+        }
+#endif /* RUFFIAN */        
+
+#endif /* CONFIG_ALPHA_SABLE */
 }
 
 int request_irq(unsigned int irq, 
@@ -236,7 +384,7 @@
 	*p = action;
 
 	if (!shared)
-		unmask_irq(irq);
+		unmask_irq(IRQ_TO_MASK(irq));
 
 	restore_flags(flags);
 	return 0;
@@ -264,7 +412,7 @@
 		cli();
 		*p = action->next;
 		if (!irq[irq_action])
-			mask_irq(irq);
+			mask_irq(IRQ_TO_MASK(irq));
 		restore_flags(flags);
 		kfree(action);
 		return;
@@ -323,25 +471,39 @@
 	struct irqaction * action;
 
 	if ((unsigned) irq > NR_IRQS) {
-		printk("device_interrupt: unexpected interrupt %d\n", irq);
+		printk("device_interrupt: illegal interrupt %d\n", irq);
+		return;
+	}
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+	/* RUFFIAN uses ISA IRQ #0 to deliver clock ticks */
+	if (irq == 0) {
+		timer_interrupt(regs);
+		ack_irq(0);
 		return;
 	}
+#endif /* RUFFIAN */
 
 	kstat.interrupts[irq]++;
 	action = irq_action[irq];
+
 	/*
 	 * For normal interrupts, we mask it out, and then ACK it.
 	 * This way another (more timing-critical) interrupt can
 	 * come through while we're doing this one.
 	 *
-	 * Note! A irq without a handler gets masked and acked, but
+	 * Note! An irq without a handler gets masked and acked, but
 	 * never unmasked. The autoirq stuff depends on this (it looks
 	 * at the masks before and after doing the probing).
 	 */
 	mask_irq(ack);
 	ack_irq(ack);
-	if (!action)
+	if (!action) {
+#if 1
+		printk("device_interrupt: unexpected interrupt %d\n", irq);
+#endif
 		return;
+	}
 	if (action->flags & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
 	do {
@@ -365,6 +527,8 @@
 #	define IACK_SC	LCA_IACK_SC
 #elif defined(CONFIG_ALPHA_CIA)
 #	define IACK_SC	CIA_IACK_SC
+#elif defined(CONFIG_ALPHA_PYXIS)
+#	define IACK_SC	PYXIS_IACK_SC
 #else
 	/*
 	 * This is bogus but necessary to get it to compile
@@ -554,8 +718,185 @@
 	restore_flags(flags);
 }
 
+#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+/* we have to conditionally compile this because of PYXIS_xxx symbols */
+static inline void miata_device_interrupt(unsigned long vector,
+                                                  struct pt_regs * regs)
+{
+        unsigned long pld, tmp;
+        unsigned int i;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+
+        /* read the interrupt summary register of PYXIS */
+        pld = (*(volatile unsigned long *)PYXIS_INT_REQ);
+
+#if 0
+        printk("[0x%08lx/0x%08lx/0x%04x]", pld,
+	       *(volatile unsigned long *)PYXIS_INT_MASK,
+	       inb(0x20) | (inb(0xA0) << 8));
+#endif
+
+#ifdef CONFIG_ALPHA_MIATA
+	/* for now, AND off any bits we are not interested in: */
+	/*  HALT (2), timer (6), ISA Bridge (7), 21142 (8) */
+	/*  then all the PCI slots/INTXs (12-31) */
+/* maybe HALT should only be used for SRM console boots? */
+	pld &= 0x00000000fffff9c4UL;
+#endif /* MIATA */
+#ifdef CONFIG_ALPHA_SX164
+	/* for now, AND off any bits we are not interested in: */
+	/*  HALT (2), timer (6), ISA Bridge (7) */
+	/*  then all the PCI slots/INTXs (8-23) */
+/* HALT should only be used for SRM console boots */
+	pld &= 0x0000000000ffffc0UL;
+#endif /* SX164 */
+
+        /*
+         * Now for every possible bit set, work through them and call
+         * the appropriate interrupt handler.
+         */
+        while (pld) {
+                i = ffz(~pld);
+                pld &= pld - 1; /* clear least bit set */
+                if (i == 7) {
+                        isa_device_interrupt(vector, regs);
+		} else if (i == 6)
+			continue;
+                else { /* if not timer int */
+                        device_interrupt(16 + i, 16 + i, regs);
+                }
+		*(unsigned long *)PYXIS_INT_REQ = 1UL << i; mb();
+		tmp = *(volatile unsigned long *)PYXIS_INT_REQ;
+        }
+        restore_flags(flags);
+}
+#endif /* MIATA || SX164 */
+
+static inline void noritake_device_interrupt(unsigned long vector,
+                                                  struct pt_regs * regs)
+{
+        unsigned long pld;
+        unsigned int i;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+
+        /* read the interrupt summary registers */
+        /* read the interrupt summary registers of NORITAKE */
+        pld = ((unsigned long) inw(0x544) << 32) |
+	      ((unsigned long) inw(0x542) << 16) |
+	      ((unsigned long) inb(0xa0)  <<  8) |
+	      ((unsigned long) inb(0x20));
+
+#if 0
+        printk("[0x%08lx]", pld);
+#endif
+
+        /*
+         * Now for every possible bit set, work through them and call
+         * the appropriate interrupt handler.
+         */
+        while (pld) {
+		i = ffz(~pld);
+		pld &= pld - 1; /* clear least bit set */
+		if (i < 16) {
+			isa_device_interrupt(vector, regs);
+		} else {
+			device_interrupt(i, i, regs);
+		}
+        }
+        restore_flags(flags);
+}
+
 #endif /* CONFIG_PCI */
 
+#if defined(CONFIG_ALPHA_RUFFIAN)
+static inline void ruffian_device_interrupt(unsigned long vector,
+					    struct pt_regs * regs)
+
+{
+	unsigned long pld, tmp;
+        unsigned int i;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+
+        /* read the interrupt summary register of PYXIS */
+        pld = (*(volatile unsigned long *)PYXIS_INT_REQ);
+
+        /* for now, AND off any bits we are not interested in:
+         *  HALT (2), timer (6), ISA Bridge (7), 21142 (8)
+         *  then all the PCI slots/INTXs (12-31) 
+         *  flash(5) :DWH:
+         */
+        pld &= 0x00000000ffffff9fUL;/* was ffff7f */
+
+        /*
+         * Now for every possible bit set, work through them and call
+         * the appropriate interrupt handler.
+         */
+
+        while (pld) {
+		i = ffz(~pld);
+                pld &= pld - 1; /* clear least bit set */
+                if (i == 7) {
+			isa_device_interrupt(vector, regs);
+                } else { /* if not timer int */
+			device_interrupt(16 + i,16 + i,regs);
+                }
+                *(unsigned long *)PYXIS_INT_REQ = 1UL << i; mb();
+                tmp = *(volatile unsigned long *)PYXIS_INT_REQ;
+        }
+        restore_flags(flags);
+}
+#endif /* RUFFIAN */
+
+static inline void takara_device_interrupt(unsigned long vector,
+					   struct pt_regs * regs)
+{
+	unsigned long flags;
+	unsigned intstatus;
+
+	save_flags(flags);
+	cli();
+
+	/*
+	 * The PALcode will have passed us vectors 0x800 or 0x810,
+	 * which are fairly arbitrary values and serve only to tell
+	 * us whether an interrupt has come in on IRQ0 or IRQ1. If
+	 * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's
+	 * probably ISA, but PCI interrupts can come through IRQ0
+	 * as well if the interrupt controller isn't in accelerated
+	 * mode.
+	 *
+	 * OTOH, the accelerator thing doesn't seem to be working
+	 * overly well, so what we'll do instead is try directly
+	 * examining the Master Interrupt Register to see if it's a
+	 * PCI interrupt, and if _not_ then we'll pass it on to the
+	 * ISA handler.
+	 */
+
+	intstatus = inw(0x500) & 15;
+	if (intstatus) {
+		/*
+		 * This is a PCI interrupt. Check each bit and
+		 * despatch an interrupt if it's set.
+		 */
+		if (intstatus & 8) device_interrupt(16+3, 16+3, regs);
+		if (intstatus & 4) device_interrupt(16+2, 16+2, regs);
+		if (intstatus & 2) device_interrupt(16+1, 16+1, regs);
+		if (intstatus & 1) device_interrupt(16+0, 16+0, regs);
+	} else
+		isa_device_interrupt (vector, regs);
+
+	restore_flags(flags);
+}
+
 /*
  * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
  * 0x9X0 for the local motherboard interrupts..
@@ -587,6 +928,9 @@
 	save_flags(flags);
 	cli();
 
+#if 0
+printk("srm_device_interrupt: vector 0x%lx\n", vector);
+#endif
 
 	ack = irq = (vector - 0x800) >> 4;
 
@@ -608,11 +952,69 @@
 		irq = 7;
 #endif /* CONFIG_ALPHA_JENSEN */
 
+#ifdef CONFIG_ALPHA_MIATA
+        /*
+         * I really hate to do this, but the MIATA SRM console ignores the
+         *  low 8 bits in the interrupt summary register, and reports the
+         *  vector 0x80 *lower* than I expected from the bit numbering in
+         *  the documentation.
+         * This was done because the low 8 summary bits really aren't used
+         *  for reporting any interrupts (the PCI-ISA bridge, bit 7, isn't
+         *  used for this purpose, as PIC interrupts are delivered as the
+         *  vectors 0x800-0x8f0).
+         * But I really don't want to change the fixup code for allocation
+         *  of IRQs, nor the irq_mask maintenance stuff, both of which look
+         *  nice and clean now.
+         * So, here's this grotty hack... :-(
+         */
+        if (irq >= 16)
+		ack = irq = irq + 8;
+#endif /* CONFIG_ALPHA_MIATA */
+
+#ifdef CONFIG_ALPHA_NORITAKE
+        /*
+         * I really hate to do this, but the NORITAKE SRM console reports
+         *  PCI vectors *lower* than I expected from the bit numbering in
+         *  the documentation.
+         * But I really don't want to change the fixup code for allocation
+         *  of IRQs, nor the irq_mask maintenance stuff, both of which look
+         *  nice and clean now.
+         * So, here's this grotty hack... :-(
+         */
+        if (irq >= 16)
+		ack = irq = irq + 1;
+#endif /* CONFIG_ALPHA_NORITAKE */
+
+#ifdef CONFIG_ALPHA_SABLE
+	irq = sable_mask_to_irq[(ack)];
+#if 0
+	if (irq == 5 || irq == 9 || irq == 10 || irq == 11 ||
+	    irq == 14 || irq == 15)
+	printk("srm_device_interrupt: vector=0x%lx  ack=0x%x  irq=0x%x\n",
+	       vector, ack, irq);
+#endif
+#endif /* CONFIG_ALPHA_SABLE */
+
 	device_interrupt(irq, ack, regs);
 
 	restore_flags(flags) ;
 }
 
+/* PROBE_MASK is the bitset of irqs that we consider for autoprobing: */
+#if defined(CONFIG_ALPHA_P2K)
+  /* always mask out unused timer irq 0 and RTC irq 8 */
+# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0x101UL)
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+  /* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */
+# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL)
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+  /* must leave timer irq 0 in the mask */
+# define PROBE_MASK ((1UL << NR_IRQS) - 1)
+#else
+  /* always mask out unused timer irq 0: */
+# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL)
+#endif
+
 /*
  * Start listening for interrupts..
  */
@@ -624,10 +1026,13 @@
 	unsigned int i;
 
 	for (i = NR_IRQS - 1; i > 0; i--) {
+		if (!(PROBE_MASK & (1UL << i))) {
+			continue;
+                }
 		action = irq_action[i];
 		if (!action) {
 			enable_irq(i);
-			irqs |= (1 << i);
+			irqs |= (1UL << i);
 		}
 	}
 	/*
@@ -650,10 +1055,7 @@
 {
 	int i;
 	
-	irqs &= irq_mask & ~1;	/* always mask out irq 0---it's the unused timer */
-#ifdef CONFIG_ALPHA_P2K
-	irqs &= ~(1 << 8);	/* mask out irq 8 since that's the unused RTC input to PIC */
-#endif
+	irqs &= irq_mask;
 	if (!irqs)
 		return 0;
 	i = ffz(~irqs);
@@ -676,6 +1078,14 @@
 	extern void cia_machine_check(unsigned long vector, unsigned long la,
 					struct pt_regs * regs);
 	cia_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_PYXIS)
+	extern void pyxis_machine_check(unsigned long vector, unsigned long la,
+					struct pt_regs * regs);
+	pyxis_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_T2)
+	extern void t2_machine_check(unsigned long vector, unsigned long la,
+				     struct pt_regs * regs);
+	t2_machine_check(vector, la, regs);
 #else
 	printk("Machine check\n");
 #endif
@@ -685,6 +1095,9 @@
 	unsigned long a3, unsigned long a4, unsigned long a5,
 	struct pt_regs regs)
 {
+#if 0
+printk("do_entInt: type 0x%lx\n", type);
+#endif
 	switch (type) {
 		case 0:
 			printk("Interprocessor interrupt? You must be kidding\n");
@@ -699,17 +1112,30 @@
 #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
     defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM)
 			srm_device_interrupt(vector, &regs);
-#elif NR_IRQS == 48
+#else /* everyone else */
+
+#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+			miata_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_NORITAKE)
+			noritake_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
 			alcor_and_xlt_device_interrupt(vector, &regs);
-#elif NR_IRQS == 33
+#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \
+      defined(CONFIG_ALPHA_EB164)     || defined(CONFIG_ALPHA_PC164) || \
+      defined(CONFIG_ALPHA_LX164)
 			cabriolet_and_eb66p_device_interrupt(vector, &regs);
 #elif defined(CONFIG_ALPHA_MIKASA)
 			mikasa_device_interrupt(vector, &regs);
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 			eb66_and_eb64p_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+                        ruffian_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_TAKARA)
+			takara_device_interrupt(vector, &regs);
 #elif NR_IRQS == 16
 			isa_device_interrupt(vector, &regs);
 #endif
+#endif /* everyone else */
 			return;
 		case 4:
 			printk("Performance counter interrupt\n");
@@ -724,23 +1150,141 @@
 
 void init_IRQ(void)
 {
+	unsigned int temp;
+
 	wrent(entInt, 0);
-	dma_outb(0, DMA1_RESET_REG);
-	dma_outb(0, DMA2_RESET_REG);
-	dma_outb(0, DMA1_CLR_MASK_REG);
-	dma_outb(0, DMA2_CLR_MASK_REG);
-#if NR_IRQS == 48
+
+	outb(0, DMA1_RESET_REG);
+	outb(0, DMA2_RESET_REG);
+
+/* FIXME FIXME FIXME FIXME FIXME */
+#if !defined(CONFIG_ALPHA_SX164)
+	outb(0, DMA1_CLR_MASK_REG);
+	/* we need to figure out why this fails on the SX164 */
+	outb(0, DMA2_CLR_MASK_REG);
+#endif /* !SX164 */
+/* end FIXMEs */
+
+#if defined(CONFIG_ALPHA_SABLE)
+	outb(irq_mask      , 0x537); /* slave 0 */
+	outb(irq_mask >>  8, 0x53b); /* slave 1 */
+	outb(irq_mask >> 16, 0x53d); /* slave 2 */
+	outb(0x44, 0x535);	/* enable cascades in master */
+#else /* everybody but SABLE */
+
+#if defined(CONFIG_ALPHA_MIATA)
+	/* note invert on MASK bits */
+        *(unsigned long *)PYXIS_INT_MASK  =
+	  ~((long)irq_mask >> 16) & ~0x400000000000063bUL; mb();
+#if 0
+	/* these break on MiataGL so we'll try not to do it at all */
+        *(unsigned long *)PYXIS_INT_HILO  = 0x000000B2UL; mb();/* ISA/NMI HI */
+        *(unsigned long *)PYXIS_RT_COUNT  = 0UL; mb();/* clear count */
+#endif
+	/* clear upper timer */
+        *(unsigned long *)PYXIS_INT_REQ  = 0x4000000000000180UL; mb();
+
+	/* Send -INTA pulses to clear any pending interrupts ...*/
+	temp = *(volatile unsigned int *) IACK_SC;
+
+	enable_irq(16 + 2);	/* enable HALT switch - SRM only? */
+        enable_irq(16 + 6);     /* enable timer */
+        enable_irq(16 + 7);     /* enable ISA PIC cascade */
+#endif /* MIATA */
+
+#if defined(CONFIG_ALPHA_SX164)
+#if !defined(CONFIG_ALPHA_SRM)
+	/* note invert on MASK bits */
+        *(unsigned long *)PYXIS_INT_MASK  = ~((long)irq_mask >> 16); mb();
+#if 0
+        *(unsigned long *)PYXIS_INT_HILO  = 0x000000B2UL; mb();/* ISA/NMI HI */
+        *(unsigned long *)PYXIS_RT_COUNT  = 0UL; mb();/* clear count */
+#endif
+#endif /* !SRM */
+        enable_irq(16 + 6);     /* enable timer */
+        enable_irq(16 + 7);     /* enable ISA PIC cascade */
+#endif /* SX164 */
+
+#if defined(CONFIG_ALPHA_NORITAKE)
+	outw(~(irq_mask >> 16), 0x54a); /* note invert */
+	outw(~(irq_mask >> 32), 0x54c); /* note invert */
+#endif /* NORITAKE */
+
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
 	*(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16); mb();/* invert */
+	*(unsigned int *)GRU_INT_EDGE  = 0UL; mb();/* all are level */
+	*(unsigned int *)GRU_INT_HILO  = 0x80000000UL; mb();/* ISA only HI */
+	*(unsigned int *)GRU_INT_CLEAR = 0UL; mb();/* all clear */
 	enable_irq(16 + 31);	/* enable (E)ISA PIC cascade */
-#elif NR_IRQS == 33
+#endif /* ALCOR || XLT */
+
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \
+    defined(CONFIG_ALPHA_PC164)     || defined(CONFIG_ALPHA_LX164) || \
+    defined(CONFIG_ALPHA_EB164)
+#if !defined(CONFIG_ALPHA_SRM)
 	outl(irq_mask >> 16, 0x804);
+#endif /* !SRM */
+	/* Send -INTA pulses to clear any pending interrupts ...*/
+	temp = *(volatile unsigned int *) IACK_SC;
 	enable_irq(16 +  4);	/* enable SIO cascade */
-#elif defined(CONFIG_ALPHA_MIKASA)
+#endif /* CABRIO || EB66P || PC164 || LX164 || EB164 */
+
+#if defined(CONFIG_ALPHA_MIKASA)
 	outw(~(irq_mask >> 16), 0x536); /* note invert */
-#elif NR_IRQS == 32
+#endif /* MIKASA */
+
+#if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 	outb(irq_mask >> 16, 0x26);
 	outb(irq_mask >> 24, 0x27);
 	enable_irq(16 +  5);	/* enable SIO cascade */
-#endif
-	enable_irq(2);		/* enable cascade */
+#endif /* EB66 || EB64P */
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+	/* invert 6&7 for i82371 */
+	*(unsigned long *)PYXIS_INT_HILO  = 0x000000c0UL;mb();
+	*(unsigned long *)PYXIS_INT_CNFG  = 0x00002064UL;mb();   /* all clear */
+	*(unsigned long *)PYXIS_INT_MASK  = ((long)0x00000000UL);mb();
+	*(unsigned long *)PYXIS_INT_REQ   = 0xffffffffUL;mb();
+
+	outb(0x11,0xA0);
+	outb(0x08,0xA1);
+	outb(0x02,0xA1);
+	outb(0x01,0xA1);
+	outb(0xFF,0xA1);
+	
+	outb(0x11,0x20);
+	outb(0x00,0x21);
+	outb(0x04,0x21);
+	outb(0x01,0x21);
+	outb(0xFF,0x21);
+	
+	/* Send -INTA pulses to clear any pending interrupts ...*/
+	temp = *(volatile unsigned int *) IACK_SC;
+	
+	/* Finish writing the 82C59A PIC Operation Control Words */
+	outb(0x20,0xA0);
+	outb(0x20,0x20);
+	
+	/* Turn on the interrupt controller, the timer interrupt  */
+	enable_irq(16 + 7);     /* enable ISA PIC cascade */
+	enable_irq(0);          /* enable timer */
+#endif /* RUFFIAN */
+
+#ifdef CONFIG_ALPHA_TAKARA
+	{
+		unsigned int ctlreg = inl(0x500);
+		ctlreg &= ~0x8000;     /* return to non-accelerated mode */
+		outw(ctlreg >> 16, 0x502);
+		outw(ctlreg & 0xFFFF, 0x500);
+		ctlreg = 0x05107c00;   /* enable the PCI interrupt register */
+		printk("Setting to 0x%08x\n", ctlreg);
+		outw(ctlreg >> 16, 0x502);
+		outw(ctlreg & 0xFFFF, 0x500);
+	}
+#endif /* TAKARA */
+
+	/* and finally, everyone but SABLE does this */
+	enable_irq(2);		/* enable 2nd PIC cascade */
+
+#endif /* SABLE */
 }
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/lca.c linux/arch/alpha/kernel/lca.c
--- v2.0.33/linux/arch/alpha/kernel/lca.c	Sun Jul 14 23:47:41 1996
+++ linux/arch/alpha/kernel/lca.c	Wed Jun  3 15:17:46 1998
@@ -22,6 +22,7 @@
 #ifdef CONFIG_ALPHA_LCA
 
 #define vulp	volatile unsigned long *
+#define vuip	volatile unsigned int  *
 
 /*
  * Machine check reasons.  Defined according to PALcode sources
@@ -46,6 +47,11 @@
 #define MCHK_K_SIO_IOCHK	0x206	/* all platforms so far */
 #define MCHK_K_DCSR		0x208	/* all but Noname */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int LCA_DMA_WIN_BASE = LCA_DMA_WIN_BASE_DEFAULT;
+unsigned int LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT;
+#endif /* SRM_SETUP */
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address and setup the LCA_IOC_CONF register
@@ -289,6 +295,40 @@
 
 unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
 {
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	/* check window 0 for enabled and mapped to 0 */
+	if ((*(vulp)LCA_IOC_W_BASE0 & (1UL<<33)) &&
+	    (*(vulp)LCA_IOC_T_BASE0 == 0))
+	{
+	  LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE0 & 0xffffffffUL;
+	  LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK0 & 0xffffffffUL;
+	  LCA_DMA_WIN_SIZE += 1;
+#if 1
+	  printk("lca_init: using Window 0 settings\n");
+	  printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+		 *(vulp)LCA_IOC_W_BASE0,
+		 *(vulp)LCA_IOC_W_MASK0,
+		 *(vulp)LCA_IOC_T_BASE0);
+#endif
+	}
+	else	/* check window 2 for enabled and mapped to 0 */
+	if ((*(vulp)LCA_IOC_W_BASE1 & (1UL<<33)) &&
+	    (*(vulp)LCA_IOC_T_BASE1 == 0))
+	{
+	  LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE1 & 0xffffffffUL;
+	  LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK1 & 0xffffffffUL;
+	  LCA_DMA_WIN_SIZE += 1;
+#if 1
+	  printk("lca_init: using Window 1 settings\n");
+	  printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+		 *(vulp)LCA_IOC_W_BASE1,
+		 *(vulp)LCA_IOC_W_MASK1,
+		 *(vulp)LCA_IOC_T_BASE1);
+#endif
+	}
+	else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+	{
 	/*
 	 * Set up the PCI->physical memory translation windows.
 	 * For now, window 1 is disabled.  In the future, we may
@@ -296,9 +336,11 @@
 	 * goes at 1 GB and is 1 GB large.
 	 */
 	*(vulp)LCA_IOC_W_BASE1 = 0UL<<33;
+
 	*(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE;
 	*(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1;
 	*(vulp)LCA_IOC_T_BASE0 = 0;
+	}
 
 	/*
 	 * Disable PCI parity for now.  The NCR53c810 chip has
@@ -386,11 +428,14 @@
 
 void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs)
 {
+	unsigned long * ptr;
 	const char * reason;
 	union el_lca el;
 	char buf[128];
+	long i;
 
-	printk("lca: machine check (la=0x%lx,pc=0x%lx)\n", la, regs->pc);
+	printk(KERN_CRIT "lca: machine check (la=0x%lx,pc=0x%lx)\n",
+	       la, regs->pc);
 	el.c = (struct el_common *) la;
 	/*
 	 * The first quadword after the common header always seems to
@@ -399,9 +444,9 @@
 	 * logout frame, the upper 32 bits is the machine check
 	 * revision level, which we ignore for now.
 	 */
-	switch (el.s->reason & 0xffffffff) {
+	switch (el.c->code & 0xffffffff) {
 	      case MCHK_K_TPERR:	reason = "tag parity error"; break;
-	      case MCHK_K_TCPERR:	reason = "tag something parity error"; break;
+	      case MCHK_K_TCPERR:	reason = "tag control parity error"; break;
 	      case MCHK_K_HERR:		reason = "access to non-existent memory"; break;
 	      case MCHK_K_ECC_C:	reason = "correctable ECC error"; break;
 	      case MCHK_K_ECC_NC:	reason = "non-correctable ECC error"; break;
@@ -416,7 +461,7 @@
 	      case MCHK_K_UNKNOWN:
 	      default:
 		sprintf(buf, "reason for machine-check unknown (0x%lx)",
-			el.s->reason & 0xffffffff);
+			el.c->code & 0xffffffff);
 		reason = buf;
 		break;
 	}
@@ -425,7 +470,8 @@
 
 	switch (el.c->size) {
 	      case sizeof(struct el_lca_mcheck_short):
-		printk("  Reason: %s (short frame%s, dc_stat=%lx):\n",
+		printk(KERN_CRIT
+		       "  Reason: %s (short frame%s, dc_stat=%lx):\pn",
 		       reason, el.c->retry ? ", retryable" : "", el.s->dc_stat);
 		if (el.s->esr & ESR_EAV) {
 		    mem_error(el.s->esr, el.s->ear);
@@ -436,11 +482,12 @@
 		break;
 
 	      case sizeof(struct el_lca_mcheck_long):
-		printk("  Reason: %s (long frame%s):\n",
+		printk(KERN_CRIT "  Reason: %s (long frame%s):\n",
 		       reason, el.c->retry ? ", retryable" : "");
-		printk("    reason: %lx  exc_addr: %lx  dc_stat: %lx\n", 
+		printk(KERN_CRIT
+		       "    reason: %lx  exc_addr: %lx  dc_stat: %lx\n", 
 		       el.l->pt[0], el.l->exc_addr, el.l->dc_stat);
-		printk("    car: %lx\n", el.l->car);
+		printk(KERN_CRIT "    car: %lx\n", el.l->car);
 		if (el.l->esr & ESR_EAV) {
 		    mem_error(el.l->esr, el.l->ear);
 		}
@@ -450,8 +497,55 @@
 		break;
 
 	      default:
-		printk("  Unknown errorlog size %d\n", el.c->size);
+		printk(KERN_CRIT "  Unknown errorlog size %d\n", el.c->size);
+	}
+
+	/* dump the logout area to give all info: */
+
+	ptr = (unsigned long *) la;
+	for (i = 0; i < el.c->size / sizeof(long); i += 2) {
+	    printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+		   i*sizeof(long), ptr[i], ptr[i+1]);
 	}
+}
+
+void
+lca_clock_print(void)
+{
+        long    pmr_reg;
+
+        pmr_reg = READ_PMR;
+
+        printk("Status of clock control:\n");
+        printk("\tPrimary clock divisor\t0x%x\n", GET_PRIMARY(pmr_reg));
+        printk("\tOverride clock divisor\t0x%x\n", GET_OVERRIDE(pmr_reg));
+        printk("\tInterrupt override is %s\n",
+	       (pmr_reg & LCA_PMR_INTO) ? "on" : "off"); 
+        printk("\tDMA override is %s\n",
+	       (pmr_reg & LCA_PMR_DMAO) ? "on" : "off"); 
+
+}
+
+int
+lca_get_clock(void)
+{
+        long    pmr_reg;
+
+        pmr_reg = READ_PMR;
+        return(GET_PRIMARY(pmr_reg));
+
+	}
+
+void
+lca_clock_fiddle(int divisor)
+{
+        long    pmr_reg;
+
+        pmr_reg = READ_PMR;
+        SET_PRIMARY_CLOCK(pmr_reg, divisor);
+/*        lca_norm_clock = divisor; */
+        WRITE_PMR(pmr_reg);
+        mb();
 }
 
 #endif /* CONFIG_ALPHA_LCA */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.0.33/linux/arch/alpha/kernel/process.c	Tue Aug 20 23:18:07 1996
+++ linux/arch/alpha/kernel/process.c	Wed Jun  3 15:17:46 1998
@@ -32,8 +32,9 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
-	unsigned long a3, unsigned long a4, unsigned long a5,
+asmlinkage int sys_sethae(unsigned long hae, unsigned long a1,
+			  unsigned long a2, unsigned long a3,
+			  unsigned long a4, unsigned long a5,
 	struct pt_regs regs)
 {
 	(&regs)->hae = hae;
@@ -52,8 +53,42 @@
 	}
 }
 
+#include <asm/hwrpb.h>
+
+static void swap_context(struct thread_struct * pcb)
+{
+        __asm__ __volatile__(
+                "bis %0,%0,$16\n\t"
+                "call_pal %1\n\t"
+                : /* no outputs */
+                : "r" (pcb), "i" (PAL_swpctx)
+                : "$0", "$1", "$16", "$22", "$23", "$24", "$25");
+}
+
 void hard_reset_now(void)
 {
+#if defined(CONFIG_ALPHA_SRM_SETUP)
+	extern void reset_for_srm(void);	
+	extern struct hwrpb_struct *hwrpb;
+	extern struct thread_struct *original_pcb_ptr;
+	struct percpu_struct *cpup;
+	unsigned long flags;
+
+	cpup = (struct percpu_struct *)
+	  ((unsigned long)hwrpb + hwrpb->processor_offset);
+	flags = cpup->flags;
+#if 1
+	printk("hard_reset_now: flags 0x%lx\n", flags);
+#endif
+	flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */
+	flags |=  0x0000000000020000UL; /* this is "cold bootstrap" */
+/*	flags |=  0x0000000000030000UL; *//* this is "warm bootstrap" */
+/*	flags |=  0x0000000000040000UL; *//* this is "remain halted" */
+	cpup->flags = flags;
+	mb();
+	reset_for_srm();
+	swap_context(original_pcb_ptr);
+#endif
 #if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR)
 	/* who said DEC engineer's have no sense of humor? ;-)) */
 	*(int *) GRU_RESET = 0x0000dead;
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/pyxis.c linux/arch/alpha/kernel/pyxis.c
--- v2.0.33/linux/arch/alpha/kernel/pyxis.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/kernel/pyxis.c	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,670 @@
+/*
+ * Code common to all PYXIS chips.
+ *
+ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef CONFIG_ALPHA_PYXIS
+
+#ifdef DEBUG 
+# define DBG(args)	printk args
+#else
+# define DBG(args)
+#endif
+
+#define DEBUG_MCHECK
+#ifdef DEBUG_MCHECK
+# define DBG_MCK(args)	printk args
+/* #define DEBUG_MCHECK_DUMP */
+#else
+# define DBG_MCK(args)
+#endif
+
+#define vuip	volatile unsigned int  *
+#define vulp	volatile unsigned long  *
+
+static volatile unsigned int PYXIS_mcheck_expected = 0;
+static volatile unsigned int PYXIS_mcheck_taken = 0;
+static unsigned int PYXIS_jd;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int PYXIS_DMA_WIN_BASE = PYXIS_DMA_WIN_BASE_DEFAULT;
+unsigned int PYXIS_DMA_WIN_SIZE = PYXIS_DMA_WIN_SIZE_DEFAULT;
+unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3;
+#endif /* SRM_SETUP */
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the PYXIS_HAXR2 register
+ * accordingly.  It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:11	Device select bit.
+ * 	10:8	Function number
+ * 	 7:2	Register number
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:24	reserved
+ *	23:16	bus number (8 bits = 128 possible buses)
+ *	15:11	Device number (5 bits)
+ *	10:8	function number
+ *	 7:2	register number
+ *  
+ * Notes:
+ *	The function number selects which function of a multi-function device 
+ *	(e.g., scsi and ethernet).
+ * 
+ *	The register selects a DWORD (32 bit) register offset.  Hence it
+ *	doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ *	bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+			unsigned char where, unsigned long *pci_addr,
+			unsigned char *type1)
+{
+	unsigned long addr;
+
+	DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
+	     bus, device_fn, where, pci_addr, type1));
+
+	if (bus == 0) {
+		int device;
+
+		device = device_fn >> 3;
+		/* type 0 configuration cycle: */
+#if NOT_NOW
+		if (device > 20) {
+			DBG(("mk_conf_addr: device (%d) > 20, returning -1\n",
+			     device));
+			return -1;
+		}
+#endif
+		*type1 = 0;
+		addr = (device_fn << 8) | (where);
+	} else {
+		/* type 1 configuration cycle: */
+		*type1 = 1;
+		addr = (bus << 16) | (device_fn << 8) | (where);
+	}
+	*pci_addr = addr;
+	DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	return 0;
+}
+
+
+static unsigned int conf_read(unsigned long addr, unsigned char type1)
+{
+	unsigned long flags;
+	unsigned int stat0, value, temp;
+	unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
+
+	save_flags(flags);	/* avoid getting hit by machine check */
+	cli();
+
+	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+	/* reset status register to avoid losing errors: */
+	stat0 = *((vuip)PYXIS_ERR);
+	*((vuip)PYXIS_ERR) = stat0; mb();
+	temp = *((vuip)PYXIS_ERR);
+	DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0));
+	/* if Type1 access, must set PYXIS CFG */
+	if (type1) {
+		pyxis_cfg = *((vuip)PYXIS_CFG);
+		*((vuip)PYXIS_CFG) = pyxis_cfg | 1; mb();
+		temp = *((vuip)PYXIS_CFG);
+		DBG(("conf_read: TYPE1 access\n"));
+	}
+
+	mb();
+	draina();
+	PYXIS_mcheck_expected = 1;
+	PYXIS_mcheck_taken = 0;
+	mb();
+	/* access configuration space: */
+	value = *((vuip)addr);
+	mb();
+	mb();
+	if (PYXIS_mcheck_taken) {
+		PYXIS_mcheck_taken = 0;
+		value = 0xffffffffU;
+		mb();
+	}
+	PYXIS_mcheck_expected = 0;
+	mb();
+
+	/* if Type1 access, must reset IOC CFG so normal IO space ops work */
+	if (type1) {
+		*((vuip)PYXIS_CFG) = pyxis_cfg & ~1; mb();
+		temp = *((vuip)PYXIS_CFG);
+	}
+
+	DBG(("conf_read(): finished\n"));
+
+	restore_flags(flags);
+	return value;
+}
+
+
+static void conf_write(unsigned long addr, unsigned int value, unsigned char type1)
+{
+	unsigned long flags;
+	unsigned int stat0, temp;
+	unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
+
+	save_flags(flags);	/* avoid getting hit by machine check */
+	cli();
+
+	/* reset status register to avoid losing errors: */
+	stat0 = *((vuip)PYXIS_ERR);
+	*((vuip)PYXIS_ERR) = stat0; mb();
+	temp = *((vuip)PYXIS_ERR);
+	DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0));
+	/* if Type1 access, must set PYXIS CFG */
+	if (type1) {
+		pyxis_cfg = *((vuip)PYXIS_CFG);
+		*((vuip)PYXIS_CFG) = pyxis_cfg | 1; mb();
+		temp = *((vuip)PYXIS_CFG);
+		DBG(("conf_read: TYPE1 access\n"));
+	}
+
+	draina();
+	PYXIS_mcheck_expected = 1;
+	mb();
+	/* access configuration space: */
+	*((vuip)addr) = value;
+	mb();
+	mb();
+	temp = *((vuip)PYXIS_ERR); /* do a PYXIS read to force the write */
+	PYXIS_mcheck_expected = 0;
+	mb();
+
+	/* if Type1 access, must reset IOC CFG so normal IO space ops work */
+	if (type1) {
+		*((vuip)PYXIS_CFG) = pyxis_cfg & ~1; mb();
+		temp = *((vuip)PYXIS_CFG);
+	}
+
+	DBG(("conf_write(): finished\n"));
+	restore_flags(flags);
+}
+
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned char *value)
+{
+	unsigned long addr = PYXIS_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	*value = 0xff;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	addr |= (pci_addr << 5) + 0x00;
+
+	*value = conf_read(addr, type1) >> ((where & 3) * 8);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned short *value)
+{
+	unsigned long addr = PYXIS_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	*value = 0xffff;
+
+	if (where & 0x1) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	addr |= (pci_addr << 5) + 0x08;
+
+	*value = conf_read(addr, type1) >> ((where & 3) * 8);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned int *value)
+{
+	unsigned long addr = PYXIS_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	*value = 0xffffffff;
+	if (where & 0x3) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x18;
+	*value = conf_read(addr, type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned char value)
+{
+	unsigned long addr = PYXIS_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x00;
+	conf_write(addr, value << ((where & 3) * 8), type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned short value)
+{
+	unsigned long addr = PYXIS_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x08;
+	conf_write(addr, value << ((where & 3) * 8), type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+				unsigned char where, unsigned int value)
+{
+	unsigned long addr = PYXIS_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x18;
+	conf_write(addr, value << ((where & 3) * 8), type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end)
+{
+        unsigned int pyxis_err;
+
+#if 0
+printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK);
+printk("pyxis_init: PYXIS_ERR 0x%x\n", *(vuip)PYXIS_ERR);
+
+printk("pyxis_init: PYXIS_INT_REQ 0x%lx\n", *(vulp)PYXIS_INT_REQ);
+printk("pyxis_init: PYXIS_INT_MASK 0x%lx\n", *(vulp)PYXIS_INT_MASK);
+printk("pyxis_init: PYXIS_INT_ROUTE 0x%lx\n", *(vulp)PYXIS_INT_ROUTE);
+printk("pyxis_init: PYXIS_INT_HILO 0x%lx\n", *(vulp)PYXIS_INT_HILO);
+printk("pyxis_init: PYXIS_INT_CNFG 0x%x\n", *(vuip)PYXIS_INT_CNFG);
+printk("pyxis_init: PYXIS_RT_COUNT 0x%lx\n", *(vulp)PYXIS_RT_COUNT);
+#endif
+
+#if 0
+printk("pyxis_init: W0 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W0_BASE, *(vuip)PYXIS_W0_MASK, *(vuip)PYXIS_T0_BASE);
+printk("pyxis_init: W1 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W1_BASE, *(vuip)PYXIS_W1_MASK, *(vuip)PYXIS_T1_BASE);
+printk("pyxis_init: W2 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W2_BASE, *(vuip)PYXIS_W2_MASK, *(vuip)PYXIS_T2_BASE);
+printk("pyxis_init: W3 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W3_BASE, *(vuip)PYXIS_W3_MASK, *(vuip)PYXIS_T3_BASE);
+#endif
+
+        /* 
+	 * Set up error reporting. Make sure CPU_PE is OFF in the mask.
+	 */
+	pyxis_err = *(vuip)PYXIS_ERR_MASK;
+	pyxis_err &= ~4;   
+	*(vuip)PYXIS_ERR_MASK = pyxis_err;
+	mb();
+	pyxis_err = *(vuip)PYXIS_ERR_MASK;
+
+	pyxis_err = *(vuip)PYXIS_ERR ;
+	pyxis_err |= 0x180;   /* master/target abort */
+	*(vuip)PYXIS_ERR = pyxis_err ;
+	mb() ;
+	pyxis_err = *(vuip)PYXIS_ERR ;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	/* check window 0 for enabled and mapped to 0 */
+	if (((*(vuip)PYXIS_W0_BASE & 3) == 1) &&
+	    (*(vuip)PYXIS_T0_BASE == 0) &&
+	    ((*(vuip)PYXIS_W0_MASK & 0xfff00000U) > 0x0ff00000U))
+	{
+	  PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W0_BASE & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W0_MASK & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("pyxis_init: using Window 0 settings\n");
+	  printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)PYXIS_W0_BASE,
+		 *(vuip)PYXIS_W0_MASK,
+		 *(vuip)PYXIS_T0_BASE);
+#endif
+	}
+	else  /* check window 1 for enabled and mapped to 0 */
+	if (((*(vuip)PYXIS_W1_BASE & 3) == 1) &&
+	    (*(vuip)PYXIS_T1_BASE == 0) &&
+	    ((*(vuip)PYXIS_W1_MASK & 0xfff00000U) > 0x0ff00000U))
+{
+	  PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W1_BASE & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W1_MASK & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("pyxis_init: using Window 1 settings\n");
+	  printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)PYXIS_W1_BASE,
+		 *(vuip)PYXIS_W1_MASK,
+		 *(vuip)PYXIS_T1_BASE);
+#endif
+	}
+	else  /* check window 2 for enabled and mapped to 0 */
+	if (((*(vuip)PYXIS_W2_BASE & 3) == 1) &&
+	    (*(vuip)PYXIS_T2_BASE == 0) &&
+	    ((*(vuip)PYXIS_W2_MASK & 0xfff00000U) > 0x0ff00000U))
+	{
+	  PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W2_BASE & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W2_MASK & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("pyxis_init: using Window 2 settings\n");
+	  printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)PYXIS_W2_BASE,
+		 *(vuip)PYXIS_W2_MASK,
+		 *(vuip)PYXIS_T2_BASE);
+#endif
+	}
+	else  /* check window 3 for enabled and mapped to 0 */
+	if (((*(vuip)PYXIS_W3_BASE & 3) == 1) &&
+	    (*(vuip)PYXIS_T3_BASE == 0) &&
+	    ((*(vuip)PYXIS_W3_MASK & 0xfff00000U) > 0x0ff00000U))
+	{
+	  PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W3_BASE & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W3_MASK & 0xfff00000U;
+	  PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+	  printk("pyxis_init: using Window 3 settings\n");
+	  printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+		 *(vuip)PYXIS_W3_BASE,
+		 *(vuip)PYXIS_W3_MASK,
+		 *(vuip)PYXIS_T3_BASE);
+#endif
+	}
+	else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+	{
+#if defined(CONFIG_ALPHA_RUFFIAN)
+#if 1
+	printk("pyxis_init: skipping window register rewrites... "
+	       "trust DeskStation firmware!\n");
+#endif
+#else /* RUFFIAN */
+	/*
+	 * Set up the PCI->physical memory translation windows.
+	 * For now, windows 1,2 and 3 are disabled.  In the future, we may
+	 * want to use them to do scatter/gather DMA.  Window 0
+	 * goes at 1 GB and is 1 GB large.
+	 */
+
+	*(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE & 0xfff00000U);
+ 	*(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE - 1) & 0xfff00000U;
+	*(vuip)PYXIS_T0_BASE = 0;
+
+	*(vuip)PYXIS_W1_BASE = 0x0 ;
+	*(vuip)PYXIS_W2_BASE = 0x0 ;
+	*(vuip)PYXIS_W3_BASE = 0x0 ;
+	mb();
+#endif /* RUFFIAN */
+	}
+
+	/*
+	 * check ASN in HWRPB for validity, report if bad
+	 */
+	if (hwrpb->max_asn != MAX_ASN) {
+		printk("PYXIS_init: max ASN from HWRPB is bad (0x%lx)\n",
+			hwrpb->max_asn);
+		hwrpb->max_asn = MAX_ASN;
+	}
+
+        /*
+         * Next, clear the PYXIS_CFG register, which gets used
+         *  for PCI Config Space accesses. That is the way
+         *  we want to use it, and we do not want to depend on
+         *  what ARC or SRM might have left behind...
+         */
+        {
+          unsigned int pyxis_cfg, temp;
+	  pyxis_cfg = *((vuip)PYXIS_CFG); mb();
+	  if (pyxis_cfg != 0) {
+#if 1
+	    printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg);
+#endif
+	    *((vuip)PYXIS_CFG) = 0; mb();
+	    temp = *((vuip)PYXIS_CFG);
+	  }
+        }
+ 
+        {
+          unsigned int pyxis_hae_mem = *((vuip)PYXIS_HAE_MEM);
+          unsigned int pyxis_hae_io = *((vuip)PYXIS_HAE_IO);
+#if 0
+	  printk("PYXIS_init: HAE_MEM was 0x%x\n", pyxis_hae_mem);
+	  printk("PYXIS_init: HAE_IO was 0x%x\n", pyxis_hae_io);
+#endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	  /*
+	    sigh... For the SRM setup, unless we know apriori what the HAE
+	    contents will be, we need to setup the arbitrary region bases
+	    so we can test against the range of addresses and tailor the
+	    region chosen for the SPARSE memory access.
+
+	    see include/asm-alpha/pyxis.h for the SPARSE mem read/write
+	  */
+	  pyxis_sm_base_r1 = (pyxis_hae_mem      ) & 0xe0000000UL;/* region 1 */
+	  pyxis_sm_base_r2 = (pyxis_hae_mem << 16) & 0xf8000000UL;/* region 2 */
+	  pyxis_sm_base_r3 = (pyxis_hae_mem << 24) & 0xfc000000UL;/* region 3 */
+#else /* SRM_SETUP */
+          *((vuip)PYXIS_HAE_MEM) = 0U; mb();
+	  pyxis_hae_mem = *((vuip)PYXIS_HAE_MEM);
+          *((vuip)PYXIS_HAE_IO) = 0; mb();
+	  pyxis_hae_io = *((vuip)PYXIS_HAE_IO);
+#endif /* SRM_SETUP */
+        }
+
+	/*
+	 * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for
+	 * enabling byte/word PCI bus space(s) access.
+	 */
+	{
+	  unsigned int ctrl1;
+	  ctrl1 = *((vuip) PYXIS_CTRL1);
+	  if (!(ctrl1 & 1)) {
+#if 0
+	    printk("PYXIS_init: enabling byte/word PCI space\n");
+#endif
+	    *((vuip) PYXIS_CTRL1) = ctrl1 | 1; mb();
+	    ctrl1 = *((vuip)PYXIS_CTRL1);
+	  }
+	}
+
+	return mem_start;
+}
+
+int pyxis_pci_clr_err(void)
+{
+	PYXIS_jd = *((vuip)PYXIS_ERR);
+	DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd));
+	*((vuip)PYXIS_ERR) = 0x0180; mb();
+	PYXIS_jd = *((vuip)PYXIS_ERR);
+	return 0;
+}
+
+void pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
+			 struct pt_regs * regs)
+{
+#if 0
+        printk("PYXIS machine check ignored\n") ;
+#else
+	struct el_common *mchk_header;
+	struct el_PYXIS_sysdata_mcheck *mchk_sysdata;
+
+	mchk_header = (struct el_common *)la_ptr;
+
+	mchk_sysdata = 
+	  (struct el_PYXIS_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
+
+#if 0
+	DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+	     vector, la_ptr));
+	DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+	     regs->pc, mchk_header->size, mchk_header->proc_offset,
+	     mchk_header->sys_offset));
+	DBG_MCK(("pyxis_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
+	     PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr,
+	     mchk_sysdata->epic_pear));
+#endif
+#ifdef DEBUG_MCHECK_DUMP
+	{
+	    unsigned long *ptr;
+	    int i;
+
+	    ptr = (unsigned long *)la_ptr;
+	    for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+		printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+	    }
+	}
+#endif /* DEBUG_MCHECK_DUMP */
+	/*
+	 * Check if machine check is due to a badaddr() and if so,
+	 * ignore the machine check.
+	 */
+	mb();
+	mb();
+	if (PYXIS_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+		DBG(("PYXIS machine check expected\n"));
+		PYXIS_mcheck_expected = 0;
+		PYXIS_mcheck_taken = 1;
+		mb();
+		mb();
+		draina();
+		pyxis_pci_clr_err();
+		wrmces(0x7);
+		mb();
+	}
+#if 1
+	else {
+		printk("PYXIS machine check NOT expected\n") ;
+	DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+	     vector, la_ptr));
+	DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+	     regs->pc, mchk_header->size, mchk_header->proc_offset,
+	     mchk_header->sys_offset));
+		PYXIS_mcheck_expected = 0;
+		PYXIS_mcheck_taken = 1;
+		mb();
+		mb();
+		draina();
+		pyxis_pci_clr_err();
+		wrmces(0x7);
+		mb();
+	}
+#endif
+#endif
+}
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+/* NOTE: this is only used by MILO, AFAIK... */
+/*
+ * The DeskStation Ruffian motherboard firmware does not place
+ * the memory size in the PALimpure area.  Therefore, it uses
+ * the Bank Configuration Registers in PYXIS to obtain the size.
+ */
+unsigned long pyxis_get_bank_size(unsigned long offset)
+{
+  unsigned long      bank_addr;
+  
+  /* valid offsets are: 0x800, 0x840 and 0x880
+   * since Ruffian only uses three banks
+   */
+  bank_addr = (unsigned long)PYXIS_MCR + offset;
+  
+  /* check BANK_ENABLE */
+  if (*((unsigned long *)bank_addr) && 0x01)
+    {
+      /* do case on BANK_SIZE bits */
+      switch (*((unsigned long *)bank_addr) & 0x01e)
+	{
+	case 0x00: return 0x40000000UL; break; /*   1G */
+	case 0x02: return 0x20000000UL; break; /* 512M */
+	case 0x04: return 0x10000000UL; break; /* 256M */
+	case 0x06: return 0x08000000UL; break; /* 128M */
+	case 0x08: return 0x04000000UL; break; /*  64M */
+	case 0x0a: return 0x02000000UL; break; /*  32M */
+	case 0x0c: return 0x01000000UL; break; /*  16M */
+	case 0x0e: return 0x00800000UL; break; /*   8M */
+	case 0x10: return 0x80000000UL; break; /*   2G */
+	default  : return 0x00000000UL; break; /* ERROR*/
+	}
+    } else
+      return 0x00UL;
+}
+#endif /* CONFIG_ALPHA_RUFFIAN */
+
+#endif /* CONFIG_ALPHA_PYXIS */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.0.33/linux/arch/alpha/kernel/setup.c	Tue Aug 20 23:18:07 1996
+++ linux/arch/alpha/kernel/setup.c	Wed Jun  3 15:17:46 1998
@@ -22,6 +22,7 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/config.h>	/* CONFIG_ALPHA_LCA etc */
+#include <linux/mc146818rtc.h>
 
 #include <asm/segment.h>
 #include <asm/pgtable.h>
@@ -58,13 +59,26 @@
  * code think we're on a VGA color display.
  */
 struct screen_info screen_info = {
+#if defined(CONFIG_ALPHA_BOOK1)
+  /* the AlphaBook1 has LCD video fixed at 800x600, 37 rows and 100 cols */
+	0, 37,			/* orig-x, orig-y */
+#else
 	0, 25,			/* orig-x, orig-y */
+#endif
 	{ 0, 0 },		/* unused */
 	0,			/* orig-video-page */
 	0,			/* orig-video-mode */
+#if defined(CONFIG_ALPHA_BOOK1)
+        100,			/* orig-video-cols */
+#else
 	80,			/* orig-video-cols */
+#endif
 	0,0,0,			/* ega_ax, ega_bx, ega_cx */
+#if defined(CONFIG_ALPHA_BOOK1)
+        37,			/* orig-video-lines */
+#else
 	25,			/* orig-video-lines */
+#endif
 	1,			/* orig-video-isVGA */
 	16			/* orig-video-points */
 };
@@ -84,9 +98,12 @@
     outb(0x18, 0x41);
 #endif
 
+#if !defined(CONFIG_ALPHA_RUFFIAN)
+    /* Ruffian depends on the system timer established in MILO!! */
     outb(0x36, 0x43);	/* counter 0: system timer */
     outb(0x00, 0x40);
     outb(0x00, 0x40);
+#endif /* RUFFIAN */
 
     outb(0xb6, 0x43);	/* counter 2: speaker */
     outb(0x31, 0x42);
@@ -121,9 +138,19 @@
 
 	init_pit();
 
+	if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) {
+#if 1
+	  printk("init_timers: setting RTC_FREQ to 1024/sec\n");
+#endif
+	  CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+	}
+
 	hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
 
+#ifndef CONFIG_ALPHA_SRM_SETUP
 	set_hae(hae.cache);	/* sync HAE register w/hae_cache */
+#endif /* !SRM_SETUP */
+
 	wrmces(0x7);		/* reset enable correctable error reports */
 
 	ROOT_DEV = to_kdev_t(0x0802);		/* sda2 */
@@ -154,39 +181,161 @@
 	*memory_start_p = apecs_init(*memory_start_p, *memory_end_p);
 #elif defined(CONFIG_ALPHA_CIA)
 	*memory_start_p = cia_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_PYXIS)
+	*memory_start_p = pyxis_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_T2)
+	*memory_start_p = t2_init(*memory_start_p, *memory_end_p);
 #endif
 }
 
-/*
- * BUFFER is PAGE_SIZE bytes long.
+#	define N(a)	(sizeof(a)/sizeof(a[0]))
+
+/* A change was made to the HWRPB via an ECO and the following code tracks
+ * a part of the ECO.  The HWRPB version must be 5 or higher or the ECO
+ * was not implemented in the console firmware.  If its at rev 5 or greater
+ * we can get the platform ascii string name from the HWRPB.  Thats what this
+ * function does.  It checks the rev level and if the string is in the HWRPB
+ * it returns the addtess of the string ... a pointer to the platform name.
+ *
+ * Returns:
+ *      - Pointer to a ascii string if its in the HWRPB
+ *      - Pointer to a blank string if the data is not in the HWRPB.
  */
+static char *
+platform_string(void)
+{
+	struct dsr_struct *dsr;
+	static char unk_system_string[] = "N/A";
+
+        /* Go to the console for the string pointer.
+         * If the rpb_vers is not 5 or greater the rpb
+	 * is old and does not have this data in it.
+	 */
+        if (hwrpb->revision < 5)
+		return (unk_system_string);
+	else {
+		/* The Dynamic System Recognition struct
+		 * has the system platform name starting
+		 * after the character count of the string.
+		 */
+		dsr =  ((struct dsr_struct *)
+			  ((char *)hwrpb + hwrpb->dsr_offset));
+		return ((char *)dsr + (dsr->sysname_off +
+						 sizeof(long)));
+        }
+}
+
+static void
+get_sysnames(long type, long variation,
+	     char **type_name, char **variation_name)
+{
+	static char *sys_unknown = "Unknown";
+	static char *systype_names[] = {
+		"0",
+		"ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen",
+		"Pelican", "Morgan", "Sable", "Medulla", "Noname",
+		"Turbolaser", "Avanti", "14", "Alcor", "Tradewind",
+		"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
+		"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
+		"Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
+		"Tsunami", "Wildfire", "CUSCO"
+	};
+
+	static char *unofficial_names[] = {
+		"100",
+		"Ruffian"
+	};
+
+	static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"};
+	static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3};
+
+	static char * alcor_names[] = {"Alcor", "Maverick", "Bret"};
+	static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2};
+
+	static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"};
+	static int eb64p_indices[] = {0,0,1.2};
+
+	static char * eb66_names[] = {"EB66", "EB66+"};
+	static int eb66_indices[] = {0,0,1};
+
+	static char * rawhide_names[] = {"Dodge", "Wrangler", "Durango",
+					 "Tincup", "DaVinci"};
+	static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
+
+	long member;
+	
+
+	/* restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */
+	if (type < 0) type = -type;
+
+	/* if not in the tables, make it UNKNOWN */
+	/* else set type name to family */
+	if (type < N(systype_names)) {
+	    *type_name = systype_names[type];
+	} else
+	if ((type > ST_UNOFFICIAL_BIAS) &&
+	    (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) {
+	    *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS];
+	} else {
+	    *type_name = sys_unknown;
+	    *variation_name = sys_unknown;
+	    return;
+	}
+
+	/* set variation to "0"; if variation is zero, done */
+	*variation_name = systype_names[0];
+	if (variation == 0) {
+		return;
+	}
+
+	member = (variation >> 10) & 0x3f; /* member ID is a bit-field */
+
+	switch (type) { /* select by family */
+	default: /* default to variation "0" ????FIXME???? */
+		break;
+	case ST_DEC_EB164:
+		if (member < N(eb164_indices))
+		  *variation_name = eb164_names[eb164_indices[member]];
+		break;
+	case ST_DEC_ALCOR:
+		if (member < N(alcor_indices))
+		  *variation_name = alcor_names[alcor_indices[member]];
+		break;
+	case ST_DEC_EB64P:
+		if (member < N(eb64p_indices))
+		  *variation_name = eb64p_names[eb64p_indices[member]];
+		break;
+	case ST_DEC_EB66:
+		if (member < N(eb66_indices))
+		  *variation_name = eb66_names[eb66_indices[member]];
+		break;
+	case ST_DEC_RAWHIDE:
+		if (member < N(rawhide_indices))
+		  *variation_name = rawhide_names[rawhide_indices[member]];
+		break;
+	} /* end family switch */
+	return;
+}
+
 int get_cpuinfo(char *buffer)
+/* BUFFER is PAGE_SIZE bytes long. */
 {
 	const char *cpu_name[] = {
-		"EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45"
-	};
-#	define SYSTYPE_NAME_BIAS	20
-	const char *systype_name[] = {
-		"Cabriolet", "EB66P", "-18", "-17", "-16", "-15",
-		"-14", "-13", "-12", "-11", "-10", "-9", "-8",
-		"-7", "-6", "-5", "-4", "-3", "-2", "-1", "0",
-		"ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen",
-		"Pelican", "8", "Sable", "AXPvme", "Noname",
-		"Turbolaser", "Avanti", "Mustang", "Alcor", "16",
-		"Mikasa", "18", "EB66", "EB64+", "21", "22", "23",
-		"24", "25", "EB164"
+		"EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45", "EV56",
+		"EV6", "PCA56"
 	};
 	struct percpu_struct *cpu;
 	unsigned int cpu_index;
-	long sysname_index;
+	char *systype_name;
+	char *sysvariation_name;
 	extern struct unaligned_stat {
 		unsigned long count, va, pc;
 	} unaligned[2];
-#	define N(a)	(sizeof(a)/sizeof(a[0]))
 
 	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
 	cpu_index = (unsigned) (cpu->type - 1);
-	sysname_index = hwrpb->sys_type + SYSTYPE_NAME_BIAS;
+	get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
+		     &systype_name, &sysvariation_name);
 
 	return sprintf(buffer,
 		       "cpu\t\t\t: Alpha\n"
@@ -195,7 +344,7 @@
 		       "cpu revision\t\t: %ld\n"
 		       "cpu serial number\t: %s\n"
 		       "system type\t\t: %s\n"
-		       "system variation\t: %ld\n"
+		       "system variation\t: %s\n"
 		       "system revision\t\t: %ld\n"
 		       "system serial number\t: %s\n"
 		       "cycle frequency [Hz]\t: %lu\n"
@@ -205,14 +354,13 @@
 		       "max. addr. space #\t: %ld\n"
 		       "BogoMIPS\t\t: %lu.%02lu\n"
 		       "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
-		       "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n",
+		       "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
+		       "platform string\t\t: %s\n",
 
 		       (cpu_index < N(cpu_name)
 			? cpu_name[cpu_index] : "Unknown"),
 		       cpu->variation, cpu->revision, (char*)cpu->serial_no,
-		       (sysname_index < N(systype_name)
-			? systype_name[sysname_index] : "Unknown"),
-		       hwrpb->sys_variation, hwrpb->sys_revision,
+		       systype_name, sysvariation_name, hwrpb->sys_revision,
 		       (char*)hwrpb->ssn,
 		       hwrpb->cycle_freq,
 		       hwrpb->intr_freq / 4096,
@@ -222,6 +370,7 @@
 		       hwrpb->max_asn,
 		       loops_per_sec / 500000, (loops_per_sec / 5000) % 100,
 		       unaligned[0].count, unaligned[0].pc, unaligned[0].va,
-		       unaligned[1].count, unaligned[1].pc, unaligned[1].va);
-#       undef N
+		       unaligned[1].count, unaligned[1].pc, unaligned[1].va,
+		       platform_string());
 }
+#       undef N
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.0.33/linux/arch/alpha/kernel/signal.c	Mon Aug  4 15:41:48 1997
+++ linux/arch/alpha/kernel/signal.c	Wed Jun  3 15:17:46 1998
@@ -203,6 +203,9 @@
 	put_fs_quad(regs->gp , sc->sc_regs+29);
 	for (i = 0; i < 31; i++)
 		put_fs_quad(sw->fp[i], sc->sc_fpregs+i);
+	put_fs_quad(regs->trap_a0, &sc->sc_traparg_a0);
+	put_fs_quad(regs->trap_a1, &sc->sc_traparg_a1);
+	put_fs_quad(regs->trap_a2, &sc->sc_traparg_a2);
 
 	/*
 	 * The following is:
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/smc.c linux/arch/alpha/kernel/smc.c
--- v2.0.33/linux/arch/alpha/kernel/smc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/kernel/smc.c	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,2842 @@
+/*
+ * SMC 37C93X and 37C669 initialization code
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#if 0
+# define DBG_DEVS(args)		printk args
+#else
+# define DBG_DEVS(args)
+#endif
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/hwrpb.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#define KB		1024
+#define MB		(1024*KB)
+#define GB		(1024*MB)
+
+#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
+
+/* device "activate" register contents */
+#define DEVICE_ON		1
+#define DEVICE_OFF		0
+
+/* configuration on/off keys */
+#define CONFIG_ON_KEY		0x55
+#define CONFIG_OFF_KEY		0xaa
+
+/* configuration space device definitions */
+#define FDC			0
+#define IDE1			1
+#define IDE2			2
+#define PARP			3
+#define SER1			4
+#define SER2			5
+#define RTCL			6
+#define KYBD			7
+#define AUXIO			8
+
+/* Chip register offsets from base */
+#define CONFIG_CONTROL		0x02
+#define INDEX_ADDRESS		0x03
+#define LOGICAL_DEVICE_NUMBER	0x07
+#define DEVICE_ID		0x20
+#define DEVICE_REV		0x21
+#define POWER_CONTROL		0x22
+#define POWER_MGMT		0x23
+#define OSC			0x24
+
+#define ACTIVATE		0x30
+#define ADDR_HI			0x60
+#define ADDR_LO			0x61
+#define INTERRUPT_SEL		0x70
+#define INTERRUPT_SEL_2		0x72 /* KYBD/MOUS only */
+#define DMA_CHANNEL_SEL		0x74 /* FDC/PARP only */
+
+#define FDD_MODE_REGISTER	0x90
+#define FDD_OPTION_REGISTER	0x91
+
+/* values that we read back that are expected ... */
+#define VALID_DEVICE_ID		2
+
+/* default device addresses */
+#define KYBD_INTERRUPT		1
+#define MOUS_INTERRUPT		12
+#define COM2_BASE		0x2f8
+#define COM2_INTERRUPT		3
+#define COM1_BASE		0x3f8
+#define COM1_INTERRUPT		4
+#define PARP_BASE		0x3bc
+#define PARP_INTERRUPT		7
+
+#define SMC_DEBUG 0
+
+unsigned long SMCConfigState( unsigned long baseAddr )
+{
+    unsigned char devId;
+    unsigned char devRev;
+
+    unsigned long configPort;
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    configPort = indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )configPort + 1 );
+
+    outb(CONFIG_ON_KEY, configPort);
+    outb(CONFIG_ON_KEY, configPort);
+    outb(DEVICE_ID, indexPort);
+    devId = inb(dataPort);
+    if ( devId == VALID_DEVICE_ID ) {
+        outb(DEVICE_REV, indexPort);
+        devRev = inb(dataPort);
+    }
+    else {
+        baseAddr = 0;
+    }
+    return( baseAddr );
+}
+
+void SMCRunState( unsigned long baseAddr )
+{
+    outb(CONFIG_OFF_KEY, baseAddr);
+}
+
+unsigned long SMCDetectUltraIO(void)
+{
+    unsigned long baseAddr;
+
+    baseAddr = 0x3F0;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
+        return( baseAddr );
+    }
+    baseAddr = 0x370;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
+        return( baseAddr );
+    }
+    return( ( unsigned long )0 );
+}
+
+void SMCEnableDevice( unsigned long baseAddr,
+		      unsigned long device,
+		      unsigned long portaddr,
+		      unsigned long interrupt)
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(device, dataPort);
+
+    outb(ADDR_LO, indexPort);
+    outb(( portaddr & 0xFF ), dataPort);
+
+    outb(ADDR_HI, indexPort);
+    outb(( ( portaddr >> 8 ) & 0xFF ), dataPort);
+
+    outb(INTERRUPT_SEL, indexPort);
+    outb(interrupt, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableKYBD( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(KYBD, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(KYBD_INTERRUPT, dataPort);
+
+    outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */
+    outb(MOUS_INTERRUPT, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableFDC( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    unsigned char oldValue;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(FDC, dataPort);
+
+    outb(FDD_MODE_REGISTER, indexPort);
+    oldValue = inb(dataPort);
+
+    oldValue |= 0x0E;                   /* Enable burst mode */
+    outb(oldValue, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(0x06, dataPort );
+
+    outb(DMA_CHANNEL_SEL, indexPort);  /* DMA channel select */
+    outb(0x02, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+#if SMC_DEBUG
+void SMCReportDeviceStatus( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+    unsigned char currentControl;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(POWER_CONTROL, indexPort);
+    currentControl = inb(dataPort);
+
+    if ( currentControl & ( 1 << FDC ) )
+        printk( "\t+FDC Enabled\n" );
+    else
+        printk( "\t-FDC Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE1 ) )
+        printk( "\t+IDE1 Enabled\n" );
+    else
+        printk( "\t-IDE1 Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE2 ) )
+        printk( "\t+IDE2 Enabled\n" );
+    else
+        printk( "\t-IDE2 Disabled\n" );
+
+    if ( currentControl & ( 1 << PARP ) )
+        printk( "\t+PARP Enabled\n" );
+    else
+        printk( "\t-PARP Disabled\n" );
+
+    if ( currentControl & ( 1 << SER1 ) )
+        printk( "\t+SER1 Enabled\n" );
+    else
+        printk( "\t-SER1 Disabled\n" );
+
+    if ( currentControl & ( 1 << SER2 ) )
+        printk( "\t+SER2 Enabled\n" );
+    else
+        printk( "\t-SER2 Disabled\n" );
+
+    printk( "\n" );
+}
+#endif
+
+void SMC93X_Init(void)
+{
+    unsigned long SMCUltraBase;
+
+    if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) {
+        printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
+		SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT );
+	/* IDE on the SMC is not enabled; CMD646 (PCI) on MB */
+        SMCEnableKYBD( SMCUltraBase );
+        SMCEnableFDC( SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCRunState( SMCUltraBase );
+    }
+    else {
+#if SMC_DEBUG
+        printk( "No SMC FDC37C93X Ultra I/O Controller found\n" );
+#endif
+    }
+}
+
+#endif /* PC164 || LX164 */
+
+/* we include MIATA because the GL has the SMC669 on board */
+#if defined(CONFIG_ALPHA_SX164) || defined(CONFIG_ALPHA_MIATA)
+
+#define SMC_DEBUG   0
+
+/* File:	smcc669_def.h
+ *
+ * Copyright (C) 1997 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  of  the  terms  of  such  license  and with the
+ * inclusion of the above copyright notice. This software or  any  other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ * The information in this software is  subject to change without notice
+ * and  should  not  be  construed  as a commitment by Digital Equipment
+ * Corporation.
+ *
+ * Digital assumes no responsibility for the use  or  reliability of its
+ * software on equipment which is not supplied by Digital.
+ *
+ *
+ * Abstract:	
+ *
+ *	This file contains header definitions for the SMC37c669 
+ *	Super I/O controller. 
+ *
+ * Author:	
+ *
+ *	Eric Rasmussen
+ *
+ * Modification History:
+ *
+ *	er	28-Jan-1997	Initial Entry
+ */
+
+#ifndef __SMC37c669_H
+#define __SMC37c669_H
+
+/*
+** Macros for handling device IRQs
+**
+** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15) 
+** to device IRQs (A - H).
+*/
+#define SMC37c669_DEVICE_IRQ_MASK	0x80000000
+#define SMC37c669_DEVICE_IRQ( __i )	\
+	((SMC37c669_DEVICE_IRQ_MASK) | (__i))
+#define SMC37c669_IS_DEVICE_IRQ(__i)	\
+	(((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK))
+#define SMC37c669_RAW_DEVICE_IRQ(__i)	\
+	((__i) & ~(SMC37c669_DEVICE_IRQ_MASK))
+
+/*
+** Macros for handling device DRQs
+**
+** The mask acts as a flag used in mapping actual ISA DMA
+** channels to device DMA channels (A - C).
+*/
+#define SMC37c669_DEVICE_DRQ_MASK	0x80000000
+#define SMC37c669_DEVICE_DRQ(__d)	\
+	((SMC37c669_DEVICE_DRQ_MASK) | (__d))
+#define SMC37c669_IS_DEVICE_DRQ(__d)	\
+	(((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK))
+#define SMC37c669_RAW_DEVICE_DRQ(__d)	\
+	((__d) & ~(SMC37c669_DEVICE_DRQ_MASK))
+
+#define SMC37c669_DEVICE_ID	0x3
+
+/*
+** SMC37c669 Device Function Definitions
+*/
+#define SERIAL_0	0
+#define SERIAL_1	1
+#define PARALLEL_0	2
+#define FLOPPY_0	3
+#define IDE_0		4
+#define NUM_FUNCS	5
+
+/*
+** Default Device Function Mappings
+*/
+#define COM1_BASE	0x3F8
+#define COM1_IRQ	4
+#define COM2_BASE	0x2F8
+#define COM2_IRQ	3
+#define PARP_BASE	0x3BC
+#define PARP_IRQ	7
+#define PARP_DRQ	3
+#define FDC_BASE	0x3F0
+#define FDC_IRQ		6
+#define FDC_DRQ		2
+
+/*
+** Configuration On/Off Key Definitions
+*/
+#define SMC37c669_CONFIG_ON_KEY		0x55
+#define SMC37c669_CONFIG_OFF_KEY	0xAA
+
+/*
+** SMC 37c669 Device IRQs
+*/
+#define SMC37c669_DEVICE_IRQ_A	    ( SMC37c669_DEVICE_IRQ( 0x01 ) )
+#define SMC37c669_DEVICE_IRQ_B	    ( SMC37c669_DEVICE_IRQ( 0x02 ) )
+#define SMC37c669_DEVICE_IRQ_C	    ( SMC37c669_DEVICE_IRQ( 0x03 ) )
+#define SMC37c669_DEVICE_IRQ_D	    ( SMC37c669_DEVICE_IRQ( 0x04 ) )
+#define SMC37c669_DEVICE_IRQ_E	    ( SMC37c669_DEVICE_IRQ( 0x05 ) )
+#define SMC37c669_DEVICE_IRQ_F	    ( SMC37c669_DEVICE_IRQ( 0x06 ) )
+/*      SMC37c669_DEVICE_IRQ_G	    *** RESERVED ***/
+#define SMC37c669_DEVICE_IRQ_H	    ( SMC37c669_DEVICE_IRQ( 0x08 ) )
+
+/*
+** SMC 37c669 Device DMA Channel Definitions
+*/
+#define SMC37c669_DEVICE_DRQ_A		    ( SMC37c669_DEVICE_DRQ( 0x01 ) )
+#define SMC37c669_DEVICE_DRQ_B		    ( SMC37c669_DEVICE_DRQ( 0x02 ) )
+#define SMC37c669_DEVICE_DRQ_C		    ( SMC37c669_DEVICE_DRQ( 0x03 ) )
+
+/*
+** Configuration Register Index Definitions
+*/
+#define SMC37c669_CR00_INDEX	    0x00
+#define SMC37c669_CR01_INDEX	    0x01
+#define SMC37c669_CR02_INDEX	    0x02
+#define SMC37c669_CR03_INDEX	    0x03
+#define SMC37c669_CR04_INDEX	    0x04
+#define SMC37c669_CR05_INDEX	    0x05
+#define SMC37c669_CR06_INDEX	    0x06
+#define SMC37c669_CR07_INDEX	    0x07
+#define SMC37c669_CR08_INDEX	    0x08
+#define SMC37c669_CR09_INDEX	    0x09
+#define SMC37c669_CR0A_INDEX	    0x0A
+#define SMC37c669_CR0B_INDEX	    0x0B
+#define SMC37c669_CR0C_INDEX	    0x0C
+#define SMC37c669_CR0D_INDEX	    0x0D
+#define SMC37c669_CR0E_INDEX	    0x0E
+#define SMC37c669_CR0F_INDEX	    0x0F
+#define SMC37c669_CR10_INDEX	    0x10
+#define SMC37c669_CR11_INDEX	    0x11
+#define SMC37c669_CR12_INDEX	    0x12
+#define SMC37c669_CR13_INDEX	    0x13
+#define SMC37c669_CR14_INDEX	    0x14
+#define SMC37c669_CR15_INDEX	    0x15
+#define SMC37c669_CR16_INDEX	    0x16
+#define SMC37c669_CR17_INDEX	    0x17
+#define SMC37c669_CR18_INDEX	    0x18
+#define SMC37c669_CR19_INDEX	    0x19
+#define SMC37c669_CR1A_INDEX	    0x1A
+#define SMC37c669_CR1B_INDEX	    0x1B
+#define SMC37c669_CR1C_INDEX	    0x1C
+#define SMC37c669_CR1D_INDEX	    0x1D
+#define SMC37c669_CR1E_INDEX	    0x1E
+#define SMC37c669_CR1F_INDEX	    0x1F
+#define SMC37c669_CR20_INDEX	    0x20
+#define SMC37c669_CR21_INDEX	    0x21
+#define SMC37c669_CR22_INDEX	    0x22
+#define SMC37c669_CR23_INDEX	    0x23
+#define SMC37c669_CR24_INDEX	    0x24
+#define SMC37c669_CR25_INDEX	    0x25
+#define SMC37c669_CR26_INDEX	    0x26
+#define SMC37c669_CR27_INDEX	    0x27
+#define SMC37c669_CR28_INDEX	    0x28
+#define SMC37c669_CR29_INDEX	    0x29
+
+/*
+** Configuration Register Alias Definitions
+*/
+#define SMC37c669_DEVICE_ID_INDEX		    SMC37c669_CR0D_INDEX
+#define SMC37c669_DEVICE_REVISION_INDEX		    SMC37c669_CR0E_INDEX
+#define SMC37c669_FDC_BASE_ADDRESS_INDEX	    SMC37c669_CR20_INDEX
+#define SMC37c669_IDE_BASE_ADDRESS_INDEX	    SMC37c669_CR21_INDEX
+#define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX	    SMC37c669_CR22_INDEX
+#define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX	    SMC37c669_CR23_INDEX
+#define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX	    SMC37c669_CR24_INDEX
+#define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX	    SMC37c669_CR25_INDEX
+#define SMC37c669_PARALLEL_FDC_DRQ_INDEX	    SMC37c669_CR26_INDEX
+#define SMC37c669_PARALLEL_FDC_IRQ_INDEX	    SMC37c669_CR27_INDEX
+#define SMC37c669_SERIAL_IRQ_INDEX		    SMC37c669_CR28_INDEX
+
+/*
+** Configuration Register Definitions
+**
+** The INDEX (write only) and DATA (read/write) ports are effective 
+** only when the chip is in the Configuration State.
+*/
+typedef struct _SMC37c669_CONFIG_REGS {
+    unsigned char index_port;
+    unsigned char data_port;
+} SMC37c669_CONFIG_REGS;
+
+/*
+** CR00 - default value 0x28
+**
+**  IDE_EN (CR00<1:0>):
+**	0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1
+**	11 - IRQ_H available as IRQ output,
+**	     IRRX2, IRTX2 available as alternate IR pins
+**	10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE
+**
+**  VALID (CR00<7>):
+**	A high level on this software controlled bit can
+**	be used to indicate that a valid configuration
+**	cycle has occurred.  The control software must
+**	take care to set this bit at the appropriate times.
+**	Set to zero after power up.  This bit has no
+**	effect on any other hardware in the chip.
+**
+*/
+typedef union _SMC37c669_CR00 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned ide_en : 2;	    /* See note above		*/
+	unsigned reserved1 : 1;	    /* RAZ			*/
+	unsigned fdc_pwr : 1;	    /* 1 = supply power to FDC  */
+	unsigned reserved2 : 3;	    /* Read as 010b		*/
+	unsigned valid : 1;	    /* See note above		*/
+    }	by_field;
+} SMC37c669_CR00;
+
+/*
+** CR01 - default value 0x9C
+*/
+typedef union _SMC37c669_CR01 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned reserved1 : 2;	    /* RAZ			    */
+	unsigned ppt_pwr : 1;	    /* 1 = supply power to PPT	    */
+	unsigned ppt_mode : 1;	    /* 1 = Printer mode, 0 = EPP    */
+	unsigned reserved2 : 1;	    /* Read as 1		    */
+	unsigned reserved3 : 2;	    /* RAZ			    */
+	unsigned lock_crx: 1;	    /* Lock CR00 - CR18		    */
+    }	by_field;
+} SMC37c669_CR01;
+
+/*
+** CR02 - default value 0x88
+*/
+typedef union _SMC37c669_CR02 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned reserved1 : 3;	    /* RAZ			    */
+	unsigned uart1_pwr : 1;	    /* 1 = supply power to UART1    */
+	unsigned reserved2 : 3;	    /* RAZ			    */
+	unsigned uart2_pwr : 1;	    /* 1 = supply power to UART2    */
+    }	by_field;
+} SMC37c669_CR02;
+
+/*
+** CR03 - default value 0x78
+**
+**  CR03<7>	CR03<2>	    Pin 94
+**  -------	-------	    ------
+**     0	   X	    DRV2 (input)
+**     1	   0	    ADRX
+**     1	   1	    IRQ_B
+**
+**  CR03<6>	CR03<5>	    Op Mode
+**  -------	-------	    -------
+**     0	   0	    Model 30
+**     0	   1	    PS/2
+**     1	   0	    Reserved
+**     1	   1	    AT Mode
+*/
+typedef union _SMC37c669_CR03 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned pwrgd_gamecs : 1;  /* 1 = PWRGD, 0 = GAMECS	    */
+	unsigned fdc_mode2 : 1;	    /* 1 = Enhanced Mode 2	    */
+	unsigned pin94_0 : 1;	    /* See note above		    */
+	unsigned reserved1 : 1;	    /* RAZ			    */
+	unsigned drvden : 1;	    /* 1 = high, 0 - output	    */
+	unsigned op_mode : 2;	    /* See note above		    */
+	unsigned pin94_1 : 1;	    /* See note above		    */
+    }	by_field;
+} SMC37c669_CR03;
+
+/*
+** CR04 - default value 0x00
+**
+**  PP_EXT_MODE:
+**	If CR01<PP_MODE> = 0 and PP_EXT_MODE =
+**	    00 - Standard and Bidirectional
+**	    01 - EPP mode and SPP
+**	    10 - ECP mode
+**		 In this mode, 2 drives can be supported
+**		 directly, 3 or 4 drives must use external
+**		 4 drive support.  SPP can be selected
+**		 through the ECR register of ECP as mode 000.
+**	    11 - ECP mode and EPP mode
+**		 In this mode, 2 drives can be supported
+**		 directly, 3 or 4 drives must use external
+**		 4 drive support.  SPP can be selected
+**		 through the ECR register of ECP as mode 000.
+**		 In this mode, EPP can be selected through
+**		 the ECR register of ECP as mode 100.
+**
+**  PP_FDC:
+**	00 - Normal
+**	01 - PPFD1
+**	10 - PPFD2
+**	11 - Reserved
+**
+**  MIDI1:
+**	Serial Clock Select: 
+**	    A low level on this bit disables MIDI support,
+**	    clock = divide by 13.  A high level on this 
+**	    bit enables MIDI support, clock = divide by 12.
+**
+**	MIDI operates at 31.25 Kbps which can be derived 
+**	from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz)
+**
+**  ALT_IO:
+**	0 - Use pins IRRX, IRTX
+**	1 - Use pins IRRX2, IRTX2
+**
+**	If this bit is set, the IR receive and transmit
+**	functions will not be available on pins 25 and 26
+**	unless CR00<IDE_EN> = 11.
+*/
+typedef union _SMC37c669_CR04 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned ppt_ext_mode : 2;  /* See note above		    */
+	unsigned ppt_fdc : 2;	    /* See note above		    */
+	unsigned midi1 : 1;	    /* See note above		    */
+	unsigned midi2 : 1;	    /* See note above		    */
+	unsigned epp_type : 1;	    /* 0 = EPP 1.9, 1 = EPP 1.7	    */
+	unsigned alt_io : 1;	    /* See note above		    */
+    }	by_field;
+} SMC37c669_CR04;
+
+/*
+** CR05 - default value 0x00
+**
+**  DEN_SEL:
+**	00 - Densel output normal
+**	01 - Reserved
+**	10 - Densel output 1
+**	11 - Densel output 0
+**
+*/
+typedef union _SMC37c669_CR05 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned reserved1 : 2;	    /* RAZ					*/
+	unsigned fdc_dma_mode : 1;  /* 0 = burst, 1 = non-burst			*/
+	unsigned den_sel : 2;	    /* See note above				*/
+	unsigned swap_drv : 1;	    /* Swap the FDC motor selects		*/
+	unsigned extx4 : 1;	    /* 0 = 2 drive, 1 = external 4 drive decode	*/
+	unsigned reserved2 : 1;	    /* RAZ					*/
+    }	by_field;
+} SMC37c669_CR05;
+
+/*
+** CR06 - default value 0xFF
+*/
+typedef union _SMC37c669_CR06 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned floppy_a : 2;	    /* Type of floppy drive A	    */
+	unsigned floppy_b : 2;	    /* Type of floppy drive B	    */
+	unsigned floppy_c : 2;	    /* Type of floppy drive C	    */
+	unsigned floppy_d : 2;	    /* Type of floppy drive D	    */
+    }	by_field;
+} SMC37c669_CR06;
+
+/*
+** CR07 - default value 0x00
+**
+**  Auto Power Management CR07<7:4>:
+**	0 - Auto Powerdown disabled (default)
+**	1 - Auto Powerdown enabled
+**
+**	This bit is reset to the default state by POR or
+**	a hardware reset.
+**
+*/
+typedef union _SMC37c669_CR07 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned floppy_boot : 2;   /* 0 = A:, 1 = B:		    */
+	unsigned reserved1 : 2;	    /* RAZ			    */
+	unsigned ppt_en : 1;	    /* See note above		    */
+	unsigned uart1_en : 1;	    /* See note above		    */
+	unsigned uart2_en : 1;	    /* See note above		    */
+	unsigned fdc_en : 1;	    /* See note above		    */
+    }	by_field;
+} SMC37c669_CR07;
+
+/*
+** CR08 - default value 0x00
+*/
+typedef union _SMC37c669_CR08 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned zero : 4;	    /* 0			    */
+	unsigned addrx7_4 : 4;	    /* ADR<7:3> for ADRx decode	    */
+    }	by_field;
+} SMC37c669_CR08;
+
+/*
+** CR09 - default value 0x00
+**
+**  ADRx_CONFIG:
+**	00 - ADRx disabled
+**	01 - 1 byte decode A<3:0> = 0000b
+**	10 - 8 byte block decode A<3:0> = 0XXXb
+**	11 - 16 byte block decode A<3:0> = XXXXb
+**
+*/
+typedef union _SMC37c669_CR09 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned adra8 : 3;	    /* ADR<10:8> for ADRx decode    */
+	unsigned reserved1 : 3;
+	unsigned adrx_config : 2;   /* See note above		    */
+    }	by_field;
+} SMC37c669_CR09;
+
+/*
+** CR0A - default value 0x00
+*/
+typedef union _SMC37c669_CR0A {
+    unsigned char as_uchar;
+    struct {
+    	unsigned ecp_fifo_threshold : 4;
+	unsigned reserved1 : 4;
+    }	by_field;
+} SMC37c669_CR0A;
+
+/*
+** CR0B - default value 0x00
+*/
+typedef union _SMC37c669_CR0B {
+    unsigned char as_uchar;
+    struct {
+    	unsigned fdd0_drtx : 2;	    /* FDD0 Data Rate Table	    */
+	unsigned fdd1_drtx : 2;	    /* FDD1 Data Rate Table	    */
+	unsigned fdd2_drtx : 2;	    /* FDD2 Data Rate Table	    */
+	unsigned fdd3_drtx : 2;	    /* FDD3 Data Rate Table	    */
+    }	by_field;
+} SMC37c669_CR0B;
+
+/*
+** CR0C - default value 0x00
+**
+**  UART2_MODE:
+**	000 - Standard (default)
+**	001 - IrDA (HPSIR)
+**	010 - Amplitude Shift Keyed IR @500 KHz
+**	011 - Reserved
+**	1xx - Reserved
+**
+*/
+typedef union _SMC37c669_CR0C {
+    unsigned char as_uchar;
+    struct {
+    	unsigned uart2_rcv_polarity : 1;    /* 1 = invert RX		*/
+	unsigned uart2_xmit_polarity : 1;   /* 1 = invert TX		*/
+	unsigned uart2_duplex : 1;	    /* 1 = full, 0 = half	*/
+	unsigned uart2_mode : 3;	    /* See note above		*/
+	unsigned uart1_speed : 1;	    /* 1 = high speed enabled	*/
+	unsigned uart2_speed : 1;	    /* 1 = high speed enabled	*/
+    }	by_field;
+} SMC37c669_CR0C;
+
+/*
+** CR0D - default value 0x03
+**
+**  Device ID Register - read only
+*/
+typedef union _SMC37c669_CR0D {
+    unsigned char as_uchar;
+    struct {
+    	unsigned device_id : 8;	    /* Returns 0x3 in this field    */
+    }	by_field;
+} SMC37c669_CR0D;
+
+/*
+** CR0E - default value 0x02
+**
+**  Device Revision Register - read only
+*/
+typedef union _SMC37c669_CR0E {
+    unsigned char as_uchar;
+    struct {
+    	unsigned device_rev : 8;    /* Returns 0x2 in this field    */
+    }	by_field;
+} SMC37c669_CR0E;
+
+/*
+** CR0F - default value 0x00
+*/
+typedef union _SMC37c669_CR0F {
+    unsigned char as_uchar;
+    struct {
+    	unsigned test0 : 1;	    /* Reserved - set to 0	    */
+	unsigned test1 : 1;	    /* Reserved - set to 0	    */
+	unsigned test2 : 1;	    /* Reserved - set to 0	    */
+	unsigned test3 : 1;	    /* Reserved - set t0 0	    */
+	unsigned test4 : 1;	    /* Reserved - set to 0	    */
+	unsigned test5 : 1;	    /* Reserved - set t0 0	    */
+	unsigned test6 : 1;	    /* Reserved - set t0 0	    */
+	unsigned test7 : 1;	    /* Reserved - set to 0	    */
+    }	by_field;
+} SMC37c669_CR0F;
+
+/*
+** CR10 - default value 0x00
+*/
+typedef union _SMC37c669_CR10 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned reserved1 : 3;	     /* RAZ			    */
+	unsigned pll_gain : 1;	     /* 1 = 3V, 2 = 5V operation    */
+	unsigned pll_stop : 1;	     /* 1 = stop PLLs		    */
+	unsigned ace_stop : 1;	     /* 1 = stop UART clocks	    */
+	unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz  */
+	unsigned ir_test : 1;	     /* Enable IR test mode	    */
+    }	by_field;
+} SMC37c669_CR10;
+
+/*
+** CR11 - default value 0x00
+*/
+typedef union _SMC37c669_CR11 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned ir_loopback : 1;   /* Internal IR loop back		    */
+	unsigned test_10ms : 1;	    /* Test 10ms autopowerdown FDC timeout  */
+	unsigned reserved1 : 6;	    /* RAZ				    */
+    }	by_field;
+} SMC37c669_CR11;
+
+/*
+** CR12 - CR1D are reserved registers
+*/
+
+/*
+** CR1E - default value 0x80
+**
+**  GAMECS:
+**	00 - GAMECS disabled
+**	01 - 1 byte decode ADR<3:0> = 0001b
+**	10 - 8 byte block decode ADR<3:0> = 0XXXb
+**	11 - 16 byte block decode ADR<3:0> = XXXXb
+**
+*/
+typedef union _SMC37c66_CR1E {
+    unsigned char as_uchar;
+    struct {
+    	unsigned gamecs_config: 2;   /* See note above		    */
+	unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4>	    */
+    }	by_field;
+} SMC37c669_CR1E;
+
+/*
+** CR1F - default value 0x00
+**
+**  DT0 DT1 DRVDEN0 DRVDEN1 Drive Type
+**  --- --- ------- ------- ----------
+**   0   0  DENSEL  DRATE0  4/2/1 MB 3.5"
+**                          2/1 MB 5.25"
+**                          2/1.6/1 MB 3.5" (3-mode)
+**   0   1  DRATE1  DRATE0
+**   1   0  nDENSEL DRATE0  PS/2
+**   1   1  DRATE0  DRATE1
+**
+**  Note: DENSEL, DRATE1, and DRATE0 map onto two output
+**	  pins - DRVDEN0 and DRVDEN1.
+**
+*/
+typedef union _SMC37c669_CR1F {
+    unsigned char as_uchar;
+    struct {
+    	unsigned fdd0_drive_type : 2;	/* FDD0 drive type	    */
+	unsigned fdd1_drive_type : 2;	/* FDD1 drive type	    */
+	unsigned fdd2_drive_type : 2;	/* FDD2 drive type	    */
+	unsigned fdd3_drive_type : 2;	/* FDD3 drive type	    */
+    }	by_field;
+} SMC37c669_CR1F;
+
+/*
+** CR20 - default value 0x3C
+**
+**  FDC Base Address Register
+**	- To disable this decode set Addr<9:8> = 0
+**	- A<10> = 0, A<3:0> = 0XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR20 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned zero : 2;	    /* 0			    */
+	unsigned addr9_4 : 6;	    /* FDC Addr<9:4>		    */
+    }	by_field;
+} SMC37c669_CR20;
+
+/*
+** CR21 - default value 0x3C
+**
+**  IDE Base Address Register
+**	- To disable this decode set Addr<9:8> = 0
+**	- A<10> = 0, A<3:0> = 0XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR21 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned zero : 2;	    /* 0			    */
+	unsigned addr9_4 : 6;	    /* IDE Addr<9:4>		    */
+    }	by_field;
+} SMC37c669_CR21;
+
+/*
+** CR22 - default value 0x3D
+**
+**  IDE Alternate Status Base Address Register
+**	- To disable this decode set Addr<9:8> = 0
+**	- A<10> = 0, A<3:0> = 0110b to access.
+**
+*/
+typedef union _SMC37c669_CR22 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned zero : 2;	    /* 0			    */
+	unsigned addr9_4 : 6;	    /* IDE Alt Status Addr<9:4>	    */
+    }	by_field;
+} SMC37c669_CR22;
+
+/*
+** CR23 - default value 0x00
+**
+**  Parallel Port Base Address Register
+**	- To disable this decode set Addr<9:8> = 0
+**	- A<10> = 0 to access.
+**	- If EPP is enabled, A<2:0> = XXXb to access.
+**	  If EPP is NOT enabled, A<1:0> = XXb to access
+**
+*/
+typedef union _SMC37c669_CR23 {
+    unsigned char as_uchar;
+    struct {
+	unsigned addr9_2 : 8;	    /* Parallel Port Addr<9:2>	    */
+    }	by_field;
+} SMC37c669_CR23;
+
+/*
+** CR24 - default value 0x00
+**
+**  UART1 Base Address Register
+**	- To disable this decode set Addr<9:8> = 0
+**	- A<10> = 0, A<2:0> = XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR24 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned zero : 1;	    /* 0			    */
+	unsigned addr9_3 : 7;	    /* UART1 Addr<9:3>		    */
+    }	by_field;
+} SMC37c669_CR24;
+
+/*
+** CR25 - default value 0x00
+**
+**  UART2 Base Address Register
+**	- To disable this decode set Addr<9:8> = 0
+**	- A<10> = 0, A<2:0> = XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR25 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned zero : 1;	    /* 0			    */
+	unsigned addr9_3 : 7;	    /* UART2 Addr<9:3>		    */
+    }	by_field;
+} SMC37c669_CR25;
+
+/*
+** CR26 - default value 0x00
+**
+**  Parallel Port / FDC DMA Select Register
+**
+**  D3 - D0	  DMA
+**  D7 - D4	Selected
+**  -------	--------
+**   0000	 None
+**   0001	 DMA_A
+**   0010	 DMA_B
+**   0011	 DMA_C
+**
+*/
+typedef union _SMC37c669_CR26 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned ppt_drq : 4;	    /* See note above		    */
+	unsigned fdc_drq : 4;	    /* See note above		    */
+    }	by_field;
+} SMC37c669_CR26;
+
+/*
+** CR27 - default value 0x00
+**
+**  Parallel Port / FDC IRQ Select Register
+**
+**  D3 - D0	  IRQ
+**  D7 - D4	Selected
+**  -------	--------
+**   0000	 None
+**   0001	 IRQ_A
+**   0010	 IRQ_B
+**   0011	 IRQ_C
+**   0100	 IRQ_D
+**   0101	 IRQ_E
+**   0110	 IRQ_F
+**   0111	 Reserved
+**   1000	 IRQ_H
+**
+**  Any unselected IRQ REQ is in tristate
+**
+*/
+typedef union _SMC37c669_CR27 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned ppt_irq : 4;	    /* See note above		    */
+	unsigned fdc_irq : 4;	    /* See note above		    */
+    }	by_field;
+} SMC37c669_CR27;
+
+/*
+** CR28 - default value 0x00
+**
+**  UART IRQ Select Register
+**
+**  D3 - D0	  IRQ
+**  D7 - D4	Selected
+**  -------	--------
+**   0000	 None
+**   0001	 IRQ_A
+**   0010	 IRQ_B
+**   0011	 IRQ_C
+**   0100	 IRQ_D
+**   0101	 IRQ_E
+**   0110	 IRQ_F
+**   0111	 Reserved
+**   1000	 IRQ_H
+**   1111	 share with UART1 (only for UART2)
+**
+**  Any unselected IRQ REQ is in tristate
+**
+**  To share an IRQ between UART1 and UART2, set
+**  UART1 to use the desired IRQ and set UART2 to
+**  0xF to enable sharing mechanism.
+**
+*/
+typedef union _SMC37c669_CR28 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned uart2_irq : 4;	    /* See note above		    */
+	unsigned uart1_irq : 4;	    /* See note above		    */
+    }	by_field;
+} SMC37c669_CR28;
+
+/*
+** CR29 - default value 0x00
+**
+**  IRQIN IRQ Select Register
+**
+**  D3 - D0	  IRQ
+**  D7 - D4	Selected
+**  -------	--------
+**   0000	 None
+**   0001	 IRQ_A
+**   0010	 IRQ_B
+**   0011	 IRQ_C
+**   0100	 IRQ_D
+**   0101	 IRQ_E
+**   0110	 IRQ_F
+**   0111	 Reserved
+**   1000	 IRQ_H
+**
+**  Any unselected IRQ REQ is in tristate
+**
+*/
+typedef union _SMC37c669_CR29 {
+    unsigned char as_uchar;
+    struct {
+    	unsigned irqin_irq : 4;	    /* See note above		    */
+	unsigned reserved1 : 4;	    /* RAZ			    */
+    }	by_field;
+} SMC37c669_CR29;
+
+/*
+** Aliases of Configuration Register formats (should match
+** the set of index aliases).
+**
+** Note that CR24 and CR25 have the same format and are the
+** base address registers for UART1 and UART2.  Because of
+** this we only define 1 alias here - for CR24 - as the serial
+** base address register.
+**
+** Note that CR21 and CR22 have the same format and are the
+** base address and alternate status address registers for
+** the IDE controller.  Because of this we only define 1 alias
+** here - for CR21 - as the IDE address register.
+**
+*/
+typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER;
+typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER;
+typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER;
+typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER;
+typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER;
+typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER;
+
+/*
+** ISA/Device IRQ Translation Table Entry Definition
+*/
+typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY {
+    int device_irq;
+    int isa_irq;
+} SMC37c669_IRQ_TRANSLATION_ENTRY;
+
+/*
+** ISA/Device DMA Translation Table Entry Definition
+*/
+typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY {
+    int device_drq;
+    int isa_drq;
+} SMC37c669_DRQ_TRANSLATION_ENTRY;
+
+/*
+** External Interface Function Prototype Declarations
+*/
+
+SMC37c669_CONFIG_REGS *SMC37c669_detect( 
+    void 
+);
+
+unsigned int SMC37c669_enable_device( 
+    unsigned int func 
+);
+
+unsigned int SMC37c669_disable_device( 
+    unsigned int func 
+);
+
+unsigned int SMC37c669_configure_device( 
+    unsigned int func, 
+    int port, 
+    int irq, 
+    int drq 
+);
+
+void SMC37c669_display_device_info( 
+    void 
+);
+
+#endif	/* __SMC37c669_H */
+
+/* file:	smcc669.c
+ *
+ * Copyright (C) 1997 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  of  the  terms  of  such  license  and with the
+ * inclusion of the above copyright notice. This software or  any  other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ * The information in this software is  subject to change without notice
+ * and  should  not  be  construed  as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use  or  reliability of its
+ * software on equipment which is not supplied by digital.
+ */
+
+/*
+ *++
+ *  FACILITY:
+ *
+ *      Alpha SRM Console Firmware
+ *
+ *  MODULE DESCRIPTION:
+ *
+ *	SMC37c669 Super I/O controller configuration routines.
+ *
+ *  AUTHORS:
+ *
+ *	Eric Rasmussen
+ *
+ *  CREATION DATE:
+ *  
+ *	28-Jan-1997
+ *
+ *  MODIFICATION HISTORY:
+ *	
+ *	er	01-May-1997	Fixed pointer conversion errors in 
+ *				SMC37c669_get_device_config().
+ *      er	28-Jan-1997	Initial version.
+ *
+ *--
+ */
+#if 0
+/* $INCLUDE_OPTIONS$ */
+#include    "cp$inc:platform_io.h"
+/* $INCLUDE_OPTIONS_END$ */
+#include    "cp$src:common.h"
+#include    "cp$inc:prototypes.h"
+#include    "cp$src:kernel_def.h"
+#include    "cp$src:msg_def.h"
+#include    "cp$src:smcc669_def.h"
+/* Platform-specific includes */
+#include    "cp$src:platform.h"
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define wb( _x_, _y_ )	outb( _y_, (unsigned int)((unsigned long)_x_) )
+#define rb( _x_ )	inb( (unsigned int)((unsigned long)_x_) )
+
+/*
+** Local storage for device configuration information.
+**
+** Since the SMC37c669 does not provide an explicit
+** mechanism for enabling/disabling individual device 
+** functions, other than unmapping the device, local 
+** storage for device configuration information is 
+** allocated here for use in implementing our own 
+** function enable/disable scheme.
+*/
+static struct DEVICE_CONFIG {
+    unsigned int port1;
+    unsigned int port2;
+    unsigned int irq;
+    unsigned int drq;
+} local_config [NUM_FUNCS];
+
+/*
+** List of all possible addresses for the Super I/O chip
+*/
+static unsigned long SMC37c669_Addresses[] =
+    {
+	0x3F0UL,	    /* Primary address	    */
+	0x370UL,	    /* Secondary address    */
+	0UL		    /* End of list	    */
+    };
+
+/*
+** Global Pointer to the Super I/O device
+*/
+static SMC37c669_CONFIG_REGS *SMC37c669 = NULL;
+
+/*
+** IRQ Translation Table
+**
+** The IRQ translation table is a list of SMC37c669 device 
+** and standard ISA IRQs.
+**
+*/
+static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table; 
+
+/*
+** The following definition is for the default IRQ 
+** translation table.
+*/
+static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[ ] = 
+    { 
+	{ SMC37c669_DEVICE_IRQ_A, -1 }, 
+	{ SMC37c669_DEVICE_IRQ_B, -1 }, 
+	{ SMC37c669_DEVICE_IRQ_C, 7 }, 
+	{ SMC37c669_DEVICE_IRQ_D, 6 }, 
+	{ SMC37c669_DEVICE_IRQ_E, 4 }, 
+	{ SMC37c669_DEVICE_IRQ_F, 3 }, 
+	{ SMC37c669_DEVICE_IRQ_H, -1 }, 
+	{ -1, -1 } /* End of table */
+    };
+
+/*
+** DRQ Translation Table
+**
+** The DRQ translation table is a list of SMC37c669 device and
+** ISA DMA channels.
+**
+*/
+static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table; 
+
+/*
+** The following definition is the default DRQ
+** translation table.
+*/
+static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[ ] = 
+    { 
+	{ SMC37c669_DEVICE_DRQ_A, 2 }, 
+	{ SMC37c669_DEVICE_DRQ_B, 3 }, 
+	{ SMC37c669_DEVICE_DRQ_C, -1 }, 
+	{ -1, -1 } /* End of table */
+    };
+
+/*
+** Local Function Prototype Declarations
+*/
+
+static unsigned int SMC37c669_is_device_enabled( 
+    unsigned int func 
+);
+
+#if 0
+static unsigned int SMC37c669_get_device_config( 
+    unsigned int func, 
+    int *port, 
+    int *irq, 
+    int *drq 
+);
+#endif
+
+static void SMC37c669_config_mode( 
+    unsigned int enable 
+);
+
+static unsigned char SMC37c669_read_config( 
+    unsigned char index 
+);
+
+static void SMC37c669_write_config( 
+    unsigned char index, 
+    unsigned char data 
+);
+
+static void SMC37c669_init_local_config( void );
+
+static struct DEVICE_CONFIG *SMC37c669_get_config(
+    unsigned int func
+);
+
+static int SMC37c669_xlate_irq(
+    unsigned int irq 
+);
+
+static int SMC37c669_xlate_drq(
+    unsigned int drq 
+);
+
+#if 0
+/*
+** External Data Declarations
+*/
+
+extern struct LOCK spl_atomic;
+
+/*
+** External Function Prototype Declarations
+*/
+
+/* From kernel_alpha.mar */
+extern spinlock( 
+    struct LOCK *spl 
+);
+
+extern spinunlock( 
+    struct LOCK *spl 
+);
+
+/* From filesys.c */
+int allocinode(
+    char *name, 
+    int can_create, 
+    struct INODE **ipp
+);
+
+extern int null_procedure( void );
+
+int smcc669_init( void );
+int smcc669_open( struct FILE *fp, char *info, char *next, char *mode );
+int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf );
+int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf );
+int smcc669_close( struct FILE *fp );
+
+struct DDB smc_ddb = {
+	"smc",			/* how this routine wants to be called	*/
+	smcc669_read,		/* read routine				*/
+	smcc669_write,		/* write routine			*/
+	smcc669_open,		/* open routine				*/
+	smcc669_close,		/* close routine			*/
+	null_procedure,		/* name expansion routine		*/
+	null_procedure,		/* delete routine			*/
+	null_procedure,		/* create routine			*/
+	null_procedure,		/* setmode				*/
+	null_procedure,		/* validation routine			*/
+	0,			/* class specific use			*/
+	1,			/* allows information			*/
+	0,			/* must be stacked			*/
+	0,			/* is a flash update driver		*/
+	0,			/* is a block device			*/
+	0,			/* not seekable				*/
+	0,			/* is an ethernet device		*/
+	0,			/* is a filesystem driver		*/
+};
+#endif
+
+#define spinlock(x)
+#define spinunlock(x)
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function detects the presence of an SMC37c669 Super I/O
+**	controller.
+**
+**  FORMAL PARAMETERS:
+**
+**	None
+**
+**  RETURN VALUE:
+**
+**      Returns a pointer to the device if found, otherwise,
+**	the NULL pointer is returned.
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+SMC37c669_CONFIG_REGS *SMC37c669_detect( void )
+{
+    int i;
+    SMC37c669_DEVICE_ID_REGISTER id;
+
+    for ( i = 0;  SMC37c669_Addresses[i] != 0;  i++ ) {
+/*
+** Initialize the device pointer even though we don't yet know if
+** the controller is at this address.  The support functions access
+** the controller through this device pointer so we need to set it
+** even when we are looking ...
+*/
+    	SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i];
+/*
+** Enter configuration mode
+*/
+	SMC37c669_config_mode( TRUE );
+/*
+** Read the device id
+*/
+	id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX );
+/*
+** Exit configuration mode
+*/
+	SMC37c669_config_mode( FALSE );
+/*
+** Does the device id match?  If so, assume we have found an
+** SMC37c669 controller at this address.
+*/
+	if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) {
+/*
+** Initialize the IRQ and DRQ translation tables.
+*/
+    	    SMC37c669_irq_table = SMC37c669_default_irq_table;
+	    SMC37c669_drq_table = SMC37c669_default_drq_table;
+/*
+** erfix
+**
+** If the platform can't use the IRQ and DRQ defaults set up in this 
+** file, it should call a platform-specific external routine at this 
+** point to reset the IRQ and DRQ translation table pointers to point 
+** at the appropriate tables for the platform.  If the defaults are 
+** acceptable, then the external routine should do nothing.
+*/
+
+/*
+** Put the chip back into configuration mode
+*/
+	    SMC37c669_config_mode( TRUE );
+/*
+** Initialize local storage for configuration information
+*/
+	    SMC37c669_init_local_config( );
+/*
+** Exit configuration mode
+*/
+	    SMC37c669_config_mode( FALSE );
+/*
+** SMC37c669 controller found, break out of search loop
+*/
+	    break;
+	}
+	else {
+/*
+** Otherwise, we did not find an SMC37c669 controller at this
+** address so set the device pointer to NULL.
+*/
+	    SMC37c669 = NULL;
+	}
+    }
+    return SMC37c669;
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function enables an SMC37c669 device function.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function to enable
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE is the device function was enabled, otherwise, FALSE
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**      Enabling a device function in the SMC37c669 controller involves
+**	setting all of its mappings (port, irq, drq ...).  A local 
+**	"shadow" copy of the device configuration is kept so we can
+**	just set each mapping to what the local copy says.
+**
+**	This function ALWAYS updates the local shadow configuration of
+**	the device function being enabled, even if the device is always
+**	enabled.  To avoid replication of code, functions such as
+**	configure_device set up the local copy and then call this 
+**	function to the update the real device.
+**
+**--
+*/
+unsigned int SMC37c669_enable_device ( unsigned int func )
+{
+    unsigned int ret_val = FALSE;
+/*
+** Put the device into configuration mode
+*/
+    SMC37c669_config_mode( TRUE );
+    switch ( func ) {
+    	case SERIAL_0:
+	    {
+	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Enable the serial 1 IRQ mapping
+*/
+	    	irq.as_uchar = 
+		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+		irq.by_field.uart1_irq =
+		    SMC37c669_RAW_DEVICE_IRQ(
+			SMC37c669_xlate_irq( local_config[ func ].irq )
+		    );
+
+		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Enable the serial 1 port base address mapping
+*/
+		base_addr.as_uchar = 0;
+		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
+
+		SMC37c669_write_config( 
+		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case SERIAL_1:
+	    {
+	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Enable the serial 2 IRQ mapping
+*/
+	    	irq.as_uchar = 
+		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+		irq.by_field.uart2_irq =
+		    SMC37c669_RAW_DEVICE_IRQ(
+			SMC37c669_xlate_irq( local_config[ func ].irq )
+		    );
+
+		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Enable the serial 2 port base address mapping
+*/
+		base_addr.as_uchar = 0;
+		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
+
+		SMC37c669_write_config( 
+		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case PARALLEL_0:
+	    {
+	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Enable the parallel port DMA channel mapping
+*/
+	    	drq.as_uchar =
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+		drq.by_field.ppt_drq = 
+		    SMC37c669_RAW_DEVICE_DRQ(
+			SMC37c669_xlate_drq( local_config[ func ].drq )
+		    );
+
+		SMC37c669_write_config(
+		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+		    drq.as_uchar
+		);
+/*
+** Enable the parallel port IRQ mapping
+*/
+		irq.as_uchar = 
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+		irq.by_field.ppt_irq =
+		    SMC37c669_RAW_DEVICE_IRQ(
+			SMC37c669_xlate_irq( local_config[ func ].irq )
+		    );
+
+		SMC37c669_write_config( 
+		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+		    irq.as_uchar
+		);
+/*
+** Enable the parallel port base address mapping
+*/
+		base_addr.as_uchar = 0;
+		base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2;
+
+		SMC37c669_write_config(
+		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case FLOPPY_0:
+	    {
+	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Enable the floppy controller DMA channel mapping
+*/
+	    	drq.as_uchar =
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+		 
+		drq.by_field.fdc_drq =
+		    SMC37c669_RAW_DEVICE_DRQ(
+			SMC37c669_xlate_drq( local_config[ func ].drq )
+		    );
+		 
+		SMC37c669_write_config( 
+		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+		    drq.as_uchar
+		);
+/*
+** Enable the floppy controller IRQ mapping
+*/
+		irq.as_uchar =
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+		 
+		irq.by_field.fdc_irq =
+		    SMC37c669_RAW_DEVICE_IRQ(
+			SMC37c669_xlate_irq( local_config[ func ].irq )
+		    );
+		 
+		SMC37c669_write_config(
+		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+		    irq.as_uchar
+		);
+/*
+** Enable the floppy controller base address mapping
+*/
+		base_addr.as_uchar = 0;
+		base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
+		 
+		SMC37c669_write_config(
+		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case IDE_0:
+	    {
+	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
+/*
+** Enable the IDE alternate status base address mapping
+*/
+	    	ide_addr.as_uchar = 0;
+		ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4;
+		 
+		SMC37c669_write_config(
+		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
+		    ide_addr.as_uchar
+		);
+/*
+** Enable the IDE controller base address mapping
+*/
+		ide_addr.as_uchar = 0;
+		ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
+		 
+		SMC37c669_write_config(
+		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
+		    ide_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+    }
+/*
+** Exit configuration mode and return
+*/
+    SMC37c669_config_mode( FALSE );
+
+    return ret_val;
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function disables a device function within the
+**	SMC37c669 Super I/O controller.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which function to disable
+**
+**  RETURN VALUE:
+**
+**      Return TRUE if the device function was disabled, otherwise, FALSE
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**      Disabling a function in the SMC37c669 device involves
+**	disabling all the function's mappings (port, irq, drq ...).
+**	A shadow copy of the device configuration is maintained
+**	in local storage so we won't worry aboving saving the
+**	current configuration information.
+**
+**--
+*/
+unsigned int SMC37c669_disable_device ( unsigned int func )
+{
+    unsigned int ret_val = FALSE;
+
+/*
+** Put the device into configuration mode
+*/
+    SMC37c669_config_mode( TRUE );
+    switch ( func ) {
+    	case SERIAL_0:
+	    {
+	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Disable the serial 1 IRQ mapping
+*/
+	    	irq.as_uchar = 
+		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+		irq.by_field.uart1_irq = 0;
+
+		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Disable the serial 1 port base address mapping
+*/
+		base_addr.as_uchar = 0;
+		SMC37c669_write_config( 
+		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case SERIAL_1:
+	    {
+	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Disable the serial 2 IRQ mapping
+*/
+	    	irq.as_uchar = 
+		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+		irq.by_field.uart2_irq = 0;
+
+		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Disable the serial 2 port base address mapping
+*/
+		base_addr.as_uchar = 0;
+
+		SMC37c669_write_config( 
+		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case PARALLEL_0:
+	    {
+	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Disable the parallel port DMA channel mapping
+*/
+	    	drq.as_uchar =
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+		drq.by_field.ppt_drq = 0;
+
+		SMC37c669_write_config(
+		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+		    drq.as_uchar
+		);
+/*
+** Disable the parallel port IRQ mapping
+*/
+		irq.as_uchar = 
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+		irq.by_field.ppt_irq = 0;
+
+		SMC37c669_write_config( 
+		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+		    irq.as_uchar
+		);
+/*
+** Disable the parallel port base address mapping
+*/
+		base_addr.as_uchar = 0;
+
+		SMC37c669_write_config(
+		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case FLOPPY_0:
+	    {
+	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
+		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Disable the floppy controller DMA channel mapping
+*/
+	    	drq.as_uchar =
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+		 
+		drq.by_field.fdc_drq = 0;
+		 
+		SMC37c669_write_config( 
+		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+		    drq.as_uchar
+		);
+/*
+** Disable the floppy controller IRQ mapping
+*/
+		irq.as_uchar =
+		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+		 
+		irq.by_field.fdc_irq = 0;
+		 
+		SMC37c669_write_config(
+		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+		    irq.as_uchar
+		);
+/*
+** Disable the floppy controller base address mapping
+*/
+		base_addr.as_uchar = 0;
+		 
+		SMC37c669_write_config(
+		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
+		    base_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+	case IDE_0:
+	    {
+	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
+/*
+** Disable the IDE alternate status base address mapping
+*/
+	    	ide_addr.as_uchar = 0;
+		 
+		SMC37c669_write_config(
+		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
+		    ide_addr.as_uchar
+		);
+/*
+** Disable the IDE controller base address mapping
+*/
+		ide_addr.as_uchar = 0;
+		 
+		SMC37c669_write_config(
+		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
+		    ide_addr.as_uchar
+		);
+		ret_val = TRUE;
+		break;
+	    }
+    }
+/*
+** Exit configuration mode and return
+*/
+    SMC37c669_config_mode( FALSE );
+
+    return ret_val;
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function configures a device function within the 
+**	SMC37c669 Super I/O controller.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**       
+**      port:
+**          I/O port for the function to use
+**	 
+**      irq:
+**          IRQ for the device function to use
+**	 
+**      drq:
+**          DMA channel for the device function to use
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE if the device function was configured, 
+**	otherwise, FALSE.
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**	If this function returns TRUE, the local shadow copy of
+**	the configuration is also updated.  If the device function
+**	is currently disabled, only the local shadow copy is 
+**	updated and the actual device function will be updated
+**	if/when is is enabled.
+**
+**--
+*/
+unsigned int SMC37c669_configure_device (
+    unsigned int func,
+    int port,
+    int irq,
+    int drq )
+{
+    struct DEVICE_CONFIG *cp;
+
+/*
+** Check for a valid configuration
+*/
+    if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) {
+/*
+** Configuration is valid, update the local shadow copy
+*/
+    	if ( ( drq & ~0xFF ) == 0 ) {
+	    cp->drq = drq;
+	}
+	if ( ( irq & ~0xFF ) == 0 ) {
+	    cp->irq = irq;
+	}
+	if ( ( port & ~0xFFFF ) == 0 ) {
+	    cp->port1 = port;
+	}
+/*
+** If the device function is enabled, update the actual
+** device configuration.
+*/
+	if ( SMC37c669_is_device_enabled( func ) ) {
+	    SMC37c669_enable_device( func );
+	}
+	return TRUE;
+    }
+    return FALSE;
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function determines whether a device function
+**	within the SMC37c669 controller is enabled.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE if the device function is enabled, otherwise, FALSE
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**      To check whether a device is enabled we will only look at 
+**	the port base address mapping.  According to the SMC37c669
+**	specification, all of the port base address mappings are
+**	disabled if the addr<9:8> (bits <7:6> of the register) are
+**	zero.
+**
+**--
+*/
+static unsigned int SMC37c669_is_device_enabled ( unsigned int func )
+{
+    unsigned char base_addr = 0;
+    unsigned int dev_ok = FALSE;
+    unsigned int ret_val = FALSE;
+/*
+** Enter configuration mode
+*/
+    SMC37c669_config_mode( TRUE );
+     
+    switch ( func ) {
+    	case SERIAL_0:
+	    base_addr =
+		SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
+	    dev_ok = TRUE;
+	    break;
+	case SERIAL_1:
+	    base_addr =
+		SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
+	    dev_ok = TRUE;
+	    break;
+	case PARALLEL_0:
+	    base_addr =
+		SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
+	    dev_ok = TRUE;
+	    break;
+	case FLOPPY_0:
+	    base_addr =
+		SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
+	    dev_ok = TRUE;
+	    break;
+	case IDE_0:
+	    base_addr =
+		SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
+	    dev_ok = TRUE;
+	    break;
+    }
+/*
+** If we have a valid device, check base_addr<7:6> to see if the
+** device is enabled (mapped).
+*/
+    if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) {
+/*
+** The mapping is not disabled, so assume that the function is 
+** enabled.
+*/
+    	ret_val = TRUE;
+    }
+/*
+** Exit configuration mode 
+*/
+    SMC37c669_config_mode( FALSE );
+
+    return ret_val;
+}
+
+
+#if 0
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function retrieves the configuration information of a 
+**	device function within the SMC37c699 Super I/O controller.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**       
+**      port:
+**          I/O port returned
+**	 
+**      irq:
+**          IRQ returned
+**	 
+**      drq:
+**          DMA channel returned
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE if the device configuration was successfully
+**	retrieved, otherwise, FALSE.
+**
+**  SIDE EFFECTS:
+**
+**      The data pointed to by the port, irq, and drq parameters
+**	my be modified even if the configuration is not successfully
+**	retrieved.
+**
+**  DESIGN:
+**
+**      The device configuration is fetched from the local shadow
+**	copy.  Any unused parameters will be set to -1.  Any
+**	parameter which is not desired can specify the NULL
+**	pointer.
+**
+**--
+*/
+static unsigned int SMC37c669_get_device_config (
+    unsigned int func,
+    int *port,
+    int *irq,
+    int *drq )
+{
+    struct DEVICE_CONFIG *cp;
+    unsigned int ret_val = FALSE;
+/*
+** Check for a valid device configuration
+*/
+    if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) {
+    	if ( drq != NULL ) {
+	    *drq = cp->drq;
+	    ret_val = TRUE;
+	}
+	if ( irq != NULL ) {
+	    *irq = cp->irq;
+	    ret_val = TRUE;
+	}
+	if ( port != NULL ) {
+	    *port = cp->port1;
+	    ret_val = TRUE;
+	}
+    }
+    return ret_val;
+}
+#endif
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function displays the current state of the SMC37c699
+**	Super I/O controller's device functions.
+**
+**  FORMAL PARAMETERS:
+**
+**      None
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+void SMC37c669_display_device_info ( void )
+{
+    if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) {
+    	printk( "  Serial 0:    Enabled [ Port 0x%x, IRQ %d ]\n",
+		 local_config[ SERIAL_0 ].port1,
+		 local_config[ SERIAL_0 ].irq
+	);
+    }
+    else {
+    	printk( "  Serial 0:    Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) {
+    	printk( "  Serial 1:    Enabled [ Port 0x%x, IRQ %d ]\n",
+		 local_config[ SERIAL_1 ].port1,
+		 local_config[ SERIAL_1 ].irq
+	);
+    }
+    else {
+    	printk( "  Serial 1:    Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) {
+    	printk( "  Parallel:    Enabled [ Port 0x%x, IRQ %d/%d ]\n",
+		 local_config[ PARALLEL_0 ].port1,
+		 local_config[ PARALLEL_0 ].irq,
+		 local_config[ PARALLEL_0 ].drq
+	);
+    }
+    else {
+    	printk( "  Parallel:    Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) {
+    	printk( "  Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n",
+		 local_config[ FLOPPY_0 ].port1,
+		 local_config[ FLOPPY_0 ].irq,
+		 local_config[ FLOPPY_0 ].drq
+	);
+    }
+    else {
+    	printk( "  Floppy Ctrl: Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( IDE_0 ) ) {
+    	printk( "  IDE 0:       Enabled [ Port 0x%x, IRQ %d ]\n",
+		 local_config[ IDE_0 ].port1,
+		 local_config[ IDE_0 ].irq
+	);
+    }
+    else {
+    	printk( "  IDE 0:       Disabled\n" );
+    }
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function puts the SMC37c669 Super I/O controller into,
+**	and takes it out of, configuration mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      enable:
+**          TRUE to enter configuration mode, FALSE to exit.
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      The SMC37c669 controller may be left in configuration mode.
+**
+**--
+*/
+static void SMC37c669_config_mode( 
+    unsigned int enable )
+{
+    if ( enable ) {
+/*
+** To enter configuration mode, two writes in succession to the index
+** port are required.  If a write to another address or port occurs
+** between these two writes, the chip does not enter configuration
+** mode.  Therefore, a spinlock is placed around the two writes to 
+** guarantee that they complete uninterrupted.
+*/
+	spinlock( &spl_atomic );
+    	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
+    	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
+	spinunlock( &spl_atomic );
+    }
+    else {
+    	wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY );
+    }
+}
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function reads an SMC37c669 Super I/O controller
+**	configuration register.  This function assumes that the
+**	device is already in configuration mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      index:
+**          Index value of configuration register to read
+**
+**  RETURN VALUE:
+**
+**      Data read from configuration register
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+static unsigned char SMC37c669_read_config( 
+    unsigned char index )
+{
+    unsigned char data;
+
+    wb( &SMC37c669->index_port, index );
+    data = rb( &SMC37c669->data_port );
+    return data;
+}
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function writes an SMC37c669 Super I/O controller
+**	configuration register.  This function assumes that the
+**	device is already in configuration mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      index:
+**          Index of configuration register to write
+**       
+**      data:
+**          Data to be written
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+static void SMC37c669_write_config( 
+    unsigned char index, 
+    unsigned char data )
+{
+    wb( &SMC37c669->index_port, index );
+    wb( &SMC37c669->data_port, data );
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function initializes the local device
+**	configuration storage.  This function assumes
+**	that the device is already in configuration
+**	mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      None
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      Local storage for device configuration information
+**	is initialized.
+**
+**--
+*/
+static void SMC37c669_init_local_config ( void )
+{
+    SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base;
+    SMC37c669_SERIAL_IRQ_REGISTER uart_irqs;
+    SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base;
+    SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs;
+    SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs;
+    SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base;
+    SMC37c669_IDE_ADDRESS_REGISTER ide_base;
+    SMC37c669_IDE_ADDRESS_REGISTER ide_alt;
+
+/*
+** Get serial port 1 base address 
+*/
+    uart_base.as_uchar = 
+	SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
+/*
+** Get IRQs for serial ports 1 & 2
+*/
+    uart_irqs.as_uchar = 
+	SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+/*
+** Store local configuration information for serial port 1
+*/
+    local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3;
+    local_config[SERIAL_0].irq = 
+	SMC37c669_xlate_irq( 
+	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq ) 
+	);
+/*
+** Get serial port 2 base address
+*/
+    uart_base.as_uchar = 
+	SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
+/*
+** Store local configuration information for serial port 2
+*/
+    local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3;
+    local_config[SERIAL_1].irq = 
+	SMC37c669_xlate_irq( 
+	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq ) 
+	);
+/*
+** Get parallel port base address
+*/
+    ppt_base.as_uchar =
+	SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
+/*
+** Get IRQs for parallel port and floppy controller
+*/
+    ppt_fdc_irqs.as_uchar =
+	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+/*
+** Get DRQs for parallel port and floppy controller
+*/
+    ppt_fdc_drqs.as_uchar =
+	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+/*
+** Store local configuration information for parallel port
+*/
+    local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2;
+    local_config[PARALLEL_0].irq =
+	SMC37c669_xlate_irq(
+	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq )
+	);
+    local_config[PARALLEL_0].drq =
+	SMC37c669_xlate_drq(
+	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq )
+	);
+/*
+** Get floppy controller base address
+*/
+    fdc_base.as_uchar = 
+	SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
+/*
+** Store local configuration information for floppy controller
+*/
+    local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4;
+    local_config[FLOPPY_0].irq =
+	SMC37c669_xlate_irq(
+	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq )
+	);
+    local_config[FLOPPY_0].drq =
+	SMC37c669_xlate_drq(
+	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq )
+	);
+/*
+** Get IDE controller base address
+*/
+    ide_base.as_uchar =
+	SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
+/*
+** Get IDE alternate status base address
+*/
+    ide_alt.as_uchar =
+	SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX );
+/*
+** Store local configuration information for IDE controller
+*/
+    local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4;
+    local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4;
+    local_config[IDE_0].irq = 14;
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function returns a pointer to the local shadow
+**	configuration of the requested device function.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**
+**  RETURN VALUE:
+**
+**      Returns a pointer to the DEVICE_CONFIG structure for the
+**	requested function, otherwise, NULL.
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**--
+*/
+static struct DEVICE_CONFIG *SMC37c669_get_config( unsigned int func )
+{
+    struct DEVICE_CONFIG *cp = NULL;
+
+    switch ( func ) {
+    	case SERIAL_0:
+	    cp = &local_config[ SERIAL_0 ];
+	    break;
+	case SERIAL_1:
+	    cp = &local_config[ SERIAL_1 ];
+	    break;
+	case PARALLEL_0:
+	    cp = &local_config[ PARALLEL_0 ];
+	    break;
+	case FLOPPY_0:
+	    cp = &local_config[ FLOPPY_0 ];
+	    break;
+	case IDE_0:
+	    cp = &local_config[ IDE_0 ];
+	    break;
+    }
+    return cp;
+}
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function translates IRQs back and forth between ISA
+**	IRQs and SMC37c669 device IRQs.
+**
+**  FORMAL PARAMETERS:
+**
+**      irq:
+**          The IRQ to translate
+**
+**  RETURN VALUE:
+**
+**      Returns the translated IRQ, otherwise, returns -1.
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**--
+*/
+static int SMC37c669_xlate_irq ( unsigned int irq )
+{
+    int i, translated_irq = -1;
+
+    if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) {
+/*
+** We are translating a device IRQ to an ISA IRQ
+*/
+    	for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) {
+	    if ( irq == SMC37c669_irq_table[i].device_irq ) {
+	    	translated_irq = SMC37c669_irq_table[i].isa_irq;
+		break;
+	    }
+	}
+    }
+    else {
+/*
+** We are translating an ISA IRQ to a device IRQ
+*/
+    	for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) {
+	    if ( irq == SMC37c669_irq_table[i].isa_irq ) {
+	    	translated_irq = SMC37c669_irq_table[i].device_irq;
+		break;
+	    }
+	}
+    }
+    return translated_irq;
+}
+
+
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function translates DMA channels back and forth between
+**	ISA DMA channels and SMC37c669 device DMA channels.
+**
+**  FORMAL PARAMETERS:
+**
+**      drq:
+**          The DMA channel to translate
+**
+**  RETURN VALUE:
+**
+**      Returns the translated DMA channel, otherwise, returns -1
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**--
+*/
+static int SMC37c669_xlate_drq ( unsigned int drq )
+{
+    int i, translated_drq = -1;
+
+    if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) {
+/*
+** We are translating a device DMA channel to an ISA DMA channel
+*/
+    	for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) {
+	    if ( drq == SMC37c669_drq_table[i].device_drq ) {
+	    	translated_drq = SMC37c669_drq_table[i].isa_drq;
+		break;
+	    }
+	}
+    }
+    else {
+/*
+** We are translating an ISA DMA channel to a device DMA channel
+*/
+    	for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) {
+	    if ( drq == SMC37c669_drq_table[i].isa_drq ) {
+	    	translated_drq = SMC37c669_drq_table[i].device_drq;
+		break;
+	    }
+	}
+    }
+    return translated_drq;
+}
+
+#if 0
+int smcc669_init ( void )
+{
+    struct INODE *ip;
+
+    allocinode( smc_ddb.name, 1, &ip );
+    ip->dva = &smc_ddb;
+    ip->attr = ATTR$M_WRITE | ATTR$M_READ;
+    ip->len[0] = 0x30;
+    ip->misc = 0;
+    INODE_UNLOCK( ip );
+
+    return msg_success;
+}
+
+int smcc669_open( struct FILE *fp, char *info, char *next, char *mode )
+{
+    struct INODE *ip;
+/*
+** Allow multiple readers but only one writer.  ip->misc keeps track
+** of the number of writers
+*/
+    ip = fp->ip;
+    INODE_LOCK( ip );
+    if ( fp->mode & ATTR$M_WRITE ) {
+	if ( ip->misc ) {
+	    INODE_UNLOCK( ip );
+	    return msg_failure;	    /* too many writers */
+	}
+	ip->misc++;
+    }
+/*
+** Treat the information field as a byte offset
+*/
+    *fp->offset = xtoi( info );
+    INODE_UNLOCK( ip );
+
+    return msg_success;
+}
+
+int smcc669_close( struct FILE *fp )
+{
+    struct INODE *ip;
+
+    ip = fp->ip;
+    if ( fp->mode & ATTR$M_WRITE ) {
+	INODE_LOCK( ip );
+	ip->misc--;
+	INODE_UNLOCK( ip );
+    }
+    return msg_success;
+}
+
+int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf )
+{
+    int i;
+    int length;
+    int nbytes;
+    struct INODE *ip;
+
+/*
+** Always access a byte at a time
+*/
+    ip = fp->ip;
+    length = size * number;
+    nbytes = 0;
+
+    SMC37c669_config_mode( TRUE );
+    for ( i = 0; i < length; i++ ) {
+	if ( !inrange( *fp->offset, 0, ip->len[0] ) ) 
+	    break;
+	*buf++ = SMC37c669_read_config( *fp->offset );
+	*fp->offset += 1;
+	nbytes++;
+    }
+    SMC37c669_config_mode( FALSE );
+    return nbytes;
+}
+
+int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf )
+{
+    int i;
+    int length;
+    int nbytes;
+    struct INODE *ip;
+/*
+** Always access a byte at a time
+*/
+    ip = fp->ip;
+    length = size * number;
+    nbytes = 0;
+
+    SMC37c669_config_mode( TRUE );
+    for ( i = 0; i < length; i++ ) {
+	if ( !inrange( *fp->offset, 0, ip->len[0] ) ) 
+	    break;
+	SMC37c669_write_config( *fp->offset, *buf );
+	*fp->offset += 1;
+	buf++;
+	nbytes++;
+    }
+    SMC37c669_config_mode( FALSE );
+    return nbytes;
+}
+#endif
+
+void
+SMC37c669_dump_registers(void)
+{
+  int i;
+  for (i = 0; i <= 0x29; i++)
+    printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i));
+}
+/*+
+ * ============================================================================
+ * = SMC_init - SMC37c669 Super I/O controller initialization                 =
+ * ============================================================================
+ *
+ * OVERVIEW:
+ *
+ *      This routine configures and enables device functions on the
+ *      SMC37c669 Super I/O controller.
+ *
+ * FORM OF CALL:
+ *
+ *      SMC_init( );
+ *
+ * RETURNS:
+ *
+ *      Nothing
+ *
+ * ARGUMENTS:
+ *
+ *      None
+ *
+ * SIDE EFFECTS:
+ *
+ *      None
+ *
+-*/
+void SMC669_Init ( void )
+{
+    SMC37c669_CONFIG_REGS *SMC_base;
+
+    if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) {
+        printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n",
+		(unsigned long) SMC_base );
+#if SMC_DEBUG
+	SMC37c669_config_mode( TRUE );
+	SMC37c669_dump_registers( );
+	SMC37c669_config_mode( FALSE );
+        SMC37c669_display_device_info( );
+#endif
+        SMC37c669_disable_device( SERIAL_0 );
+        SMC37c669_configure_device(
+            SERIAL_0,
+            COM1_BASE,
+            COM1_IRQ,
+            -1
+        );
+        SMC37c669_enable_device( SERIAL_0 );
+
+        SMC37c669_disable_device( SERIAL_1 );
+        SMC37c669_configure_device(
+            SERIAL_1,
+            COM2_BASE,
+            COM2_IRQ,
+            -1
+        );
+        SMC37c669_enable_device( SERIAL_1 );
+
+        SMC37c669_disable_device( PARALLEL_0 );
+        SMC37c669_configure_device(
+            PARALLEL_0,
+            PARP_BASE,
+            PARP_IRQ,
+            PARP_DRQ
+        );
+        SMC37c669_enable_device( PARALLEL_0 );
+
+        SMC37c669_disable_device( FLOPPY_0 );
+        SMC37c669_configure_device(
+            FLOPPY_0,
+            FDC_BASE,
+            FDC_IRQ,
+            FDC_DRQ
+        );
+        SMC37c669_enable_device( FLOPPY_0 );
+          
+        SMC37c669_disable_device( IDE_0 );
+
+#if SMC_DEBUG
+	SMC37c669_config_mode( TRUE );
+	SMC37c669_dump_registers( );
+	SMC37c669_config_mode( FALSE );
+        SMC37c669_display_device_info( );
+#endif
+    }
+    else {
+#if SMC_DEBUG
+        printk( "No SMC37c669 Super I/O Controller found\n" );
+#endif
+    }
+}
+
+#endif /* SX164 */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/t2.c linux/arch/alpha/kernel/t2.c
--- v2.0.33/linux/arch/alpha/kernel/t2.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/kernel/t2.c	Wed Jun  3 15:17:46 1998
@@ -0,0 +1,654 @@
+/*
+ * Code common to all T2 chips.
+ *
+ * Written by Jay A Estabrook (jestabro@amt.tay1.dec.com).
+ * December 1996.
+ *
+ * based on CIA code by David A Rusling (david.rusling@reo.mts.dec.com)
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+extern asmlinkage unsigned long whami(void);
+
+#define CPUID whami()
+
+/*
+ * Machine check reasons.  Defined according to PALcode sources
+ * (osf.h and platform.h).
+ */
+#define MCHK_K_TPERR		0x0080
+#define MCHK_K_TCPERR		0x0082
+#define MCHK_K_HERR		0x0084
+#define MCHK_K_ECC_C		0x0086
+#define MCHK_K_ECC_NC		0x0088
+#define MCHK_K_OS_BUGCHECK	0x008A
+#define MCHK_K_PAL_BUGCHECK	0x0090
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef CONFIG_ALPHA_T2
+
+#ifdef DEBUG_CONF
+# define DBG(args)	printk args
+#else
+# define DBG(args)
+#endif
+
+#ifdef DEBUG_MCHECK
+# define DBGMC(args)	printk args
+#else
+# define DBGMC(args)
+#endif
+
+#define vulp	volatile unsigned long *
+#define vuip	volatile unsigned int  *
+
+static volatile unsigned int T2_mcheck_expected = 0;
+static volatile unsigned int T2_mcheck_taken = 0;
+static unsigned long T2_jd;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int T2_DMA_WIN_BASE = T2_DMA_WIN_BASE_DEFAULT;
+unsigned int T2_DMA_WIN_SIZE = T2_DMA_WIN_SIZE_DEFAULT;
+unsigned long t2_sm_base;
+#endif /* SRM_SETUP */
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the T2_HAXR2 register
+ * accordingly.  It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:11	Device select bit.
+ * 	10:8	Function number
+ * 	 7:2	Register number
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:24	reserved
+ *	23:16	bus number (8 bits = 128 possible buses)
+ *	15:11	Device number (5 bits)
+ *	10:8	function number
+ *	 7:2	register number
+ *  
+ * Notes:
+ *	The function number selects which function of a multi-function device 
+ *	(e.g., scsi and ethernet).
+ * 
+ *	The register selects a DWORD (32 bit) register offset.  Hence it
+ *	doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ *	bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+			unsigned char where, unsigned long *pci_addr,
+			unsigned char *type1)
+{
+	unsigned long addr;
+
+	DBG(("mk_conf_addr(bus=%d,dfn=0x%x,where=0x%x,addr=0x%lx,type1=0x%x)\n",
+	     bus, device_fn, where, pci_addr, type1));
+
+	if (bus == 0) {
+		int device = device_fn >> 3;
+
+		/* type 0 configuration cycle: */
+
+		if (device > 8) {
+			DBG(("mk_conf_addr: device (%d)>20, returning -1\n",
+			     device));
+			return -1;
+		}
+
+		*type1 = 0;
+#if 0
+		addr = (device_fn << 8) | (where);
+#else
+		addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where);
+#endif
+	} else {
+		/* type 1 configuration cycle: */
+		*type1 = 1;
+		addr = (bus << 16) | (device_fn << 8) | (where);
+	}
+	*pci_addr = addr;
+	DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	return 0;
+}
+
+
+static unsigned int conf_read(unsigned long addr, unsigned char type1)
+{
+	unsigned long flags;
+	unsigned int stat0, value;
+	unsigned int t2_cfg = 0; /* to keep gcc quiet */
+
+	save_flags(flags);	/* avoid getting hit by machine check */
+	cli();
+
+	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+#if 0
+	/* reset status register to avoid losing errors: */
+	stat0 = *((volatile unsigned int *)T2_IOCSR);
+	*((volatile unsigned int *)T2_IOCSR) = stat0;
+	mb();
+	DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0));
+	/* if Type1 access, must set T2 CFG */
+	if (type1) {
+		t2_cfg = *((unsigned int *)T2_IOC_CFG);
+		mb();
+		*((unsigned int *)T2_IOC_CFG) = t2_cfg | 1;
+		DBG(("conf_read: TYPE1 access\n"));
+	}
+	mb();
+	draina();
+#endif
+	T2_mcheck_expected = 1;
+	T2_mcheck_taken = 0;
+	mb();
+	/* access configuration space: */
+	value = *((volatile unsigned int *)addr);
+	mb();
+	mb();
+	if (T2_mcheck_taken) {
+		T2_mcheck_taken = 0;
+		value = 0xffffffffU;
+		mb();
+	}
+	T2_mcheck_expected = 0;
+	mb();
+
+#if 0
+	/* if Type1 access, must reset IOC CFG so normal IO space ops work */
+	if (type1) {
+		*((unsigned int *)T2_IOC_CFG) = t2_cfg & ~1;
+		mb();
+	}
+#endif
+	DBG(("conf_read(): finished\n"));
+
+	restore_flags(flags);
+	return value;
+}
+
+
+static void conf_write(unsigned long addr, unsigned int value,
+		       unsigned char type1)
+{
+	unsigned long flags;
+	unsigned int stat0;
+	unsigned int t2_cfg = 0; /* to keep gcc quiet */
+
+	save_flags(flags);	/* avoid getting hit by machine check */
+	cli();
+
+#if 0
+	/* reset status register to avoid losing errors: */
+	stat0 = *((volatile unsigned int *)T2_IOCSR);
+	*((volatile unsigned int *)T2_IOCSR) = stat0;
+	mb();
+	DBG(("conf_write: T2 ERR was 0x%x\n", stat0));
+	/* if Type1 access, must set T2 CFG */
+	if (type1) {
+		t2_cfg = *((unsigned int *)T2_IOC_CFG);
+		mb();
+		*((unsigned int *)T2_IOC_CFG) = t2_cfg | 1;
+		DBG(("conf_write: TYPE1 access\n"));
+	}
+	draina();
+#endif
+	T2_mcheck_expected = 1;
+	mb();
+	/* access configuration space: */
+	*((volatile unsigned int *)addr) = value;
+	mb();
+	mb();
+	T2_mcheck_expected = 0;
+	mb();
+
+#if 0
+	/* if Type1 access, must reset IOC CFG so normal IO space ops work */
+	if (type1) {
+		*((unsigned int *)T2_IOC_CFG) = t2_cfg & ~1;
+		mb();
+	}
+#endif
+	DBG(("conf_write(): finished\n"));
+	restore_flags(flags);
+}
+
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned char *value)
+{
+	unsigned long addr = T2_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	*value = 0xff;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	addr |= (pci_addr << 5) + 0x00;
+
+	*value = conf_read(addr, type1) >> ((where & 3) * 8);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned short *value)
+{
+	unsigned long addr = T2_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	*value = 0xffff;
+
+	if (where & 0x1) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	addr |= (pci_addr << 5) + 0x08;
+
+	*value = conf_read(addr, type1) >> ((where & 3) * 8);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned int *value)
+{
+	unsigned long addr = T2_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	*value = 0xffffffff;
+	if (where & 0x3) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x18;
+	*value = conf_read(addr, type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned char value)
+{
+	unsigned long addr = T2_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x00;
+	conf_write(addr, value << ((where & 3) * 8), type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned short value)
+{
+	unsigned long addr = T2_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x08;
+	conf_write(addr, value << ((where & 3) * 8), type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+				unsigned char where, unsigned int value)
+{
+	unsigned long addr = T2_CONF;
+	unsigned long pci_addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	}
+	addr |= (pci_addr << 5) + 0x18;
+	conf_write(addr, value << ((where & 3) * 8), type1);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long t2_init(unsigned long mem_start, unsigned long mem_end)
+{
+        unsigned int t2_err;
+	struct percpu_struct *cpu;
+	int i;
+
+#if 0
+        /* 
+	 * Set up error reporting.
+	 */
+	t2_err = *(vuip)T2_IOCSR ;
+	t2_err |= (0x1 << 7) ;   /* master abort */
+	*(vuip)T2_IOC_T2_ERR = t2_err ;
+	mb() ;
+#endif
+
+	printk("t2_init: HBASE was 0x%lx\n", *((unsigned long *)T2_HBASE));
+#if 0
+	printk("t2_init: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+	       *((vulp)T2_WBASE1),
+	       *((vulp)T2_WMASK1),
+	       *((vulp)T2_TBASE1));
+	printk("t2_init: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+	       *((vulp)T2_WBASE2),
+	       *((vulp)T2_WMASK2),
+	       *((vulp)T2_TBASE2));
+#endif
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	/* check window 1 for enabled and mapped to 0 */
+	if (((*(vulp)T2_WBASE1 & (3UL<<18)) == (2UL<<18)) &&
+	     (*(vuip)T2_TBASE1 == 0))
+	{
+	  T2_DMA_WIN_BASE = *(vulp)T2_WBASE1 & 0xfff00000UL;
+	  T2_DMA_WIN_SIZE = *(vulp)T2_WMASK1 & 0xfff00000UL;
+	  T2_DMA_WIN_SIZE += 0x00100000UL;
+/* DISABLE window 2!! ?? */
+#if 1
+	  printk("t2_init: using Window 1 settings\n");
+	  printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+		 *(vulp)T2_WBASE1,
+		 *(vulp)T2_WMASK1,
+		 *(vulp)T2_TBASE1);
+#endif
+	}
+	else	/* check window 2 for enabled and mapped to 0 */
+	if (((*(vulp)T2_WBASE2 & (3UL<<18)) == (2UL<<18)) &&
+	     (*(vuip)T2_TBASE2 == 0))
+	{
+	  T2_DMA_WIN_BASE = *(vulp)T2_WBASE2 & 0xfff00000UL;
+	  T2_DMA_WIN_SIZE = *(vulp)T2_WMASK2 & 0xfff00000UL;
+	  T2_DMA_WIN_SIZE += 0x00100000UL;
+/* DISABLE window 1!! ?? */
+#if 1
+	  printk("t2_init: using Window 2 settings\n");
+	  printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+		 *(vulp)T2_WBASE2,
+		 *(vulp)T2_WMASK2,
+		 *(vulp)T2_TBASE2);
+#endif
+	}
+	else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+	{
+	/*
+	 * Set up the PCI->physical memory translation windows.
+	 * For now, window 2 is  disabled.  In the future, we may
+	 * want to use it to do scatter/gather DMA.  Window 1
+	 * goes at 1 GB and is 1 GB large.
+	 */
+
+	/* WARNING!! must correspond to the DMA_WIN params!!! */
+	*(vuip)T2_WBASE1 = 0x400807ffU;
+ 	*(vuip)T2_WMASK1 = 0x3ff00000U;
+	*(vuip)T2_TBASE1 = 0;
+
+	*(vuip)T2_WBASE2 = 0x0;
+	*(vuip)T2_HBASE = 0x0;
+	}
+
+
+	/*
+	 * check ASN in HWRPB for validity, report if bad
+	 */
+	if (hwrpb->max_asn != MAX_ASN) {
+		printk("T2_init: max ASN from HWRPB is bad (0x%lx)\n",
+			hwrpb->max_asn);
+		hwrpb->max_asn = MAX_ASN;
+	}
+
+        /*
+         * Finally, clear the T2_HAE_3 register, which gets used
+         *  for PCI Config Space accesses. That is the way
+         *  we want to use it, and we do not want to depend on
+         *  what ARC or SRM might have left behind...
+         */
+        {
+	  unsigned long t2_hae_1 = *((unsigned long *)T2_HAE_1);
+	  unsigned long t2_hae_2 = *((unsigned long *)T2_HAE_2);
+	  unsigned long t2_hae_3 = *((unsigned long *)T2_HAE_3);
+	  unsigned long t2_hae_4 = *((unsigned long *)T2_HAE_4);
+#if 1
+          printk("T2_init: HAE1 was 0x%lx\n", t2_hae_1);
+          printk("T2_init: HAE2 was 0x%lx\n", t2_hae_2);
+          printk("T2_init: HAE3 was 0x%lx\n", t2_hae_3);
+          printk("T2_init: HAE4 was 0x%lx\n", t2_hae_4);
+#endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+	  /*
+	    sigh... For the SRM setup, unless we know apriori what the HAE
+	    contents will be, we need to setup the arbitrary region bases
+	    so we can test against the range of addresses and tailor the
+	    region chosen for the SPARSE memory access.
+
+	    see include/asm-alpha/t2.h for the SPARSE mem read/write
+	  */
+	  t2_sm_base = (t2_hae_1 << 27) & 0xf8000000UL;
+#else /* SRM_SETUP */
+          *((unsigned int *)T2_HAE_1) = 0; mb();
+          *((unsigned int *)T2_HAE_2) = 0; mb();
+          *((unsigned int *)T2_HAE_3) = 0; mb();
+#if 0
+          *((unsigned int *)T2_HAE_4) = 0; mb();
+#endif
+#endif /* SRM_SETUP */
+        }
+ 
+#if 1
+	if (hwrpb->nr_processors > 1) {
+            printk("T2_init: nr_processors 0x%lx\n",
+		   hwrpb->nr_processors);
+            printk("T2_init: processor_size 0x%lx\n",
+		   hwrpb->processor_size);
+            printk("T2_init: processor_offset 0x%lx\n",
+		   hwrpb->processor_offset);
+
+	    cpu = (struct percpu_struct *)
+			((char*)hwrpb + hwrpb->processor_offset);
+
+	    for (i = 0; i < hwrpb->nr_processors; i++ ) {
+	        printk("T2_init: CPU 0x%x: flags 0x%lx type 0x%lx\n",
+		       i, cpu->flags, cpu->type);
+		cpu = (struct percpu_struct *)
+			((char *)cpu + hwrpb->processor_size);
+	    }
+	}
+#endif
+
+	return mem_start;
+}
+
+#define SIC_SEIC (1UL << 33)    /* System Event Clear */
+
+struct sable_cpu_csr *sable_cpu_regs[4] = {
+	(struct sable_cpu_csr *)CPU0_BASE,
+	(struct sable_cpu_csr *)CPU1_BASE,
+	(struct sable_cpu_csr *)CPU2_BASE,
+	(struct sable_cpu_csr *)CPU3_BASE,
+};
+int t2_clear_errors(void)
+{
+	DBGMC(("???????? t2_clear_errors\n"));
+
+	sable_cpu_regs[CPUID]->sic &= ~SIC_SEIC;
+
+	/* 
+	 * clear cpu errors
+	 */
+	sable_cpu_regs[CPUID]->bcce |= sable_cpu_regs[CPUID]->bcce;
+	sable_cpu_regs[CPUID]->cbe  |= sable_cpu_regs[CPUID]->cbe;
+	sable_cpu_regs[CPUID]->bcue |= sable_cpu_regs[CPUID]->bcue;
+	sable_cpu_regs[CPUID]->dter |= sable_cpu_regs[CPUID]->dter;
+
+	*(unsigned long *)T2_CERR1 |= *(unsigned long *)T2_CERR1;
+	*(unsigned long *)T2_PERR1 |= *(unsigned long *)T2_PERR1;
+
+ 	mb();
+ 	mb();
+	return 0;
+}
+
+void t2_machine_check(unsigned long vector, unsigned long la_ptr,
+		       struct pt_regs * regs)
+{
+	struct el_t2_logout_header *mchk_header;
+	struct el_t2_procdata_mcheck *mchk_procdata;
+	struct el_t2_sysdata_mcheck *mchk_sysdata;
+	unsigned long * ptr;
+	const char * reason;
+	char buf[128];
+	long i;
+
+	DBGMC(("t2_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+	       vector, la_ptr));
+
+	mchk_header = (struct el_t2_logout_header *)la_ptr;
+
+	DBGMC(("t2_machine_check: susoffset=0x%lx procoffset=0x%lx\n",
+	       mchk_header->elfl_sysoffset, mchk_header->elfl_procoffset));
+
+	mchk_sysdata = (struct el_t2_sysdata_mcheck *)
+	  (la_ptr + mchk_header->elfl_sysoffset);
+	mchk_procdata = (struct el_t2_procdata_mcheck *)
+	  (la_ptr + mchk_header->elfl_procoffset - sizeof(unsigned long)*32);
+
+	DBGMC(("         pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+	     regs->pc, mchk_header->elfl_size, mchk_header->elfl_procoffset,
+	     mchk_header->elfl_sysoffset));
+	DBGMC(("t2_machine_check: expected %d\n", T2_mcheck_expected));
+#ifdef DEBUG_DUMP
+	{
+		unsigned long *ptr;
+		int i;
+
+		ptr = (unsigned long *)la_ptr;
+		for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) {
+			printk(" +%lx %lx %lx\n", i*sizeof(long),
+			       ptr[i], ptr[i+1]);
+		}
+	}
+#endif /* DEBUG_DUMP */
+	/*
+	 * Check if machine check is due to a badaddr() and if so,
+	 * ignore the machine check.
+	 */
+	mb();
+	mb();
+	if (T2_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+		DBGMC(("T2 machine check expected\n"));
+		T2_mcheck_taken = 1;
+		t2_clear_errors();
+		T2_mcheck_expected = 0;
+		mb();
+		mb();
+		wrmces(rdmces()|1);/* ??? */
+		draina();
+		return;
+	}
+
+	switch ((unsigned int) mchk_header->elfl_error_type) {
+	      case MCHK_K_TPERR:	reason = "tag parity error"; break;
+	      case MCHK_K_TCPERR:	reason = "tag control parity error"; break;
+	      case MCHK_K_HERR:		reason = "generic hard error"; break;
+	      case MCHK_K_ECC_C:	reason = "correctable ECC error"; break;
+	      case MCHK_K_ECC_NC:	reason = "uncorrectable ECC error"; break;
+	      case MCHK_K_OS_BUGCHECK:	reason = "OS-specific PAL bugcheck"; break;
+	      case MCHK_K_PAL_BUGCHECK:	reason = "callsys in kernel mode"; break;
+	      case 0x96: reason = "i-cache read retryable error"; break;
+	      case 0x98: reason = "processor detected hard error"; break;
+
+		/* system specific (these are for Alcor, at least): */
+	      case 0x203: reason = "system detected uncorrectable ECC error"; break;
+	      case 0x205: reason = "parity error detected by T2"; break;
+	      case 0x207: reason = "non-existent memory error"; break;
+	      case 0x209: reason = "PCI SERR detected"; break;
+	      case 0x20b: reason = "PCI data parity error detected"; break;
+	      case 0x20d: reason = "PCI address parity error detected"; break;
+	      case 0x20f: reason = "PCI master abort error"; break;
+	      case 0x211: reason = "PCI target abort error"; break;
+	      case 0x213: reason = "scatter/gather PTE invalid error"; break;
+	      case 0x215: reason = "flash ROM write error"; break;
+	      case 0x217: reason = "IOA timeout detected"; break;
+	      case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
+	      case 0x21b: reason = "EISA fail-safe timer timeout"; break;
+	      case 0x21d: reason = "EISA bus time-out"; break;
+	      case 0x21f: reason = "EISA software generated NMI"; break;
+	      case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
+	      default:
+		sprintf(buf, "reason for machine-check unknown (0x%x)",
+			(unsigned int) mchk_header->elfl_error_type);
+		reason = buf;
+		break;
+	}
+	wrmces(rdmces()|1);	/* reset machine check pending flag */
+	mb();
+
+	printk(KERN_CRIT "  T2 machine check: %s%s\n",
+	       reason, mchk_header->elfl_retry ? " (retryable)" : "");
+
+	/* dump the logout area to give all info: */
+
+	ptr = (unsigned long *)la_ptr;
+	for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) {
+	    printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+		   i*sizeof(long), ptr[i], ptr[i+1]);
+	}
+}
+
+#endif /* CONFIG_ALPHA_T2 */
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.0.33/linux/arch/alpha/kernel/traps.c	Wed Aug 13 12:54:02 1997
+++ linux/arch/alpha/kernel/traps.c	Wed Jun  3 15:17:46 1998
@@ -286,7 +286,7 @@
 	extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
 	extern unsigned long alpha_read_fp_reg (unsigned long reg);
 
-	pc_addr = frame + 7 + 20 + 1;			/* pc in PAL frame */
+	pc_addr = frame + 7 + 20 + 3 /* em86 */ + 1;	/* pc in PAL frame */
 
 	if (cnt >= 5 && jiffies - last_time > 5*HZ) {
 		cnt = 0;
@@ -336,7 +336,7 @@
 
 		      case 16: case 17: case 18: 
 			/* a0-a2 in PAL frame */
-			reg_addr += 7 + 20 + 3 + (reg - 16);
+			reg_addr += 7 + 20 + 3 /* em86 */ + 3 + (reg - 16);
 			break;
 
 		      case 19: case 20: case 21: case 22: case 23: 
@@ -347,7 +347,7 @@
 
 		      case 29:
 			/* gp in PAL frame */
-			reg_addr += 7 + 20 + 2;
+			reg_addr += 7 + 20 + 3 /* em86 */ + 2;
 			break;
 
 		      case 30:
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c
--- v2.0.33/linux/arch/alpha/math-emu/fp-emul.c	Sun Aug  3 10:58:38 1997
+++ linux/arch/alpha/math-emu/fp-emul.c	Wed Jun  3 15:17:46 1998
@@ -13,9 +13,9 @@
 #define OPC_INTL	0x11
 #define OPC_INTS	0x12
 #define OPC_INTM	0x13
-#define OPC_FLTV	0x14
-#define OPC_FLTI	0x15
-#define OPC_FLTL	0x16
+#define OPC_FLTV	0x15
+#define OPC_FLTI	0x16
+#define OPC_FLTL	0x17
 
 #define OPC_MISC	0x18
 
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/math-emu/ieee-math.c linux/arch/alpha/math-emu/ieee-math.c
--- v2.0.33/linux/arch/alpha/math-emu/ieee-math.c	Thu Apr 11 23:49:30 1996
+++ linux/arch/alpha/math-emu/ieee-math.c	Wed Jun  3 15:17:46 1998
@@ -137,9 +137,8 @@
 static inline void
 mul64 (const unsigned long a, const unsigned long b, unsigned long c[2])
 {
-	asm ("mulq  %2,%3,%0\n\t"
-	     "umulh %2,%3,%1"
-	     : "r="(c[0]), "r="(c[1]) : "r"(a), "r"(b));
+	c[0] = a * b;
+	asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b));
 }
 
 
@@ -276,7 +275,7 @@
 {
 	unsigned long res, sticky;
 
-	if (!a->f[0] && !a->f[1]) {
+	if (!a->e && !a->f[0] && !a->f[1]) {
 		*b = (unsigned long) a->s << 63;	/* return +/-0 */
 		return 0;
 	}
@@ -356,7 +355,7 @@
 {
 	unsigned long res, sticky;
 
-	if (!a->f[0] && !a->f[1]) {
+	if (!a->e && !a->f[0] && !a->f[1]) {
 		*b = (unsigned long) a->s << 63;	/* return +/-0 */
 		return 0;
 	}
@@ -384,7 +383,7 @@
 			a->e = -0x3ff;
 		}
 	}
-	if (a->e > 0x3ff) {
+	if (a->e >= 0x3ff) {
 		res = FPCR_OVF | FPCR_INE;
 		if (f & IEEE_TRAP_ENABLE_OVF) {
 			a->e -= 0x600;	/* scale down result by 2^alpha */
@@ -1143,12 +1142,9 @@
 		return 0;
 	}
 	op_c.s = op_a.s ^ op_b.s;
-	op_c.e = op_a.e + op_b.e;
+	op_c.e = op_a.e + op_b.e - 55;
 	mul64(op_a.f[0], op_b.f[0], op_c.f);
 
-	normalize(&op_c);
-	op_c.e -= 55;		/* drop the 55 original bits. */
-
 	return round_s_ieee(f, &op_c, c);
 }
 
@@ -1200,11 +1196,8 @@
 		return 0;
 	}
 	op_c.s = op_a.s ^ op_b.s;
-	op_c.e = op_a.e + op_b.e;
+	op_c.e = op_a.e + op_b.e - 55;
 	mul64(op_a.f[0], op_b.f[0], op_c.f);
-
-	normalize(&op_c);
-	op_c.e -= 55;	/* drop the 55 original bits. */
 
 	return round_t_ieee(f, &op_c, c);
 }
diff -u --recursive --new-file v2.0.33/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.0.33/linux/arch/alpha/mm/init.c	Tue Aug 20 23:18:07 1996
+++ linux/arch/alpha/mm/init.c	Wed Jun  3 15:17:46 1998
@@ -26,6 +26,8 @@
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
+struct thread_struct * original_pcb_ptr;
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -81,15 +83,19 @@
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
-static void load_PCB(struct thread_struct * pcb)
+static struct thread_struct * load_PCB(struct thread_struct * pcb)
 {
+	struct thread_struct *old_pcb;
+
 	__asm__ __volatile__(
-		"stq $30,0(%0)\n\t"
-		"bis %0,%0,$16\n\t"
-		"call_pal %1"
-		: /* no outputs */
+		"stq $30,0(%1)\n\t"
+		"bis %1,%1,$16\n\t"
+		"call_pal %2\n\t"
+		"bis $0,$0,%0"
+		: "=r" (old_pcb)
 		: "r" (pcb), "i" (PAL_swpctx)
 		: "$0", "$1", "$16", "$22", "$23", "$24", "$25");
+	return old_pcb;
 }
 
 /*
@@ -107,10 +113,15 @@
 	start_mem = free_area_init(start_mem, end_mem);
 
 	/* find free clusters, update mem_map[] accordingly */
-	memdesc = (struct memdesc_struct *) (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
+	memdesc = (struct memdesc_struct *)
+		(INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
 	cluster = memdesc->cluster;
 	for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
 		unsigned long pfn, nr;
+#if 0
+printk("paging_init: cluster %d usage %ld start %ld size %ld\n",
+       i, cluster->usage, cluster->start_pfn, cluster->numpages);
+#endif
 		if (cluster->usage & 1)
 			continue;
 		pfn = cluster->start_pfn;
@@ -134,7 +145,7 @@
 	init_task.tss.pal_flags = 1;	/* set FEN, clear everything else */
 	init_task.tss.flags = 0;
 	init_task.kernel_stack_page = INIT_STACK;
-	load_PCB(&init_task.tss);
+	original_pcb_ptr = load_PCB(&init_task.tss);
 
 	flush_tlb_all();
 	return start_mem;
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.0.33/linux/arch/i386/kernel/entry.S	Tue Sep 16 14:42:45 1997
+++ linux/arch/i386/kernel/entry.S	Wed Jun  3 15:17:46 1998
@@ -182,10 +182,10 @@
 	cmpb SYMBOL_NAME(active_kernel_processor), %al; \
 	je 4f; \
 2:	SMP_PROF_B \
-	btl %al, SYMBOL_NAME(smp_invalidate_needed); \
+	btl %eax, SYMBOL_NAME(smp_invalidate_needed); \
 	jnc 5f; \
 	lock; \
-	btrl %al, SYMBOL_NAME(smp_invalidate_needed); \
+	btrl %eax, SYMBOL_NAME(smp_invalidate_needed); \
 	jnc 5f; \
 	movl %cr3,%edx; \
 	movl %edx,%cr3; \
@@ -326,7 +326,7 @@
 	ALIGN
 1:	call SYMBOL_NAME(syscall_trace)
 	movl ORIG_EAX(%esp),%eax
-	call SYMBOL_NAME(sys_call_table)(,%eax,4)
+	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
 	movl %eax,EAX(%esp)		# save the return value
 #ifdef __SMP__
 	GET_PROCESSOR_OFFSET(%eax)
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.0.33/linux/arch/i386/kernel/head.S	Tue Mar 10 13:19:08 1998
+++ linux/arch/i386/kernel/head.S	Wed Jun  3 15:17:46 1998
@@ -134,13 +134,20 @@
 isnew:	pushl %ecx		# restore original EFLAGS
 	popfl
 	incl SYMBOL_NAME(have_cpuid)	# we have CPUID
+	/*
+ 	 *	Technically we should use CPUID 0 to see if we have CPUID 1!
+	 */
 	/* get processor type */
 	movl $1, %eax		# Use the CPUID instruction to 
+#ifdef GAS_KNOWS_CPUID
+	cpuid			# check the processor type
+#else
 	.byte 0x0f, 0xa2	# check the processor type
+#endif
 	movb %al, %cl		# save reg for future use
 	andb $0x0f,%ah		# mask processor family
 	movb %ah,SYMBOL_NAME(x86)
-	andb $0xf0, %eax	# mask model
+	andb $0xf0, %al		# mask model
 	shrb $4, %al
 	movb %al,SYMBOL_NAME(x86_model)
 	andb $0x0f, %cl		# mask mask revision
@@ -148,7 +155,11 @@
 	movl %edx,SYMBOL_NAME(x86_capability)
 	/* get vendor info */
 	xorl %eax, %eax			# call CPUID with 0 -> return vendor ID
+#ifdef GAS_KNOWS_CPUID
+	cpuid
+#else
 	.byte 0x0f, 0xa2		# CPUID
+#endif
 	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
@@ -171,8 +182,8 @@
 2:	movl %eax,%cr0
 	call check_x87
 #ifdef __SMP__
-	movb ready,%eax
-	orb %eax,%eax
+	movb ready,%al
+	orb %al,%al
 	jz 3f	
 	movl $ SYMBOL_NAME(swapper_pg_dir), %eax
 	movl %eax, %cr3
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/ioport.c linux/arch/i386/kernel/ioport.c
--- v2.0.33/linux/arch/i386/kernel/ioport.c	Wed Jan 11 11:10:53 1995
+++ linux/arch/i386/kernel/ioport.c	Wed Jun  3 15:17:46 1998
@@ -54,7 +54,7 @@
 		return -EINVAL;
 	if (from + num > IO_BITMAP_SIZE*32)
 		return -EINVAL;
-	if (!suser())
+	if (!suser() || securelevel > 0)
 		return -EPERM;
 
 	set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
@@ -82,7 +82,7 @@
 
 	if (level > 3)
 		return -EINVAL;
-	if (!suser())
+	if (!suser() || securelevel > 0)
 		return -EPERM;
 	*(&eflags) = (eflags & 0xffffcfff) | (level << 12);
 	return 0;
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.0.33/linux/arch/i386/kernel/process.c	Tue Dec  2 13:52:31 1997
+++ linux/arch/i386/kernel/process.c	Wed Jun  3 15:17:46 1998
@@ -421,8 +421,9 @@
 	int i;
 
 	if (current->ldt) {
-		free_page((unsigned long) current->ldt);
+		void * ldt = current->ldt;
 		current->ldt = NULL;
+		vfree(ldt);
 		for (i=1 ; i<NR_TASKS ; i++) {
 			if (task[i] == current)  {
 				set_ldt_desc(gdt+(i<<1)+
@@ -487,7 +488,7 @@
 	}
 	set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
 	if (p->ldt)
-		set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
+		set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, LDT_ENTRIES);
 	else
 		set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
 	p->tss.bitmap = offsetof(struct thread_struct,io_bitmap);
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.0.33/linux/arch/i386/kernel/ptrace.c	Tue Dec  2 13:52:31 1997
+++ linux/arch/i386/kernel/ptrace.c	Wed Jun  3 15:17:47 1998
@@ -2,6 +2,7 @@
 /* By Ross Biro 1/23/92 */
 /* edited by Linus Torvalds */
 
+#include <linux/config.h> /* CONFIG_MATH_EMULATION */
 #include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -688,3 +689,9 @@
 		current->signal |= (1 << (current->exit_code - 1));
 	current->exit_code = 0;
 }
+
+void get_pt_regs_for_task(struct pt_regs *regs, struct task_struct *task)
+{
+        *regs = *(struct pt_regs *) (((unsigned char *) task->tss.esp0) - MAGICNUMBER);
+}
+
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.0.33/linux/arch/i386/kernel/setup.c	Tue Dec  2 13:52:31 1997
+++ linux/arch/i386/kernel/setup.c	Wed Jun  3 15:17:47 1998
@@ -47,6 +47,11 @@
 
 char x86_vendor_id[13] = "unknown";
 
+unsigned char Cx86_step = 0;
+static const char *Cx86_type[] = {
+	"unknown", "1.3", "1.4", "2.4", "2.5", "2.6", "2.7 or 3.7", "4.2"
+	};
+
 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 */
@@ -226,6 +231,50 @@
 	return NULL;
 }
 
+static const char * Cx86model(void)
+{
+	unsigned char nr6x86 = 0;
+	static const char *model[] = {
+		"unknown", "6x86", "6x86L", "6x86MX", "6x86MXi"
+	};
+	switch (x86) {
+		case 5:
+			nr6x86 = ((x86_capability & (1 << 8)) ? 2 : 1); /* cx8 flag only on 6x86L */
+			break;
+		case 6:
+			nr6x86 = 3;
+			break;
+		default:
+			nr6x86 = 0;
+	}
+	switch (x86_mask) {
+		case 0x03:
+			Cx86_step =  1;	/* 6x86MX Rev 1.3 */
+			break;
+		case 0x04:
+			Cx86_step =  2;	/* 6x86MX Rev 1.4 */
+			break;
+		case 0x14:
+			Cx86_step =  3;	/* 6x86 Rev 2.4 */
+			break;
+		case 0x15:
+			Cx86_step =  4;	/* 6x86 Rev 2.5 */
+			break;
+		case 0x16:
+			Cx86_step =  5;	/* 6x86 Rev 2.6 */
+			break;
+		case 0x17:
+			Cx86_step =  6;	/* 6x86 Rev 2.7 or 3.7 */
+			break;
+		case 0x22:
+			Cx86_step =  7;	/* 6x86L Rev 4.2 */
+			break;
+		default:
+			Cx86_step = 0;
+	}
+	return model[nr6x86];
+}
+
 static const char * i686model(unsigned int nr)
 {
 	static const char *model[] = {
@@ -240,16 +289,20 @@
 {
         const char *p = NULL;
         static char nbuf[12];
-	switch (x86) {
-		case 4:
-			p = i486model(model);
-			break;
-		case 5:
-			p = i586model(model);
-			break;
-		case 6:
-			p = i686model(model);
-			break;
+	if (strncmp(x86_vendor_id, "Cyrix", 5) == 0)
+		p = Cx86model();
+	else {
+		switch (x86) {
+			case 4:
+				p = i486model(model);
+				break;
+			case 5:
+				p = i586model(model);
+				break;
+			case 6:
+				p = i686model(model);
+				break;
+		}
 	}
         if (p)
                 return p;
@@ -297,9 +350,16 @@
                                        CD(x86_vendor_id));
         
                         if (CD(x86_mask))
-                                len += sprintf(buffer+len,
-                                               "stepping\t: %d\n",
-                                               CD(x86_mask));
+                                if (strncmp(x86_vendor_id, "Cyrix", 5) != 0) {
+                                	len += sprintf(buffer+len,
+                                        	       "stepping\t: %d\n",
+                                             	       CD(x86_mask));
+                                }
+                                else { 			/* we have a Cyrix */
+                                	len += sprintf(buffer+len,
+                                        	       "stepping\t: %s\n",
+                                             	       Cx86_type[Cx86_step]);
+                                }
                         else
                                 len += sprintf(buffer+len, 
                                                "stepping\t: unknown\n");
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.0.33/linux/arch/i386/kernel/smp.c	Tue Dec  2 13:52:31 1997
+++ linux/arch/i386/kernel/smp.c	Wed Jun  3 15:17:47 1998
@@ -1025,7 +1025,7 @@
 	 */
 	 
 	if(ct==1000)
-		printk("CPU #%d: previous IPI still not cleared after 10mS", smp_processor_id());
+		printk("CPU #%d: previous IPI still not cleared after 10ms\n", smp_processor_id());
 		
 	/*
 	 *	Program the APIC to deliver the IPI
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.0.33/linux/arch/i386/kernel/time.c	Tue Dec  2 13:52:31 1997
+++ linux/arch/i386/kernel/time.c	Wed Jun  3 15:17:47 1998
@@ -475,29 +475,30 @@
 				/* Don't use them if a suspend/resume could
                                    corrupt the timer value.  This problem
                                    needs more debugging. */
-	if (x86_capability & 16) {
-		do_gettimeoffset = do_fast_gettimeoffset;
+	if (x86_capability & 16)
+		if (strncmp(x86_vendor_id, "Cyrix", 5) != 0) {
+			do_gettimeoffset = do_fast_gettimeoffset;
 
-		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( 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);
+					}
 				}
-			}
-		}
+			}	
 
-		/* read Pentium cycle counter */
-		__asm__(".byte 0x0f,0x31"
-			:"=a" (init_timer_cc.low),
-			 "=d" (init_timer_cc.high));
-		irq0.handler = pentium_timer_interrupt;
-	}
+			/* read Pentium cycle counter */
+			__asm__(".byte 0x0f,0x31"
+				:"=a" (init_timer_cc.low),
+			 	"=d" (init_timer_cc.high));
+			irq0.handler = pentium_timer_interrupt;
+		}
 #endif
 	setup_x86_irq(0, &irq0);
 }
diff -u --recursive --new-file v2.0.33/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.0.33/linux/arch/i386/kernel/vm86.c	Tue Feb 25 12:22:17 1997
+++ linux/arch/i386/kernel/vm86.c	Wed Jun  3 15:17:47 1998
@@ -104,7 +104,7 @@
 
 
 
-static do_vm86_irq_handling(int subfunction, int irqnumber);
+static int do_vm86_irq_handling(int subfunction, int irqnumber);
 static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
 
 asmlinkage int sys_vm86old(struct vm86_struct * v86)
@@ -611,7 +611,7 @@
 			int sig = irqnumber >> 8;
 			int irq = irqnumber & 255;
 			handle_irq_zombies();
-			if (!suser()) return -EPERM;
+			if (!suser() || securelevel > 0) return -EPERM;
 			if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM;
 			if ( (irq<3) || (irq>15) ) return -EPERM;
 			if (vm86_irqs[irq].tsk) return -EPERM;
diff -u --recursive --new-file v2.0.33/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.0.33/linux/arch/m68k/kernel/head.S	Sat May 18 01:15:10 1996
+++ linux/arch/m68k/kernel/head.S	Wed Jun  3 15:17:47 1998
@@ -65,6 +65,7 @@
  *   d4 - machine type
  */
 
+#include <linux/config.h>
 #include <linux/autoconf.h>
 #include <linux/linkage.h>
 #include <asm/bootinfo.h>
diff -u --recursive --new-file v2.0.33/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.0.33/linux/arch/ppc/kernel/setup.c	Mon Jul  8 01:27:43 1996
+++ linux/arch/ppc/kernel/setup.c	Wed Jun  3 15:17:47 1998
@@ -9,6 +9,7 @@
  * bootup setup stuff..
  */
 
+#include <linux/config.h> /* CONFIG_BLK_DEV_RAM */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.0.33/linux/drivers/block/floppy.c	Tue Apr  8 08:47:45 1997
+++ linux/drivers/block/floppy.c	Wed Jun  3 15:17:47 1998
@@ -118,7 +118,8 @@
 static int FLOPPY_IRQ=6;
 static int FLOPPY_DMA=2;
 static int allowed_drive_mask = 0x33;
- 
+
+static int irqdma_allocated = 0; 
 
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -743,6 +744,9 @@
 			UDRS->select_date = jiffies;
 		}
 	}
+	
+	/* FIXME: we should be more graceful here */
+	
 	if (newdor & FLOPPY_MOTOR_MASK)
 		floppy_grab_irq_and_dma();
 	if (olddor & FLOPPY_MOTOR_MASK)
@@ -802,10 +806,11 @@
 	unsigned long flags;
 
 	if (!usage_count){
-		printk("trying to lock fdc while usage count=0\n");
+		printk(KERN_ERR "trying to lock fdc while usage count=0\n");
 		return -1;
 	}
-	floppy_grab_irq_and_dma();
+	if(floppy_grab_irq_and_dma()==-1)
+		return -EBUSY;
 	INT_OFF;
 	while (fdc_busy && NO_SIGNAL)
 		interruptible_sleep_on(&fdc_wait);
@@ -4084,6 +4089,7 @@
 			fd_outb(FDCS->dor, FD_DOR);
 	fdc = 0;
 	fd_enable_irq();
+	irqdma_allocated=1;
 	return 0;
 }
 
@@ -4102,10 +4108,14 @@
 		return;
 	}
 	INT_ON;
-	fd_disable_dma();
-	fd_free_dma();
-	fd_disable_irq();
-	fd_free_irq();
+	if(irqdma_allocated)
+	{
+		fd_disable_dma();
+		fd_free_dma();
+		fd_disable_irq();
+		fd_free_irq();
+		irqdma_allocated=0;
+	}
 
 	set_dor(0, ~0, 8);
 #if N_FDC > 1
@@ -4248,10 +4258,12 @@
 void floppy_eject(void)
 {
 	int dummy;
-	floppy_grab_irq_and_dma();
-	lock_fdc(MAXTIMEOUT,0);
-	dummy=fd_eject(0);
-	process_fd_request();
-	floppy_release_irq_and_dma();
+	if(floppy_grab_irq_and_dma()==0)
+	{
+		lock_fdc(MAXTIMEOUT,0);
+		dummy=fd_eject(0);
+		process_fd_request();
+		floppy_release_irq_and_dma();
+	}
 }
 #endif
diff -u --recursive --new-file v2.0.33/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.0.33/linux/drivers/block/genhd.c	Mon Aug  4 11:45:55 1997
+++ linux/drivers/block/genhd.c	Wed Jun  3 15:17:47 1998
@@ -102,6 +102,7 @@
 static inline int is_extended_partition(struct partition *p)
 {
 	return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
+		SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
 		SYS_IND(p) == LINUX_EXTENDED_PARTITION);
 }
 
diff -u --recursive --new-file v2.0.33/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.0.33/linux/drivers/block/ide-cd.c	Mon Aug  4 11:45:55 1997
+++ linux/drivers/block/ide-cd.c	Wed Jun  3 15:17:47 1998
@@ -1980,7 +1980,7 @@
 	pc.c[7] = ((nblocks>>8) & 0xff);
 	pc.c[6] = ((nblocks>>16) & 0xff);
 	if (format <= 1)
-		pc.c[9] = 0xf0;
+		pc.c[9] = 0xf8;
 	else
 		pc.c[9] = 0x10;
 
@@ -2409,7 +2409,7 @@
 		kfree (buf);
 		return stat;
 	}
-
+	case CDROMREADRAW:
 	case CDROMREADMODE1:
 	case CDROMREADMODE2: {
 		struct cdrom_msf msf;
@@ -2420,10 +2420,13 @@
 		if (cmd == CDROMREADMODE1) {
 			blocksize = CD_FRAMESIZE;
 			format = 2;
-		} else {
-			blocksize = CD_FRAMESIZE_RAW0;
-			format = 3;
-		}
+		} else if (cmd == CDROMREADMODE2) {
+				blocksize = CD_FRAMESIZE_RAW0;
+				format = 3;
+		       } else {
+				blocksize = CD_FRAMESIZE_RAW;
+			 	format = 0;      	
+		       }
 
 		stat = verify_area (VERIFY_WRITE, (char *)arg, blocksize);
 		if (stat) return stat;
@@ -2434,16 +2437,16 @@
 				  msf.cdmsf_sec0,
 				  msf.cdmsf_frame0);
 	
-		/* Make sure the TOC is up to date. */
-		stat = cdrom_read_toc (drive, NULL);
+		/* DON'T make sure the TOC is up to date. */
+	     /*	stat = cdrom_read_toc (drive, NULL);
 		if (stat) return stat;
 
 		toc = drive->cdrom_info.toc;
 
 		if (lba < 0 || lba >= toc->capacity)
-			return -EINVAL;
+			return -EINVAL; */
 
-		buf = (char *) kmalloc (CD_FRAMESIZE_RAW0, GFP_KERNEL);
+		buf = (char *) kmalloc (CD_FRAMESIZE_RAW, GFP_KERNEL);
 		if (buf == NULL)
 			return -ENOMEM;
 
diff -u --recursive --new-file v2.0.33/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.0.33/linux/drivers/block/ide.c	Mon Aug  4 11:45:55 1997
+++ linux/drivers/block/ide.c	Wed Jun  3 15:17:47 1998
@@ -272,6 +272,7 @@
  *			acknowledge media change on removable drives
  *			add work-around for BMI drives
  *			remove "LBA" from boot messages
+ * Version 5.53.1	add UDMA "CRC retry" support
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -602,6 +603,11 @@
 	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
 	unsigned long _10_percent = chs_sects / 10;
 
+	/* very large drives (8GB+) may lie about the number of cylinders */
+	if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {
+		id->cyls = lba_sects / (16 * 63); /* correct cyls */
+		return 1;	/* lba_capacity is our only option */
+	}
 	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
 	if ((lba_sects - chs_sects) < _10_percent)
 		return 1;	/* lba_capacity is good */
@@ -636,6 +642,7 @@
 	/* Determine capacity, and use LBA if the drive properly supports it */
 	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
 		if (id->lba_capacity >= capacity) {
+			drive->cyl = id->lba_capacity / (drive->head * drive->sect);
 			capacity = id->lba_capacity;
 			drive->select.b.lba = 1;
 		}
@@ -1043,12 +1050,15 @@
 	} else {
 		if (drive->media == ide_disk && (stat & ERR_STAT)) {
 			/* err has different meaning on cdrom and tape */
-			if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+					return;	/* some newer drives don't support WIN_SPECIFY */
+			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
+				; /* UDMA crc error -- just retry the operation */
+			else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
 				rq->errors = ERROR_MAX;
 			else if (err & TRK0_ERR)	/* help it find track zero */
 				rq->errors |= ERROR_RECAL;
-			else if (err & MC_ERR)
-				drive->special.b.mc = 1;
 		}
 		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
 			try_to_flush_leftover_data(drive);
@@ -2270,7 +2280,7 @@
 		{
 			byte args[4], *argbuf = args;
 			int argsize = 4;
-			if (!suser()) return -EACCES;
+			if (!suser() || securelevel > 0) return -EACCES;
 			if (NULL == (void *) arg) {
 				err = ide_do_drive_cmd(drive, &rq, ide_wait);
 			} else if (!(err = verify_area(VERIFY_READ,(void *)arg, 4))) {
@@ -2561,14 +2571,16 @@
 		drive->head = id->heads;
 		drive->sect = id->sectors;
 	}
+
+	/* calculate drive capacity, and select LBA if possible */
+	(void) current_capacity (drive);
+
 	/* Correct the number of cyls if the bios value is too small */
 	if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
 		if (drive->cyl > drive->bios_cyl)
 			drive->bios_cyl = drive->cyl;
 	}
 
-	(void) current_capacity (drive); /* initialize LBA selection */
-
 	if (!strncmp(id->model, "BMI ", 4) &&
 	    strstr(id->model, " ENHANCED IDE ") &&
 	    drive->select.b.lba)
@@ -2587,8 +2599,12 @@
 			drive->special.b.set_multmode = 1;
 	}
 	if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
-		if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
-			printk(", DMA");
+		if (!(HWIF(drive)->dmaproc(ide_dma_check, drive))) {
+			if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7))
+				printk(", UDMA");
+			else
+				printk(", DMA");
+		}
 	}
 	printk("\n");
 }
@@ -2618,11 +2634,12 @@
 {
 	int hd_status, rc;
 	unsigned long timeout;
-	int irqs = 0;
+	unsigned long irqs_on = 0;
+	int irq_off;
 
 	if (!HWIF(drive)->irq) {		/* already got an IRQ? */
 		probe_irq_off(probe_irq_on());	/* clear dangling irqs */
-		irqs = probe_irq_on();		/* start monitoring irqs */
+		irqs_on = probe_irq_on();	/* start monitoring irqs */
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
 	}
 
@@ -2636,8 +2653,8 @@
 #if CONFIG_BLK_DEV_PROMISE
 	if (IS_PROMISE_DRIVE) {
 		if (promise_cmd(drive,PROMISE_IDENTIFY)) {
-			if (irqs)
-				(void) probe_irq_off(irqs);
+			if (irqs_on)
+				(void) probe_irq_off(irqs_on);
 			return 1;
 		}
 	} else
@@ -2647,8 +2664,8 @@
 	timeout += jiffies;
 	do {
 		if (jiffies > timeout) {
-			if (irqs)
-				(void) probe_irq_off(irqs);
+			if (irqs_on)
+				(void) probe_irq_off(irqs_on);
 			return 1;	/* drive timed-out */
 		}
 		delay_50ms();		/* give drive a breather */
@@ -2666,18 +2683,18 @@
 	} else
 		rc = 2;			/* drive refused ID */
 	if (!HWIF(drive)->irq) {
-		irqs = probe_irq_off(irqs);	/* get our irq number */
-		if (irqs > 0) {
-			HWIF(drive)->irq = irqs; /* save it for later */
-			irqs = probe_irq_on();
+		irq_off = probe_irq_off(irqs_on);	/* get our irq number */
+		if (irq_off > 0) {
+			HWIF(drive)->irq = irq_off; /* save it for later */
+			irqs_on = probe_irq_on();
 			OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
 			udelay(5);
-			(void) probe_irq_off(irqs);
+			(void) probe_irq_off(irqs_on);
 			(void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */
 			(void) GET_STAT();	/* clear drive IRQ */
 
 		} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
-			printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
+			printk("%s: IRQ probe failed (%d)\n", drive->name, irq_off);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
 			if (HWIF(drive)->chipset == ide_cmd640) {
diff -u --recursive --new-file v2.0.33/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v2.0.33/linux/drivers/block/ide.h	Wed Oct 15 15:22:14 1997
+++ linux/drivers/block/ide.h	Wed Jun  3 15:17:47 1998
@@ -65,6 +65,10 @@
  *  "No user-serviceable parts" beyond this point  :)
  *****************************************************************************/
 
+#if defined(CONFIG_BLK_DEV_IDESCSI) && !defined(CONFIG_SCSI)
+#error "SCSI must also be selected"
+#endif
+
 typedef unsigned char	byte;	/* used everywhere */
 
 /*
diff -u --recursive --new-file v2.0.33/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.0.33/linux/drivers/block/md.c	Sat Jun 29 14:04:00 1996
+++ linux/drivers/block/md.c	Wed Jun  3 15:17:47 1998
@@ -202,7 +202,7 @@
   
   if (inode->i_count>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
   {
-    printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, inode->i_count, md_dev[minor].busy);
+    printk ("STOP_MD md%x failed : i_count=%ld, busy=%d\n", minor, inode->i_count, md_dev[minor].busy);
     return -EBUSY;
   }
   
diff -u --recursive --new-file v2.0.33/linux/drivers/block/raid0.c linux/drivers/block/raid0.c
--- v2.0.33/linux/drivers/block/raid0.c	Sun May 19 21:50:46 1996
+++ linux/drivers/block/raid0.c	Wed Jun  3 15:17:47 1998
@@ -26,7 +26,7 @@
 #define MD_DRIVER
 #define MD_PERSONALITY
 
-static void create_strip_zones (int minor, struct md_dev *mddev)
+static int create_strip_zones (int minor, struct md_dev *mddev)
 {
   int i, j, c=0;
   int current_offset=0;
@@ -50,8 +50,8 @@
     c=0;
   }
 
-  data->strip_zone=kmalloc (sizeof(struct strip_zone)*data->nr_strip_zones,
-			      GFP_KERNEL);
+  if ((data->strip_zone=vmalloc(sizeof(struct strip_zone)*data->nr_strip_zones)) == NULL)
+    return 1;
 
   data->smallest=NULL;
   
@@ -81,6 +81,7 @@
 					   data->strip_zone[i-1].size) : 0;
     current_offset=smallest_by_zone->size;
   }
+  return 0;
 }
 
 static int raid0_run (int minor, struct md_dev *mddev)
@@ -90,16 +91,18 @@
 
   MOD_INC_USE_COUNT;
 
-  mddev->private=kmalloc (sizeof (struct raid0_data), GFP_KERNEL);
+  if ((mddev->private=vmalloc (sizeof (struct raid0_data))) == NULL) return 1;
   data=(struct raid0_data *) mddev->private;
   
-  create_strip_zones (minor, mddev);
+  if (create_strip_zones (minor, mddev)) return 1;
 
   nb_zone=data->nr_zones=
     md_size[minor]/data->smallest->size +
     (md_size[minor]%data->smallest->size ? 1 : 0);
-  
-  data->hash_table=kmalloc (sizeof (struct raid0_hash)*nb_zone, GFP_KERNEL);
+
+  printk ("raid0 : Allocating %d bytes for hash.\n",sizeof(struct raid0_hash)*nb_zone);
+  if ((data->hash_table=vmalloc (sizeof (struct raid0_hash)*nb_zone)) == NULL)
+    return 1;
 
   size=data->strip_zone[cur].size;
 
@@ -142,9 +145,9 @@
 {
   struct raid0_data *data=(struct raid0_data *) mddev->private;
 
-  kfree (data->hash_table);
-  kfree (data->strip_zone);
-  kfree (data);
+  vfree (data->hash_table);
+  vfree (data->strip_zone);
+  vfree (data);
 
   MOD_DEC_USE_COUNT;
   return 0;
diff -u --recursive --new-file v2.0.33/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.0.33/linux/drivers/block/rd.c	Tue Jul  2 09:08:41 1996
+++ linux/drivers/block/rd.c	Wed Jun  3 15:17:47 1998
@@ -422,7 +422,7 @@
 /*
  * This routine loads in the ramdisk image.
  */
-static void rd_load_image(kdev_t device,int offset)
+static void rd_load_image(kdev_t device,int offset, int unit)
 {
 	struct inode inode, out_inode;
 	struct file infile, outfile;
@@ -433,7 +433,7 @@
 	unsigned short rotate = 0;
 	char rotator[4] = { '|' , '/' , '-' , '\\' };
 
-	ram_device = MKDEV(MAJOR_NR, 0);
+	ram_device = MKDEV(MAJOR_NR, unit);
 
 	memset(&infile, 0, sizeof(infile));
 	memset(&inode, 0, sizeof(inode));
@@ -500,7 +500,7 @@
 
 successful_load:
 	invalidate_buffers(device);
-	ROOT_DEV = MKDEV(MAJOR_NR,0);
+	ROOT_DEV = MKDEV(MAJOR_NR,unit);
 
 done:
 	if (infile.f_op->release)
@@ -509,12 +509,21 @@
 }
 
 
-void rd_load()
+static void rd_load_disk(int n)
 {
+#ifdef CONFIG_BLK_DEV_INITRD
+	extern kdev_t real_root_dev;
+#endif	
+	
 	if (rd_doload == 0)
 		return;
 	
-	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
+	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR
+#ifdef CONFIG_BLK_DEV_INITRD	
+		&& MAJOR(real_root_dev) != FLOPPY_MAJOR
+#endif		
+	)
+			return;
 
 	if (rd_prompt) {
 #ifdef CONFIG_BLK_DEV_FD
@@ -525,15 +534,24 @@
 		wait_for_keypress();
 	}
 
-	rd_load_image(ROOT_DEV,rd_image_start);
+	rd_load_image(ROOT_DEV,rd_image_start,n);
+
+}
 
+void rd_load(void)
+{
+	rd_load_disk(0);
 }
 
+void rd_load_secondary(void)
+{
+	rd_load_disk(1);
+}
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void initrd_load(void)
 {
-	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
+	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0);
 }
 #endif
 
@@ -658,6 +676,13 @@
 crd_load(struct file * fp, struct file *outfp)
 {
 	int result;
+
+	insize = 0;  /* valid bytes in inbuf */
+	inptr = 0;   /* index of next byte to be processed in inbuf */
+	outcnt = 0;  /* bytes in output buffer */
+	exit_code = 0;
+	bytes_out = 0;
+	crc = 0xFFFFFFFF;
 	
 	crd_infp = fp;
 	crd_outfp = outfp;
diff -u --recursive --new-file v2.0.33/linux/drivers/block/triton.c linux/drivers/block/triton.c
--- v2.0.33/linux/drivers/block/triton.c	Sat Sep 21 23:54:08 1996
+++ linux/drivers/block/triton.c	Wed Jun  3 15:17:47 1998
@@ -247,14 +247,21 @@
 static int config_drive_for_dma (ide_drive_t *drive)
 {
 	const char **list;
-
 	struct hd_driveid *id = drive->id;
+
 	if (id && (id->capability & 1)) {
-		/* Enable DMA on any drive that supports mword2 DMA */
-		if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
-			drive->using_dma = 1;
-			return 0;		/* DMA enabled */
-		}
+		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+		if (id->field_valid & 4)	/* UltraDMA */
+			if  ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+				drive->using_dma = 1;
+				return 0;	/* dma enabled */
+			}
+		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+		if (id->field_valid & 2)	/* regular DMA */
+			if  ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
+				drive->using_dma = 1;
+				return 0;	/* dma enabled */
+			}
 		/* Consult the list of known "good" drives */
 		list = good_dma_drives;
 		while (*list) {
diff -u --recursive --new-file v2.0.33/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.0.33/linux/drivers/block/xd.c	Sun Sep  8 09:50:20 1996
+++ linux/drivers/block/xd.c	Wed Jun  3 15:17:47 1998
@@ -20,6 +20,14 @@
  *
  * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu
  *
+ * Revised: 13/12/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl
+ *   Fixed some problems with disk initialization and module initiation.
+ *   Recovered DMA access. Abridged messages. Added support for DTC5051CX,
+ *   WD1002-27X & XEBEC controllers. Driver uses now some jumper settings.
+ *   Added support for manual geometry setting (except Seagate controllers)
+ *   in form:
+ *      xd_geo=<cyl_xda>,<head_xda>,<sec_xda>[,<cyl_xdb>,<head_xdb>,<sec_xdb>]
+ *   Extended ioctl() support.
  */
 
 #include <linux/module.h>
@@ -28,7 +36,9 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/timer.h>
 #include <linux/genhd.h>
+#include <linux/ioport.h>
 #include <linux/xd.h>
 
 #include <asm/system.h>
@@ -39,6 +49,13 @@
 #define MAJOR_NR XT_DISK_MAJOR
 #include <linux/blk.h>
 
+#define XD_DONT_USE_DMA		0  /* Initial value. may be overriden using
+				      "nodma" module option */
+#define XD_INIT_DISK_DELAY	3  /* 30 ms delay during disk initialization */
+
+/* Above may need to be increased if a problem with the 2nd drive detection
+   (ST11M controller) or resetting a controler (WD) appears */
+
 XD_INFO xd_info[XD_MAXDRIVES];
 
 /* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
@@ -65,26 +82,49 @@
    NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver
    should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
 
+#include <asm/page.h>
+/* coppied from floppy.c */
+static inline int __get_order(unsigned long size)
+{
+	int order;
+
+	size = (size-1) >> (PAGE_SHIFT-1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
+}
+#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size))
+#define xd_dma_mem_free(addr, size) free_pages(addr, __get_order(size))
+static char *xd_dma_buffer = 0;
+
 static XD_SIGNATURE xd_sigs[] = {
 	{ 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */
+	{ 0x0008,"[BXD06 (C) DTC 17-MAY-1985]",xd_dtc_init_controller,xd_dtc5150cx_init_drive," DTC 5150CX" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
 	{ 0x000B,"CRD18A   Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Todd Fries, tfries@umr.edu */
 	{ 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, pat@it.com.au */
-	{ 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
-	{ 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
-	{ 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
+	{ 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," WD 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
+	{ 0x0008,"07/15/86(C) Copyright 1986 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," WD 1002-27X" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
+	{ 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," WD 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
+	{ 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
 	{ 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
 	{ 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
 	{ 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
 	{ 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
+	{ 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
 };
 static u_char *xd_bases[] =
 {
 	(u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xCC000,
-	(u_char *) 0xCE000,(u_char *) 0xD0000,(u_char *) 0xD8000,
+	(u_char *) 0xCE000,(u_char *) 0xD0000,(u_char *) 0xD2000,
+	(u_char *) 0xD4000,(u_char *) 0xD6000,(u_char *) 0xD8000,
+	(u_char *) 0xDA000,(u_char *) 0xDC000,(u_char *) 0xDE000,
 	(u_char *) 0xE0000
 };
 
-static struct hd_struct xd[XD_MAXDRIVES << 6];
+static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
 static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES] = { 0, 0 };
 static int xd_blocksizes[XD_MAXDRIVES << 6];
 static struct gendisk xd_gendisk = {
@@ -98,7 +138,7 @@
 #else
         xd_geninit,     /* init function */
 #endif
-	xd,		/* hd struct */
+	xd_struct,	/* hd struct */
 	xd_sizes,	/* block sizes */
 	0,		/* number */
 	(void *) xd_info,	/* internal */
@@ -118,9 +158,22 @@
 };
 static struct wait_queue *xd_wait_int = NULL, *xd_wait_open = NULL;
 static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
-static u_char xd_drives = 0, xd_irq = 0, xd_dma = 0, xd_maxsectors;
+static u_char xd_drives = 0, xd_irq = 5, xd_dma = 3, xd_maxsectors;
 static u_char xd_override = 0, xd_type = 0;
-static u_short xd_iobase = 0;
+static u_short xd_iobase = 0x320;
+static int xd_geo[XD_MAXDRIVES*3] = { 0,0,0,0,0,0 };
+
+static int xd[5];
+
+static volatile int xdc_busy = 0;
+static struct wait_queue *xdc_wait = NULL;
+
+typedef void (*timeout_fn)(unsigned long);
+static struct timer_list xd_timer = { NULL, NULL, 0, 0, (timeout_fn) xd_wakeup },
+			 xd_watchdog_int = { NULL, NULL, 0, 0, (timeout_fn) xd_watchdog };
+
+static volatile u_char xd_error;
+static int nodma = XD_DONT_USE_DMA;
 
 /* xd_init: register the block device number and set up pointer tables */
 int xd_init (void)
@@ -153,6 +206,7 @@
 		for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
 			if (!memcmp(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
 				*controller = j;
+				xd_type = j;
 				*address = xd_bases[i];
 				found++;
 			}
@@ -168,6 +222,11 @@
 	if (xd_detect(&controller,&address)) {
 
 		printk("xd_geninit: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,controller,address);
+		if (check_region(xd_iobase,4)) {
+			printk("xd: Ports at 0x%x are not available\n",xd_iobase);
+			return;
+		}
+		request_region(xd_iobase,4,"xd");
 		if (controller)
 			xd_sigs[controller].init_controller(address);
 		xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
@@ -176,6 +235,8 @@
 		for (i = 0; i < xd_drives; i++)
 			printk("xd_geninit: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors);
 
+	}
+	if (xd_drives) {
 		if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT harddisk", NULL)) {
 			if (request_dma(xd_dma,"xd")) {
 				printk("xd_geninit: unable to get DMA%d\n",xd_dma);
@@ -187,7 +248,7 @@
 	}
 
 	for (i = 0; i < xd_drives; i++) {
-		xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
+		xd_struct[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
 		xd_valid[i] = 1;
 	}
 
@@ -206,6 +267,10 @@
 		while (!xd_valid[dev])
 			sleep_on(&xd_wait_open);
 
+#ifdef MODULE
+		MOD_INC_USE_COUNT;
+#endif /* MODULE */
+
 		xd_access[dev]++;
 
 		return (0);
@@ -221,13 +286,15 @@
 	int code;
 
 	sti();
+	if (xdc_busy)
+		return;
 	while (code = 0, CURRENT) {
 		INIT_REQUEST;	/* do some checking on the request structure */
 
 		if (CURRENT_DEV < xd_drives
 		    && CURRENT->sector + CURRENT->nr_sectors
-		         <= xd[MINOR(CURRENT->rq_dev)].nr_sects) {
-			block = CURRENT->sector + xd[MINOR(CURRENT->rq_dev)].start_sect;
+		         <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) {
+			block = CURRENT->sector + xd_struct[MINOR(CURRENT->rq_dev)].start_sect;
 			count = CURRENT->nr_sectors;
 
 			switch (CURRENT->cmd) {
@@ -244,6 +311,18 @@
 	}
 }
 
+static int write_fs_long (unsigned long useraddr, long value)
+{
+	int err;
+
+	if (NULL == (long *)useraddr)
+		return -EINVAL;
+	if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
+		return err;
+	put_user((unsigned)value, (long *) useraddr);
+	return 0;
+}
+
 /* xd_ioctl: handle device ioctl's */
 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
 {
@@ -259,7 +338,7 @@
 					put_user(xd_info[dev].heads, &geometry->heads);
 					put_user(xd_info[dev].sectors, &geometry->sectors);
 					put_user(xd_info[dev].cylinders, &geometry->cylinders);
-					put_user(xd[MINOR(inode->i_rdev)].start_sect,&geometry->start);
+					put_user(xd_struct[MINOR(inode->i_rdev)].start_sect,&geometry->start);
 
 					return (0);
 				}
@@ -273,11 +352,13 @@
 					return -EINVAL;
 				read_ahead[MAJOR(inode->i_rdev)] = arg;
 				return 0;
+			case BLKRAGET:
+				return write_fs_long(arg, read_ahead[MAJOR(inode->i_rdev)]);
 			case BLKGETSIZE:
 				if (arg) {
 					if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
 						return (err);
-					put_user(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
+					put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
 
 					return (0);
 				}
@@ -289,7 +370,21 @@
 				fsync_dev(inode->i_rdev);
 				invalidate_buffers(inode->i_rdev);
 				return 0;
-				
+			case HDIO_SET_DMA:
+				if (!suser())
+					return -EACCES;
+				if (xdc_busy)
+					return -EBUSY;
+				nodma = !arg;
+				if (nodma && xd_dma_buffer) {
+					xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
+					xd_dma_buffer = 0;
+				}
+				return 0;
+			case HDIO_GET_DMA:
+				return write_fs_long(arg, !nodma);
+			case HDIO_GET_MULTCOUNT:
+				return write_fs_long(arg, xd_maxsectors);
 			case BLKRRPART:
 				return (xd_reread_partitions(inode->i_rdev));
 			RO_IOCTLS(inode->i_rdev,arg);
@@ -305,6 +400,11 @@
 	if (dev < xd_drives) {
 		sync_dev(inode->i_rdev);
 		xd_access[dev]--;
+
+#ifdef MODULE
+		MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+
 	}
 }
 
@@ -343,13 +443,17 @@
 {
 	u_char cmdblk[6],sense[4];
 	u_short track,cylinder;
-	u_char head,sector,control,mode,temp;
+	u_char head,sector,control,mode = PIO_MODE,temp;
+	char **real_buffer;
+	register int i;
 	
 #ifdef DEBUG_READWRITE
 	printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 #endif /* DEBUG_READWRITE */
 
 	control = xd_info[drive].control;
+	if (!xd_dma_buffer)
+		xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
 	while (count) {
 		temp = count < xd_maxsectors ? count : xd_maxsectors;
 
@@ -362,10 +466,18 @@
 		printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
 #endif /* DEBUG_READWRITE */
 
-		mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200);
+		if (xd_dma_buffer) {
+			mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
+			real_buffer = &xd_dma_buffer;
+			for (i=0; i < (temp * 0x200); i++)
+				xd_dma_buffer[i] = buffer[i];
+		}
+		else
+			real_buffer = &buffer;
+
 		xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
 
-		switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) {
+		switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
 			case 1:
 				printk("xd_readwrite: timeout, recalibrating drive\n");
 				xd_recalibrate(drive);
@@ -383,6 +495,10 @@
 					printk(" - no valid disk address\n");
 				return (0);
 		}
+		if (xd_dma_buffer)
+			for (i=0; i < (temp * 0x200); i++)
+				buffer[i] = xd_dma_buffer[i];
+
 		count -= temp, buffer += temp * 0x200, block += temp;
 	}
 	return (1);
@@ -412,28 +528,24 @@
 		printk("xd_interrupt_handler: unexpected interrupt\n");
 }
 
-/* xd_dma: set up the DMA controller for a data transfer */
+/* xd_setup_dma: set up the DMA controller for a data transfer */
 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
 {
-	if (buffer < ((u_char *) 0x1000000 - count)) {		/* transfer to address < 16M? */
-		if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) {
+	if (nodma)
+		return (PIO_MODE);
+	if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) {
 #ifdef DEBUG_OTHER
 			printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 #endif /* DEBUG_OTHER */
-			return (PIO_MODE);
-		}
-		disable_dma(xd_dma);
-		clear_dma_ff(xd_dma);
-		set_dma_mode(xd_dma,mode);
-		set_dma_addr(xd_dma,(u_int) buffer);
-		set_dma_count(xd_dma,count);
-
-		return (DMA_MODE);			/* use DMA and INT */
+		return (PIO_MODE);
 	}
-#ifdef DEBUG_OTHER
-	printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
-#endif /* DEBUG_OTHER */
-	return (PIO_MODE);
+	disable_dma(xd_dma);
+	clear_dma_ff(xd_dma);
+	set_dma_mode(xd_dma,mode);
+	set_dma_addr(xd_dma,(u_int) buffer);
+	set_dma_count(xd_dma,count);
+
+	return (DMA_MODE);			/* use DMA and INT */
 }
 
 /* xd_build: put stuff into an array in a format suitable for the controller */
@@ -445,19 +557,57 @@
 	cmdblk[3] = cylinder & 0xFF;
 	cmdblk[4] = count;
 	cmdblk[5] = control;
-	
+
 	return (cmdblk);
 }
 
+/* xd_wakeup is called from timer interrupt */
+static void xd_wakeup (void)
+{
+	wake_up(&xdc_wait);
+}
+
+/* xd_wakeup is called from timer interrupt */
+static void xd_watchdog (void)
+{
+	xd_error = 1;
+	wake_up(&xd_wait_int);
+}
+
 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
 {
 	u_long expiry = jiffies + timeout;
+	int success;
 
-	while (((inb(port) & mask) != flags) && (jiffies < expiry))
-		;
-
-	return (jiffies >= expiry);
+	xdc_busy = 1;
+	while ((success = ((inb(port) & mask) != flags)) && (jiffies < expiry)) {
+		xd_timer.expires = jiffies;
+		cli();
+		add_timer(&xd_timer);
+		sleep_on(&xdc_wait);
+		del_timer(&xd_timer);
+		sti();
+	}
+	xdc_busy = 0;
+	return (success);
+}
+
+static inline u_int xd_wait_for_IRQ (void)
+{
+	xd_watchdog_int.expires = jiffies + 8 * HZ;
+	add_timer(&xd_watchdog_int);
+	enable_dma(xd_dma);
+	sleep_on(&xd_wait_int);
+	del_timer(&xd_watchdog_int);
+	xdc_busy = 0;
+	disable_dma(xd_dma);
+	if (xd_error) {
+		printk("xd: missed IRQ - command aborted\n");
+		xd_error = 0;
+		return (1);
+	}
+	return (0);
 }
 
 /* xd_command: handle all data transfers necessary for a single command */
@@ -481,17 +631,15 @@
 		switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
 			case 0:
 				if (mode == DMA_MODE) {
-					enable_dma(xd_dma);
-					sleep_on(&xd_wait_int);
-					disable_dma(xd_dma);
+					if (xd_wait_for_IRQ())
+						return (1);
 				} else
 					outb(outdata ? *outdata++ : 0,XD_DATA);
 				break;
 			case STAT_INPUT:
 				if (mode == DMA_MODE) {
-					enable_dma(xd_dma);
-					sleep_on(&xd_wait_int);
-					disable_dma(xd_dma);
+					if (xd_wait_for_IRQ())
+						return (1);
 				} else
 					if (indata)
 						*indata++ = inb(XD_DATA);
@@ -531,28 +679,93 @@
 	for (i = 0; i < XD_MAXDRIVES; i++) {
 		xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 		if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) {
+	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
+			add_timer(&xd_timer);
+			sleep_on(&xdc_wait);
+
 			init_drive(count);
 			count++;
+
+	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
+			add_timer(&xd_timer);
+			sleep_on(&xdc_wait);
 		}
 	}
 	return (count);
 }
 
+static void xd_manual_geo_set (u_char drive)
+{
+	xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
+	xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
+	xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
+}
+
 static void xd_dtc_init_controller (u_char *address)
 {
 	switch ((u_long) address) {
-		case 0xC8000:	xd_iobase = 0x320; break;
-		case 0xCA000:	xd_iobase = 0x324; break;
+		case 0x00000:
+		case 0xC8000:	break;			/*initial: 0x320 */
+		case 0xCA000:	xd_iobase = 0x324; 
+				break;
+		case 0xD0000:				/*5150CX*/
+		case 0xD8000:	break;			/*5150CX & 5150XL*/
 		default:        printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
-				xd_iobase = 0x320; break;
+				break;
 	}
-	xd_irq = 5;			/* the IRQ _can_ be changed on this card, but requires a hardware mod */
-	xd_dma = 3;
 	xd_maxsectors = 0x01;		/* my card seems to have trouble doing multi-block transfers? */
 
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
+
+static void xd_dtc5150cx_init_drive (u_char drive)
+{
+	/* values from controller's BIOS - BIOS chip may be removed */
+	static u_short geometry_table[][4] = {
+		{0x200,8,0x200,0x100},
+		{0x267,2,0x267,0x267},
+		{0x264,4,0x264,0x80},
+		{0x132,4,0x132,0x0},
+		{0x132,2,0x80, 0x132},
+		{0x177,8,0x177,0x0},
+		{0x132,8,0x84, 0x0},
+		{},  /* not used */
+		{0x132,6,0x80, 0x100},
+		{0x200,6,0x100,0x100},
+		{0x264,2,0x264,0x80},
+		{0x280,4,0x280,0x100},
+		{0x2B9,3,0x2B9,0x2B9},
+		{0x2B9,5,0x2B9,0x2B9},
+		{0x280,6,0x280,0x100},
+		{0x132,4,0x132,0x0}};
+	u_char n;
+
+	n = inb(XD_JUMPER);
+	n = (drive ? n : (n >> 2)) & 0x33;
+	n = (n | (n >> 2)) & 0x0F;
+	if (xd_geo[3*drive])
+		xd_manual_geo_set(drive);
+	else
+		if (n != 7) {	
+			xd_info[drive].heads = (u_char)(geometry_table[n][1]);			/* heads */
+			xd_info[drive].cylinders = geometry_table[n][0];	/* cylinders */
+			xd_info[drive].sectors = 17;				/* sectors */
+#if 0
+			xd_info[drive].rwrite = geometry_table[n][2];	/* reduced write */
+			xd_info[drive].precomp = geometry_table[n][3]		/* write precomp */
+			xd_info[drive].ecc = 0x0B;				/* ecc length */
+#endif /* 0 */
+		}
+		else {
+			printk("xd%c: undetermined drive geometry\n",'a'+drive);
+			return;
+		}
+	xd_info[drive].control = 5;				/* control byte */
+	xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
+	xd_recalibrate(drive);
+}
+
 static void xd_dtc_init_drive (u_char drive)
 {
 	u_char cmdblk[6],buf[64];
@@ -562,6 +775,8 @@
 		xd_info[drive].heads = buf[0x0A];			/* heads */
 		xd_info[drive].cylinders = ((u_short *) (buf))[0x04];	/* cylinders */
 		xd_info[drive].sectors = 17;				/* sectors */
+		if (xd_geo[3*drive])
+			xd_manual_geo_set(drive);
 #if 0
 		xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05];	/* reduced write */
 		xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06];	/* write precomp */
@@ -581,31 +796,60 @@
 static void xd_wd_init_controller (u_char *address)
 {
 	switch ((u_long) address) {
-		case 0xC8000:	xd_iobase = 0x320; break;
+		case 0x00000:
+		case 0xC8000:	break;			/*initial: 0x320 */
 		case 0xCA000:	xd_iobase = 0x324; break;
 		case 0xCC000:   xd_iobase = 0x328; break;
 		case 0xCE000:   xd_iobase = 0x32C; break;
 		case 0xD0000:	xd_iobase = 0x328; break;
 		case 0xD8000:	xd_iobase = 0x32C; break;
 		default:        printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
-				xd_iobase = 0x320; break;
+				break;
 	}
-	xd_irq = 5;			/* don't know how to auto-detect this yet */
-	xd_dma = 3;
 	xd_maxsectors = 0x01;		/* this one doesn't wrap properly either... */
 
-	/* outb(0,XD_RESET); */		/* reset the controller */
+	outb(0,XD_RESET);		/* reset the controller */
+
+	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
+	add_timer(&xd_timer);
+	sleep_on(&xdc_wait);
 }
 
 static void xd_wd_init_drive (u_char drive)
 {
+	/* values from controller's BIOS - BIOS may be disabled */
+	static u_short geometry_table[][4] = {
+		{0x264,4,0x1C2,0x1C2},   /* common part */
+		{0x132,4,0x099,0x0},
+		{0x267,2,0x1C2,0x1C2},
+		{0x267,4,0x1C2,0x1C2},
+
+		{0x334,6,0x335,0x335},   /* 1004 series RLL */
+		{0x30E,4,0x30F,0x3DC},
+		{0x30E,2,0x30F,0x30F},
+		{0x267,4,0x268,0x268},
+
+		{0x3D5,5,0x3D6,0x3D6},   /* 1002 series RLL */
+		{0x3DB,7,0x3DC,0x3DC},
+		{0x264,4,0x265,0x265},
+		{0x267,4,0x268,0x268}};
+
 	u_char cmdblk[6],buf[0x200];
+	u_char n = 0,rll,jumper_state,use_jumper_geo;
+	u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
+	
+	jumper_state = ~(inb(0x322));
+	if (jumper_state & 0x40)
+		xd_irq = 9;
+	rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
 
 	xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
 	if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 		xd_info[drive].heads = buf[0x1AF];				/* heads */
 		xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6];	/* cylinders */
 		xd_info[drive].sectors = 17;					/* sectors */
+		if (xd_geo[3*drive])
+			xd_manual_geo_set(drive);
 #if 0
 		xd_info[drive].rwrite = ((u_short *) (buf))[0xD8];		/* reduced write */
 		xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA];		/* write precomp */
@@ -613,7 +857,43 @@
 #endif /* 0 */
 		xd_info[drive].control = buf[0x1B5];				/* control byte */
 
-		xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
+		use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
+		if (xd_geo[3*drive]) {
+			xd_manual_geo_set(drive);
+			xd_info[drive].control = rll ? 7 : 5;
+		}
+		else if (use_jumper_geo) {
+			n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
+			xd_info[drive].cylinders = geometry_table[n][0];
+			xd_info[drive].heads = (u_char)(geometry_table[n][1]);
+			xd_info[drive].control = rll ? 7 : 5;
+#if 0
+			xd_info[drive].rwrite = geometry_table[n][2];
+			xd_info[drive].wprecomp = geometry_table[n][3];
+			xd_info[drive].ecc = 0x0B;
+#endif /* 0 */
+		}
+		if (!wd_1002)
+			if (use_jumper_geo)
+				xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
+					geometry_table[n][2],geometry_table[n][3],0x0B);
+			else
+				xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
+					((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
+	/* 1002 based RLL controler requests converted adressing, but reports physical 
+	   (physical 26 sec., logical 17 sec.) 
+	   1004 based ???? */
+		if (rll & wd_1002) {
+			if ((xd_info[drive].cylinders *= 26,
+			     xd_info[drive].cylinders /= 17) > 1023)
+				xd_info[drive].cylinders = 1023;  /* 1024 ? */
+#if 0
+			xd_info[drive].rwrite *= 26; 
+			xd_info[drive].rwrite /= 17;
+			xd_info[drive].wprecomp *= 26
+			xd_info[drive].wprecomp /= 17;
+#endif /* 0 */
+		}
 	}
 	else
 		printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);	
@@ -622,15 +902,14 @@
 static void xd_seagate_init_controller (u_char *address)
 {
 	switch ((u_long) address) {
-		case 0xC8000:	xd_iobase = 0x320; break;
+		case 0x00000:
+		case 0xC8000:	break;			/*initial: 0x320 */
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
 		default:	printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
-				xd_iobase = 0x320; break;
+				break;
 	}
-	xd_irq = 5;			/* the IRQ and DMA channel are fixed on the Seagate controllers */
-	xd_dma = 3;
 	xd_maxsectors = 0x40;
 
 	outb(0,XD_RESET);		/* reset the controller */
@@ -655,16 +934,15 @@
 static void xd_omti_init_controller (u_char *address)
 {
 	switch ((u_long) address) {
-		case 0xC8000:	xd_iobase = 0x320; break;
+		case 0x00000:
+		case 0xC8000:	break;			/*initial: 0x320 */
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
 		default:	printk("xd_omti_init_controller: unsupported BIOS address %p\n",address);
-				xd_iobase = 0x320; break;
+				break;
 	}
 	
-	xd_irq = 5;			/* the IRQ and DMA channel are fixed on the Omti controllers */
-	xd_dma = 3;
 	xd_maxsectors = 0x40;
 
 	outb(0,XD_RESET);		/* reset the controller */
@@ -679,6 +957,81 @@
 	xd_info[drive].control = 2;
 }
 
+/* Xebec support (AK) */
+static void xd_xebec_init_controller (u_char *address)
+{
+/* iobase may be set manually in range 0x300 - 0x33C
+      irq may be set manually to 2(9),3,4,5,6,7
+      dma may be set manually to 1,2,3
+	(How to detect them ???)
+BIOS address may be set manually in range 0x0 - 0xF8000
+If you need non-standard settings use the xd=... command */
+
+	switch ((u_long) address) {
+		case 0x00000:
+		case 0xC8000:	/* initially: xd_iobase==0x320 */
+		case 0xD0000:
+		case 0xD2000:
+		case 0xD4000:
+		case 0xD6000:
+		case 0xD8000:
+		case 0xDA000:
+		case 0xDC000:
+		case 0xDE000:
+		case 0xE0000:	break;
+		default:	printk("xd_xebec_init_controller: unsupported BIOS address %p\n",address);
+				break;
+	}
+	
+	xd_maxsectors = 0x01;
+	outb(0,XD_RESET);		/* reset the controller */
+
+	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
+	add_timer(&xd_timer);
+	sleep_on(&xdc_wait);
+}
+
+static void xd_xebec_init_drive (u_char drive)
+{
+	/* values from controller's BIOS - BIOS chip may be removed */
+	static u_short geometry_table[][5] = {
+		{0x132,4,0x080,0x080,0x7},
+		{0x132,4,0x080,0x080,0x17},
+		{0x264,2,0x100,0x100,0x7},
+		{0x264,2,0x100,0x100,0x17},
+		{0x132,8,0x080,0x080,0x7},
+		{0x132,8,0x080,0x080,0x17},
+		{0x264,4,0x100,0x100,0x6},
+		{0x264,4,0x100,0x100,0x17},
+		{0x2BC,5,0x2BC,0x12C,0x6},
+		{0x3A5,4,0x3A5,0x3A5,0x7},
+		{0x26C,6,0x26C,0x26C,0x7},
+		{0x200,8,0x200,0x100,0x17},
+		{0x400,5,0x400,0x400,0x7},
+		{0x400,6,0x400,0x400,0x7},
+		{0x264,8,0x264,0x200,0x17},
+		{0x33E,7,0x33E,0x200,0x7}};
+	u_char n;
+
+	n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry 
+					is assumed for BOTH drives */
+	if (xd_geo[3*drive])
+		xd_manual_geo_set(drive);
+	else {
+		xd_info[drive].heads = (u_char)(geometry_table[n][1]);			/* heads */
+		xd_info[drive].cylinders = geometry_table[n][0];	/* cylinders */
+		xd_info[drive].sectors = 17;				/* sectors */
+#if 0
+		xd_info[drive].rwrite = geometry_table[n][2];	/* reduced write */
+		xd_info[drive].precomp = geometry_table[n][3]		/* write precomp */
+		xd_info[drive].ecc = 0x0B;				/* ecc length */
+#endif /* 0 */
+	}
+	xd_info[drive].control = geometry_table[n][4];			/* control byte */
+	xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
+	xd_recalibrate(drive);
+}
+
 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
 static void xd_override_init_drive (u_char drive)
@@ -686,36 +1039,63 @@
 	u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
 	u_char cmdblk[6],i;
 
-	for (i = 0; i < 3; i++) {
-		while (min[i] != max[i] - 1) {
-			test[i] = (min[i] + max[i]) / 2;
-			xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
-			if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
-				min[i] = test[i];
-			else
-				max[i] = test[i];
+	if (xd_geo[3*drive])
+		xd_manual_geo_set(drive);
+	else {
+		for (i = 0; i < 3; i++) {
+			while (min[i] != max[i] - 1) {
+				test[i] = (min[i] + max[i]) / 2;
+				xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
+				if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
+					min[i] = test[i];
+				else
+					max[i] = test[i];
+			}
+			test[i] = min[i];
 		}
-		test[i] = min[i];
+		xd_info[drive].heads = (u_char) min[0] + 1;
+		xd_info[drive].cylinders = (u_short) min[1] + 1;
+		xd_info[drive].sectors = (u_char) min[2] + 1;
 	}
-	xd_info[drive].heads = (u_char) min[0] + 1;
-	xd_info[drive].cylinders = (u_short) min[1] + 1;
-	xd_info[drive].sectors = (u_char) min[2] + 1;
 	xd_info[drive].control = 0;
 }
 
-/* xd_setup: initialise from command line parameters */
+/* xd_setup: initialise controler from command line parameters */
 void xd_setup (char *command,int *integers)
 {
-	xd_override = 1;
-
-	xd_type = integers[1];
-	xd_irq = integers[2];
-	xd_iobase = integers[3];
-	xd_dma = integers[4];
-
+	switch (integers[0]) {
+		case 4: if (integers[4] < 0)
+				nodma = 1;
+			else if (integers[4] < 8)
+				xd_dma = integers[4];
+		case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
+				xd_iobase = integers[3];
+		case 2: if ((integers[2] > 0) && (integers[2] < 16))
+				xd_irq = integers[2];
+		case 1: xd_override = 1;
+			if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0]))))
+				xd_type = integers[1];
+		case 0: break;
+		default:printk("xd: too many parameters for xd\n");
+	}
 	xd_maxsectors = 0x01;
 }
 
+#ifndef MODULE
+/* xd_manual_geo_init: initialise drive geometry from command line parameters
+   (used only for WD drives) */
+void xd_manual_geo_init (char *command,int *integers)
+{
+	int i;
+	if (integers[0]%3 != 0) {
+		printk("xd: incorrect number of parameters for xd_geo\n");
+		return;
+	}
+	for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
+		xd_geo[i] = integers[i+1];
+}
+#endif /* MODULE */
+
 /* xd_setparam: set the drive characteristics */
 static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
 {
@@ -731,19 +1111,55 @@
 	cmdblk[12] = (u_char) (wprecomp & 0xFF);
 	cmdblk[13] = ecc;
 
-	if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
+	/* Some controllers require geometry info as data, not command */
+	
+	if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2))
 		printk("xd_setparam: error setting characteristics for drive %d\n",drive);
 }
 
 
 #ifdef MODULE
+static int xd[5] = { -1,-1,-1,-1, };
+
+static void xd_done (void)
+{
+	struct gendisk ** gdp;
+	
+	blksize_size[MAJOR_NR] = NULL;
+	blk_dev[MAJOR_NR].request_fn = NULL;
+	blk_size[MAJOR_NR] = NULL;
+	hardsect_size[MAJOR_NR] = NULL;
+	read_ahead[MAJOR_NR] = 0;
+	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+		if (*gdp == &xd_gendisk)
+			break;
+	if (*gdp)
+		*gdp = (*gdp)->next;
+	release_region(xd_iobase,4);
+}
+
 int init_module(void)
 {
+	int i,count = 0;
 	int error = xd_init();
+
 	if (!error)
 	{
 		printk(KERN_INFO "XD: Loaded as a module.\n");
+		for (i = 4; i > 0; i--)
+			if(((xd[i] = xd[i-1]) >= 0) && !count)
+				count = i;
+		if((xd[0] = count));
+			xd_setup(NULL, xd);
 		xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 });
+		if (!xd_drives) {
+					/* no drives detected - unload module */
+			unregister_blkdev(MAJOR_NR, "xd");
+			xd_done();
+			return (-1);
+		}
+		for (i = 0; i < xd_drives; i++)
+			resetup_one_dev(&xd_gendisk, i);
 	}
         
 	return error;
@@ -751,9 +1167,25 @@
 
 void cleanup_module(void)
 {
+	int partition,dev,start;
+
 	unregister_blkdev(MAJOR_NR, "xd");
-	free_irq(xd_irq, NULL);
-	free_dma(xd_dma);
+	for (dev = 0; dev < xd_drives; dev++) {
+		start = dev << xd_gendisk.minor_shift; 
+		for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
+			int minor = (start | partition);
+			kdev_t devp = MKDEV(MAJOR_NR, minor);
+			start = dev << xd_gendisk.minor_shift; 
+			sync_dev(devp);
+			invalidate_buffers(devp);
+		}
+	}
+	xd_done();
+	if (xd_drives) {
+		free_irq(xd_irq, NULL);
+		free_dma(xd_dma);
+		if (xd_dma_buffer)
+			xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
+	}
 }
 #endif /* MODULE */
-
diff -u --recursive --new-file v2.0.33/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.0.33/linux/drivers/cdrom/cdrom.c	Sat Aug 17 11:19:26 1996
+++ linux/drivers/cdrom/cdrom.c	Wed Jun  3 15:17:47 1998
@@ -97,7 +97,9 @@
 
 /* We need our own cdrom error types! This is a temporary solution. */
 
+#ifndef ENOMEDIUM
 #define ENOMEDIUM EAGAIN				/* no medium in removable device */
+#endif
 
 /* We use the open-option O_NONBLOCK to indicate that the
  * purpose of opening is only for subsequent ioctl() calls; no device
diff -u --recursive --new-file v2.0.33/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.0.33/linux/drivers/char/Config.in	Tue Aug 12 13:06:54 1997
+++ linux/drivers/char/Config.in	Wed Jun  3 15:17:47 1998
@@ -57,6 +57,10 @@
   bool '   Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
   bool '   Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
   bool '   Power off on shutdown' CONFIG_APM_POWER_OFF
+  bool '   Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+fi
+if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
+  bool 'Tadpole ANA H8 Support'	CONFIG_H8
 fi
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
diff -u --recursive --new-file v2.0.33/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.0.33/linux/drivers/char/Makefile	Tue Aug 12 13:06:54 1997
+++ linux/drivers/char/Makefile	Wed Jun  3 15:17:47 1998
@@ -196,6 +196,11 @@
 M = y
 endif
 
+ifdef CONFIG_H8
+LX_OBJS += h8.o
+M = y
+endif
+
 ifdef M
 LX_OBJS += misc.o
 else
@@ -222,6 +227,9 @@
 
 ifdef CONFIG_TGA_CONSOLE
 L_OBJS += tga.o
+  ifdef CONFIG_VGA_CONSOLE
+    L_OBJS += vga.o vesa_blank.o
+  endif
 else
  ifndef CONFIG_SUN_CONSOLE
  L_OBJS += vga.o vesa_blank.o
diff -u --recursive --new-file v2.0.33/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- v2.0.33/linux/drivers/char/apm_bios.c	Tue May 14 23:06:55 1996
+++ linux/drivers/char/apm_bios.c	Wed Jun  3 15:17:47 1998
@@ -124,6 +124,11 @@
  * problems have been reported when using this option with gpm (if you'd
  * like to debug this, please do so).
  *
+ * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist
+ * on returning multiple suspend/standby events whenever one occurs.  We
+ * really only need one at a time, so just ignore any beyond the first.
+ * This is probably safe on most laptops.
+ *
  * If you are debugging the APM support for your laptop, note that code for
  * all of these options is contained in this file, so you can #define or
  * #undef these on the next line to avoid recompiling the whole kernel.
@@ -330,6 +335,9 @@
 #endif
 static int			suspends_pending = 0;
 static int			standbys_pending = 0;
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+static int			waiting_for_resume = 0;
+#endif
 
 static long			clock_cmos_diff;
 static int			got_clock_diff = 0;
@@ -586,8 +594,15 @@
 		if (as == sender)
 			continue;
 		as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
-		if (as->event_head == as->event_tail)
+		if (as->event_head == as->event_tail) {
+			static int notified;
+
+			if (notified == 0) {
+			    printk( "apm_bios: an event queue overflowed\n" );
+			    notified = 1;
+			}
 			as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+		}
 		as->events[as->event_head] = event;
 		if (!as->suser)
 			continue;
@@ -692,9 +707,23 @@
 	apm_event_t	event;
 
 	while ((event = get_event()) != 0) {
+#ifdef APM_DEBUG
+		if (event <= NR_APM_EVENT_NAME)
+			printk("APM BIOS received %s notify\n",
+			       apm_event_name[event - 1]);
+		else
+			printk("APM BIOS received unknown event 0x%02x\n",
+			       event);
+#endif
 		switch (event) {
 		case APM_SYS_STANDBY:
 		case APM_USER_STANDBY:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+			if (waiting_for_resume) {
+			    return;
+			}
+			waiting_for_resume = 1;
+#endif
 			send_event(event, APM_STANDBY_RESUME, NULL);
 			if (standbys_pending <= 0)
 				standby();
@@ -707,6 +736,12 @@
 			break;
 #endif
 		case APM_SYS_SUSPEND:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+			if (waiting_for_resume) {
+			    return;
+			}
+			waiting_for_resume = 1;
+#endif
 			send_event(event, APM_NORMAL_RESUME, NULL);
 			if (suspends_pending <= 0)
 				suspend();
@@ -715,6 +750,9 @@
 		case APM_NORMAL_RESUME:
 		case APM_CRITICAL_RESUME:
 		case APM_STANDBY_RESUME:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+			waiting_for_resume = 0;
+#endif
 			set_time();
 			send_event(event, 0, NULL);
 			break;
@@ -732,14 +770,6 @@
 			suspend();
 			break;
 		}
-#ifdef APM_DEBUG
-		if (event <= NR_APM_EVENT_NAME)
-			printk("APM BIOS received %s notify\n",
-			       apm_event_name[event - 1]);
-		else
-			printk("APM BIOS received unknown event 0x%02x\n",
-			       event);
-#endif
 	}
 }
 
diff -u --recursive --new-file v2.0.33/linux/drivers/char/cd1865.h linux/drivers/char/cd1865.h
--- v2.0.33/linux/drivers/char/cd1865.h	Tue Aug 12 13:06:54 1997
+++ linux/drivers/char/cd1865.h	Wed Jun  3 15:17:47 1998
@@ -3,7 +3,7 @@
  *                          for the Specialix IO8+ multiport serial driver.
  *
  *      Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl)
- *      Copyright (C) 1994-1996  Dmitry Gorodchanin (begemot@bgm.rosprint.net)
+ *      Copyright (C) 1994-1996  Dmitry Gorodchanin (pgmdsg@ibi.com)
  *
  *      Specialix pays for the development and support of this driver.
  *      Please DO contact io8-linux@specialix.co.uk if you require
diff -u --recursive --new-file v2.0.33/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.0.33/linux/drivers/char/console.c	Tue Dec  2 13:52:31 1997
+++ linux/drivers/char/console.c	Wed Jun  3 15:17:47 1998
@@ -594,13 +594,15 @@
 	__set_origin(__real_origin);
 }
 
-void scrup(int currcons, unsigned int t, unsigned int b)
+static void scrup(int currcons, unsigned int t, unsigned int b, unsigned int nr)
 {
 	int hardscroll = hardscroll_enabled;
 
-	if (b > video_num_lines || t >= b)
+	if (t+nr >= b)
+		nr = b - t - 1;
+	if (b > video_num_lines || t >= b || nr < 1)
 		return;
-	if (t || b != video_num_lines)
+	if (t || b != video_num_lines || nr > 1)
 		hardscroll = 0;
 	if (hardscroll) {
 		origin += video_size_row;
@@ -641,40 +643,34 @@
 		set_origin(currcons);
 	} else {
 		unsigned short * d = (unsigned short *) (origin+video_size_row*t);
-		unsigned short * s = (unsigned short *) (origin+video_size_row*(t+1));
-		unsigned int count = (b-t-1) * video_num_columns;
+		unsigned short * s = (unsigned short *) (origin+video_size_row*(t+nr));
 
-		while (count) {
-			count--;
-			scr_writew(scr_readw(s++), d++);
-		}
-		count = video_num_columns;
-		while (count) {
-			count--;
-			scr_writew(video_erase_char, d++);
-		}
+		memcpyw(d, s, (b-t-nr) * video_size_row);
+		memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
 	}
 }
 
-void
-scrdown(int currcons, unsigned int t, unsigned int b)
+static void
+scrdown(int currcons, unsigned int t, unsigned int b, unsigned int nr)
 {
-	unsigned short *d, *s;
+	unsigned short *s;
 	unsigned int count;
+	unsigned int step;
 
-	if (b > video_num_lines || t >= b)
+	if (t+nr >= b)
+		nr = b - t - 1;
+	if (b > video_num_lines || t >= b || nr < 1)
 		return;
-	d = (unsigned short *) (origin+video_size_row*b);
-	s = (unsigned short *) (origin+video_size_row*(b-1));
-	count = (b-t-1)*video_num_columns;
-	while (count) {
-		count--;
-		scr_writew(scr_readw(--s), --d);
-	}
-	count = video_num_columns;
-	while (count) {
-		count--;
-		scr_writew(video_erase_char, --d);
+	s = (unsigned short *) (origin+video_size_row*(b-nr-1));
+	step = video_num_columns * nr;
+	count = b - t - nr;
+	while (count--) {
+		memcpyw(s + step, s, video_size_row);
+		s -= video_num_columns;
+	}
+	while (nr--) {
+		s += video_num_columns;
+		memsetw(s, video_erase_char, video_size_row);
 	}
 	has_scrolled = 1;
 }
@@ -685,7 +681,7 @@
 	 * if below scrolling region
 	 */
     	if (y+1 == bottom)
-		scrup(currcons,top,bottom);
+		scrup(currcons,top,bottom, 1);
 	else if (y < video_num_lines-1) {
 	    	y++;
 		pos += video_size_row;
@@ -699,7 +695,7 @@
 	 * if above scrolling region
 	 */
 	if (y == top)
-		scrdown(currcons,top,bottom);
+		scrdown(currcons,top,bottom, 1);
 	else if (y > 0) {
 		y--;
 		pos -= video_size_row;
@@ -1188,9 +1184,9 @@
 	need_wrap = 0;
 }
 
-static void insert_line(int currcons)
+static void insert_line(int currcons, unsigned int nr)
 {
-	scrdown(currcons,y,bottom);
+	scrdown(currcons, y, bottom, nr);
 	need_wrap = 0;
 }
 
@@ -1207,9 +1203,9 @@
 	need_wrap = 0;
 }
 
-static void delete_line(int currcons)
+static void delete_line(int currcons, unsigned int nr)
 {
-	scrup(currcons,y,bottom);
+	scrup(currcons, y, bottom, nr);
 	need_wrap = 0;
 }
 
@@ -1229,8 +1225,7 @@
 		nr = video_num_lines;
 	else if (!nr)
 		nr = 1;
-	while (nr--)
-		insert_line(currcons);
+	insert_line(currcons, nr);
 }
 
 static void csi_P(int currcons, unsigned int nr)
@@ -1249,8 +1244,7 @@
 		nr = video_num_lines;
 	else if (!nr)
 		nr=1;
-	while (nr--)
-		delete_line(currcons);
+	delete_line(currcons, nr);
 }
 
 static void save_cur(int currcons)
diff -u --recursive --new-file v2.0.33/linux/drivers/char/h8.c linux/drivers/char/h8.c
--- v2.0.33/linux/drivers/char/h8.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/h8.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,1272 @@
+/*
+ */
+/*
+ * Hitachi H8/337 Microcontroller driver
+ *
+ * The H8 is used to deal with the power and thermal environment
+ * of a system.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/linkage.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif
+#include <linux/miscdevice.h>
+#include <linux/lists.h>
+#include <linux/ioport.h>
+
+#define __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
+
+#include "h8.h"
+
+#define DEBUG_H8
+
+#ifdef DEBUG_H8
+#define Dprintk		printk
+#else
+#define Dprintk
+#endif
+
+#define XDprintk if(h8_debug==-1)printk
+
+/*
+ * The h8 device is one of the misc char devices.
+ */
+#define H8_MINOR_DEV   140
+
+/*
+ * Forward declarations.
+ */
+int          h8_init(void);
+int          h8_display_blank(void);
+int          h8_display_unblank(void);
+
+static int   h8_open(struct inode *, struct file *);
+static void  h8_release(struct inode *, struct file *);
+static long  h8_read(struct inode *, struct file *, char *, u_long);
+static int   h8_select(struct inode *, struct file *, int, select_table *);
+static int   h8_ioctl(struct inode *, struct file *, u_int, u_long);
+
+static void  h8_intr(int irq, void *dev_id, struct pt_regs *regs);
+
+#ifdef CONFIG_PROC_FS
+static int   h8_get_info(char *, char **, off_t, int, int);
+#endif
+
+/*
+ * Support Routines.
+ */
+static void h8_hw_init(void);
+static void h8_start_new_cmd(void);
+static void h8_send_next_cmd_byte(void);
+static void h8_read_event_status(void);
+static void h8_sync(void);
+static void h8_q_cmd(u_char *, int, int);
+static void h8_cmd_done(h8_cmd_q_t *qp);
+static int  h8_alloc_queues(void);
+
+static u_long h8_get_cpu_speed(void);
+static int h8_get_curr_temp(u_char curr_temp[]);
+static void h8_get_max_temp(void);
+static void h8_get_upper_therm_thold(void);
+static void h8_set_upper_therm_thold(int);
+static int h8_get_ext_status(u_char stat_word[]);
+
+static int h8_monitor_thread(void *);
+
+static int h8_manage_therm(void);
+static void h8_set_cpu_speed(int speed_divisor);
+
+static void h8_start_monitor_timer(unsigned long secs);
+static void h8_activate_monitor(unsigned long unused);
+
+/* in arch/alpha/kernel/lca.c */
+extern void lca_clock_print(void);
+extern int  lca_get_clock(void);
+extern void lca_clock_fiddle(int);
+
+static void h8_set_event_mask(int);
+static void h8_clear_event_mask(int);
+
+/*
+ * Driver structures
+ */
+
+static struct timer_list h8_monitor_timer;
+static int h8_monitor_timer_active = 0;
+
+static char  driver_version[] = "X0.0";/* no spaces */
+
+static struct file_operations h8_fops = {
+        NULL,           /* lseek */
+        h8_read,
+        NULL,           /* write */
+        NULL,           /* readdir */
+        h8_select,
+        h8_ioctl,
+        NULL,           /* mmap */
+        h8_open,
+        h8_release,
+        NULL,           /* fsync */
+        NULL            /* fasync */
+};
+
+static struct miscdevice h8_device = {
+        H8_MINOR_DEV,
+        "h8",
+        &h8_fops
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry    h8_proc_entry = {
+        0, 3, "h8", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, h8_get_info
+};
+#endif
+
+union	intr_buf intrbuf;
+int	intr_buf_ptr;
+union   intr_buf xx;	
+u_char  last_temp;
+
+/*
+ * I/O Macros for register reads and writes.
+ */
+#define H8_READ(a) 	inb((a))
+#define H8_WRITE(d,a)	outb((d),(a))
+
+#define	H8_GET_STATUS	H8_READ((h8_base) + H8_STATUS_REG_OFF)
+#define H8_READ_DATA	H8_READ((h8_base) + H8_DATA_REG_OFF)
+#define WRITE_DATA(d)	H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
+#define WRITE_CMD(d)	H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
+
+unsigned int h8_base = H8_BASE_ADDR;
+unsigned int h8_irq = H8_IRQ;
+unsigned int h8_state = H8_IDLE;
+unsigned int h8_index = -1;
+unsigned int h8_enabled = 0;
+
+queue_head_t h8_actq, h8_cmdq, h8_freeq;
+
+/* 
+ * Globals used in thermal control of Alphabook1.
+ */
+int cpu_speed_divisor = -1;			
+int h8_event_mask = 0;			
+struct wait_queue *h8_monitor_wait = NULL;
+unsigned int h8_command_mask = 0;
+int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
+int h8_uthermal_window = UTH_HYSTERESIS;		      
+int h8_debug = 0xfffffdfc;
+int h8_ldamp = MHZ_115;
+int h8_udamp = MHZ_57;
+u_char h8_current_temp = 0;
+u_char h8_system_temp = 0;
+int h8_sync_channel = 0;
+struct wait_queue *h8_sync_wait = NULL;
+int h8_init_performed;
+
+/* CPU speeds and clock divisor values */
+int speed_tab[6] = {230, 153, 115, 57, 28, 14};
+  
+/*
+ * H8 interrupt handler
+ */
+static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u_char	stat_reg, data_reg;
+	h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+
+	stat_reg = H8_GET_STATUS;
+	data_reg = H8_READ_DATA;
+
+	XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg);
+
+	switch (h8_state) {
+	  /* Response to an asynchronous event. */
+	case H8_IDLE: { /* H8_IDLE */
+	    if (stat_reg & H8_OFULL) {
+	        if (data_reg == H8_INTR) {
+		    h8_state = H8_INTR_MODE;
+		    /* Executing a command to determine what happened. */
+		    WRITE_CMD(H8_RD_EVENT_STATUS);
+		    intr_buf_ptr = 1;
+		    WRITE_CMD(H8_RD_EVENT_STATUS);
+		} else {
+		    Dprintk("h8_intr: idle stat 0x%x data 0x%x\n",
+			    stat_reg, data_reg);
+		}
+	    } else {
+	        Dprintk("h8_intr: bogus interrupt\n");
+	    }
+	    break;
+	}
+	case H8_INTR_MODE: { /* H8_INTR_MODE */
+	    XDprintk("H8 intr/intr_mode\n");
+	    if (data_reg == H8_BYTE_LEVEL_ACK) {
+	        return;
+	    } else if (data_reg == H8_CMD_ACK) {
+	        return;
+	    } else {
+	        intrbuf.byte[intr_buf_ptr] = data_reg;
+		if(!intr_buf_ptr) {
+		    h8_state = H8_IDLE;
+		    h8_read_event_status();
+		}
+		intr_buf_ptr--;
+	    }
+	    break;
+	}
+	/* Placed in this state by h8_start_new_cmd(). */
+	case H8_XMIT: { /* H8_XMIT */
+	    XDprintk("H8 intr/xmit\n");
+	    /* If a byte level acknowledgement has been received */
+	    if (data_reg == H8_BYTE_LEVEL_ACK) {
+	        XDprintk("H8 intr/xmit BYTE ACK\n");
+		qp->nacks++;
+		if (qp->nacks > qp->ncmd)
+		    if(h8_debug & 0x1)
+		        Dprintk("h8intr: bogus # of acks!\n");
+		/* 
+		 * If the number of bytes sent is less than the total 
+		 * number of bytes in the command.
+		 */ 
+		if (qp->cnt < qp->ncmd) {
+		    h8_send_next_cmd_byte();
+		}
+		return;
+		/* If the complete command has produced an acknowledgement. */
+	    } else if (data_reg == H8_CMD_ACK) {
+	        XDprintk("H8 intr/xmit CMD ACK\n");
+		/* If there are response bytes */
+		if (qp->nrsp)
+		    h8_state = H8_RCV;
+		else
+		    h8_state = H8_IDLE;
+		qp->cnt = 0;
+		return;
+		/* Error, need to start over with a clean slate. */
+	    } else if (data_reg == H8_NACK) {
+	        XDprintk("h8_intr: NACK received restarting command\n");
+		qp->nacks = 0;
+		qp->cnt = 0;
+		h8_state = H8_IDLE;
+		WRITE_CMD(H8_SYNC);
+		return;
+	    } else {
+	        Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg);
+		return;
+	    }
+	    break;
+	}
+	case H8_RESYNC: { /* H8_RESYNC */
+	    XDprintk("H8 intr/resync\n");
+	    if (data_reg == H8_BYTE_LEVEL_ACK) {
+	        return;
+	    } else if (data_reg == H8_SYNC_BYTE) {
+	        h8_state = H8_IDLE;
+		if (!QUEUE_EMPTY(&h8_actq, link))
+		    h8_send_next_cmd_byte();
+	    } else {
+	        Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
+		return;
+	    }
+	    break;
+	} 
+	case H8_RCV: { /* H8_RCV */
+	    XDprintk("H8 intr/rcv\n");
+	    if (qp->cnt < qp->nrsp) {
+	        qp->rcvbuf[qp->cnt] = data_reg;
+		qp->cnt++;
+		/* If command reception finished. */
+		if (qp->cnt == qp->nrsp) {
+		    h8_state = H8_IDLE;
+		    QUEUE_REMOVE(&h8_actq, qp, link);
+		    h8_cmd_done (qp);
+		    /* More commands to send over? */
+		    if (!QUEUE_EMPTY(&h8_cmdq, link))
+		        h8_start_new_cmd();
+		}
+		return;
+	    } else {
+	        Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]);
+	    }
+	    break;
+	}
+	default: /* default */
+	    Dprintk("H8 intr/unknown\n");
+	    break;
+	}
+	return;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+        printk("H8 module at %X(Interrupt %d)\n", h8_base, h8_irq);
+        if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
+        {
+                printk("H8: error: IRQ %d is not free.\n", h8_irq);
+                return -EIO;
+        }
+
+        misc_register(&h8_device);
+        request_region(h8_base, 8, "h8");
+
+#ifdef CONFIG_PROC_FS
+        proc_register_dynamic(&proc_root, &h8_proc_entry);
+#endif
+
+	QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
+	QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
+	QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *);
+	h8_alloc_queues();
+
+	h8_hw_init();
+
+	kernel_thread(h8_monitor_thread, NULL, 0);
+
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        misc_deregister(&h8_device);
+        release_region(h8_base, 8);
+        free_irq(h8_irq, NULL);
+}
+
+#else /* MODULE */
+
+int h8_init(void)
+{
+        if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
+        {
+                printk("H8: error: IRQ %d is not free\n", h8_irq);
+                return -EIO;
+        }
+        printk("H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
+
+#ifdef CONFIG_PROC_FS
+        proc_register_dynamic(&proc_root, &h8_proc_entry);
+#endif
+
+        misc_register(&h8_device);
+        request_region(h8_base, 8, "h8");
+
+	QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
+	QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
+	QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *);
+	h8_alloc_queues();
+
+	h8_hw_init();
+
+	kernel_thread(h8_monitor_thread, NULL, 0);
+
+        return 0;
+}
+#endif /* MODULE */
+
+void h8_hw_init(void)
+{
+	u_char	buf[H8_MAX_CMD_SIZE];
+
+	/* set CPU speed to max for booting */
+	h8_set_cpu_speed(MHZ_230);
+
+	/*
+	 * Initialize the H8
+	 */
+	h8_sync();  /* activate interrupts */
+
+	/* To clear conditions left by console */
+	h8_read_event_status(); 
+
+	/* Perform a conditioning read */
+	buf[0] = H8_DEVICE_CONTROL;
+	buf[1] = 0xff;
+	buf[2] = 0x0;
+	h8_q_cmd(buf, 3, 1);
+
+	/* Turn on built-in and external mice, capture power switch */
+	buf[0] = H8_DEVICE_CONTROL;
+	buf[1] = 0x0;
+	buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
+	       /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
+	h8_q_cmd(buf, 3, 1);
+
+        h8_enabled = 1;
+	return;
+}
+
+#ifdef CONFIG_PROC_FS
+int h8_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
+{
+        char *p;
+
+        if (!h8_enabled)
+                return 0;
+        p = buf;
+
+
+        /*
+           0) Linux driver version (this will change if format changes)
+           1) 
+           2) 
+           3)
+           4)
+	*/
+            
+        p += sprintf(p, "%s \n",
+                     driver_version
+		     );
+
+        return p - buf;
+}
+#endif
+
+static long h8_read(struct inode *inode, struct file *fp, char *buf,
+		    u_long count)
+{
+	printk("h8_read: IMPDEL\n");
+	return 0;
+}
+
+static int h8_select(struct inode *inode, struct file *fp, int sel_type,
+                     select_table * wait)
+{
+	printk("h8_select: IMPDEL\n");
+	return 0;
+}
+
+static int h8_ioctl(struct inode * inode, struct file *filp,
+                    u_int cmd, u_long arg)
+{
+	printk("h8_ioctl: IMPDEL\n");
+	return 0;
+}
+
+static void h8_release(struct inode * inode, struct file * filp)
+{
+	printk("h8_release: IMPDEL\n");
+}
+
+static int h8_open(struct inode * inode, struct file * filp)
+{
+	printk("h8_open: IMPDEL\n");
+	return 0;
+}
+
+/* Called from console driver -- must make sure h8_enabled. */
+int h8_display_blank(void)
+{
+#ifdef CONFIG_H8_DISPLAY_BLANK
+        int     error;
+
+        if (!h8_enabled)
+                return 0;
+        error = h8_set_display_power_state(H8_STATE_STANDBY);
+        if (error == H8_SUCCESS)
+                return 1;
+        h8_error("set display standby", error);
+#endif
+        return 0;
+}
+
+/* Called from console driver -- must make sure h8_enabled. */
+int h8_display_unblank(void)
+{
+#ifdef CONFIG_H8_DISPLAY_BLANK
+        int error;
+
+        if (!h8_enabled)
+                return 0;
+        error = h8_set_display_power_state(H8_STATE_READY);
+        if (error == H8_SUCCESS)
+                return 1;
+        h8_error("set display ready", error);
+#endif
+        return 0;
+}
+
+int
+h8_alloc_queues(void)
+{
+        h8_cmd_q_t *qp;
+	unsigned long flags;
+        int i;
+
+        qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
+				   GFP_KERNEL);
+
+        if (!qp) {
+                printk("H8: could not allocate memory for command queue\n");
+                return(0);
+        }
+        /* add to the free queue */
+        save_flags(flags); cli();
+        for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
+                /* place each at front of freeq */
+                QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *);
+        }
+        restore_flags(flags);
+        return (1);
+}
+
+/* 
+ * Basic means by which commands are sent to the H8.
+ */
+void
+h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
+{
+        h8_cmd_q_t      *qp;
+	unsigned long flags;
+        int             i;
+
+        /* get cmd buf */
+	save_flags(flags); cli();
+        while (QUEUE_EMPTY(&h8_freeq, link)) {
+                Dprintk("H8: need to allocate more cmd buffers\n");
+                restore_flags(flags);
+                h8_alloc_queues();
+                save_flags(flags); cli();
+        }
+        /* get first element from queue */
+        qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link);
+        QUEUE_REMOVE(&h8_freeq, qp, link);
+
+        restore_flags(flags);
+
+        /* fill it in */
+        for (i = 0; i < cmd_size; i++)
+            qp->cmdbuf[i] = cmd[i];
+        qp->ncmd = cmd_size;
+        qp->nrsp = resp_size;
+
+        /* queue it at the end of the cmd queue */
+        save_flags(flags); cli();
+
+        QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *);
+
+        restore_flags(flags);
+
+        h8_start_new_cmd();
+}
+
+void
+h8_start_new_cmd(void)
+{
+        unsigned long flags;
+        h8_cmd_q_t *qp;
+
+	save_flags(flags); cli();
+        if (h8_state != H8_IDLE) {
+                if (h8_debug & 0x1)
+                        Dprintk("h8_start_new_cmd: not idle\n");
+                restore_flags(flags);
+                return;
+        }
+
+        if (!QUEUE_EMPTY(&h8_actq, link)) {
+                Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
+                restore_flags(flags);
+                return;
+        }
+
+        if (QUEUE_EMPTY(&h8_cmdq, link)) {
+                Dprintk("h8_start_new_cmd: no command to dequeue\n");
+                restore_flags(flags);
+                return;
+        }
+        /*
+         * Take first command off of the command queue and put
+         * it on the active queue.
+         */
+        qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link);
+        QUEUE_REMOVE(&h8_cmdq, qp, link);
+        QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *);
+        h8_state = H8_XMIT;
+        if (h8_debug & 0x1)
+                Dprintk("h8_start_new_cmd: Starting a command\n");
+
+        qp->cnt = 1;
+        WRITE_CMD(qp->cmdbuf[0]);               /* Kick it off */
+
+        restore_flags(flags);
+        return;
+}
+
+void
+h8_send_next_cmd_byte(void)
+{
+        h8_cmd_q_t      *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+        int cnt;
+
+        cnt = qp->cnt;
+        qp->cnt++;
+
+        if (h8_debug & 0x1)
+                Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n",
+			cnt, qp->cmdbuf[cnt]);
+
+        if (cnt) {
+                WRITE_DATA(qp->cmdbuf[cnt]);
+        } else {
+                WRITE_CMD(qp->cmdbuf[cnt]);
+        }
+        return;
+}
+
+/*
+ * Synchronize H8 communications channel for command transmission.
+ */
+void
+h8_sync(void)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        buf[0] = H8_SYNC;
+        buf[1] = H8_SYNC_BYTE;
+        h8_q_cmd(buf, 2, 1);
+}
+
+/*
+ * Responds to external interrupt. Reads event status word and 
+ * decodes type of interrupt. 
+ */
+void
+h8_read_event_status(void)
+{
+
+        if(h8_debug & 0x200)
+                printk("h8_read_event_status: value 0x%x\n", intrbuf.word);
+
+        /*
+         * Power related items
+         */
+        if (intrbuf.word & H8_DC_CHANGE) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: DC_CHANGE\n");
+                /* see if dc added or removed, set batt/dc flag, send event */
+
+                h8_set_event_mask(H8_MANAGE_BATTERY);
+                wake_up(&h8_monitor_wait);
+        }
+
+        if (intrbuf.word & H8_POWER_BUTTON) {
+                printk("Power switch pressed - please wait - preparing to power 
+off\n");
+                h8_set_event_mask(H8_POWER_BUTTON);
+                wake_up(&h8_monitor_wait);
+        }
+
+        /*
+         * Thermal related items
+         */
+        if (intrbuf.word & H8_THERMAL_THRESHOLD) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: THERMAL_THRESHOLD\n");
+                h8_set_event_mask(H8_MANAGE_UTHERM);
+                wake_up(&h8_monitor_wait);
+        }
+
+        /*
+         * nops -for now
+         */
+        if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: DOCKING_STATION_STATUS\n");
+                /* read_ext_status */
+        }
+        if (intrbuf.word & H8_EXT_BATT_STATUS) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: EXT_BATT_STATUS\n");
+
+        }
+        if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
+
+        }
+        if (intrbuf.word & H8_BATT_CHANGE_OVER) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: BATT_CHANGE_OVER\n");
+
+        }
+        if (intrbuf.word & H8_WATCHDOG) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: WATCHDOG\n");
+                /* nop */
+        }
+        if (intrbuf.word & H8_SHUTDOWN) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: SHUTDOWN\n");
+                /* nop */
+        }
+        if (intrbuf.word & H8_KEYBOARD) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: KEYBOARD\n");
+                /* nop */
+        }
+        if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
+                /* read_ext_status*/
+        }
+        if (intrbuf.word & H8_INT_BATT_LOW) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: INT_BATT_LOW\n");
+                /* post event, warn user */
+        }
+        if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: INT_BATT_CHARGE_STATE\n");
+                /* nop - happens often */
+        }
+        if (intrbuf.word & H8_INT_BATT_STATUS) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: INT_BATT_STATUS\n");
+
+        }
+        if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
+                /* nop - happens often */
+        }
+        if (intrbuf.word & H8_EXT_BATT_LOW) {
+		if(h8_debug & 0x4)
+		    printk("h8_read_event_status: EXT_BATT_LOW\n");
+                /*if no internal, post event, warn user */
+                /* else nop */
+        }
+
+        return;
+}
+
+/*
+ * Function called when H8 has performed requested command.
+ */
+void
+h8_cmd_done(h8_cmd_q_t *qp)
+{
+
+        /* what to do */
+        switch (qp->cmdbuf[0]) {
+	case H8_SYNC:
+	    if (h8_debug & 0x40000) 
+	        printk("H8: Sync command done - byte returned was 0x%x\n", 
+		       qp->rcvbuf[0]);
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+	    break;
+
+	case H8_RD_SN:
+	case H8_RD_ENET_ADDR:
+	    printk("H8: Read ethernet addr - command done - address: %x - %x - %x - %x - %x - %x \n", 
+		   qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
+		   qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+	    break;
+
+	case H8_RD_HW_VER:
+	case H8_RD_MIC_VER:
+	case H8_RD_MAX_TEMP:
+	    printk("H8: Max recorded CPU temp %d, Sys temp %d\n",
+		   qp->rcvbuf[0], qp->rcvbuf[1]);
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+	    break;
+
+	case H8_RD_MIN_TEMP:
+	    printk("H8: Min recorded CPU temp %d, Sys temp %d\n",
+		   qp->rcvbuf[0], qp->rcvbuf[1]);
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+	    break;
+
+	case H8_RD_CURR_TEMP:
+	    h8_sync_channel |= H8_RD_CURR_TEMP;
+	    xx.byte[0] = qp->rcvbuf[0];
+	    xx.byte[1] = qp->rcvbuf[1];
+	    wake_up(&h8_sync_wait); 
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); 
+	    break;
+
+	case H8_RD_SYS_VARIENT:
+	case H8_RD_PWR_ON_CYCLES:
+	    printk(" H8: RD_PWR_ON_CYCLES command done\n");
+	    break;
+
+	case H8_RD_PWR_ON_SECS:
+	    printk("H8: RD_PWR_ON_SECS command done\n");
+	    break;
+
+	case H8_RD_RESET_STATUS:
+	case H8_RD_PWR_DN_STATUS:
+	case H8_RD_EVENT_STATUS:
+	case H8_RD_ROM_CKSM:
+	case H8_RD_EXT_STATUS:
+	    xx.byte[1] = qp->rcvbuf[0];
+	    xx.byte[0] = qp->rcvbuf[1];
+	    h8_sync_channel |= H8_GET_EXT_STATUS;
+	    wake_up(&h8_sync_wait); 
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); 
+	    break;
+
+	case H8_RD_USER_CFG:
+	case H8_RD_INT_BATT_VOLT:
+	case H8_RD_DC_INPUT_VOLT:
+	case H8_RD_HORIZ_PTR_VOLT:
+	case H8_RD_VERT_PTR_VOLT:
+	case H8_RD_EEPROM_STATUS:
+	case H8_RD_ERR_STATUS:
+	case H8_RD_NEW_BUSY_SPEED:
+	case H8_RD_CONFIG_INTERFACE:
+	case H8_RD_INT_BATT_STATUS:
+	    printk("H8: Read int batt status cmd done - returned was %x %x %x\n",
+		   qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+	    break;
+
+	case H8_RD_EXT_BATT_STATUS:
+	case H8_RD_PWR_UP_STATUS:
+	case H8_RD_EVENT_STATUS_MASK:
+	case H8_CTL_EMU_BITPORT:
+	case H8_DEVICE_CONTROL:
+	    if(h8_debug & 0x20000) {
+	        printk("H8: Device control cmd done - byte returned was 0x%x\n",
+		       qp->rcvbuf[0]);
+	    }
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+	    break;
+
+	case H8_CTL_TFT_BRT_DC:
+	case H8_CTL_WATCHDOG:
+	case H8_CTL_MIC_PROT:
+	case H8_CTL_INT_BATT_CHG:
+	case H8_CTL_EXT_BATT_CHG:
+	case H8_CTL_MARK_SPACE:
+	case H8_CTL_MOUSE_SENSITIVITY:
+	case H8_CTL_DIAG_MODE:
+	case H8_CTL_IDLE_AND_BUSY_SPDS:
+	    printk("H8: Idle and busy speed command done\n");
+	    break;
+
+	case H8_CTL_TFT_BRT_BATT:
+	case H8_CTL_UPPER_TEMP:
+	    if(h8_debug & 0x10) {
+	        XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n",
+		       qp->rcvbuf[0]);
+	    }
+	    QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+	    break;
+
+	case H8_CTL_LOWER_TEMP:
+	case H8_CTL_TEMP_CUTOUT:
+	case H8_CTL_WAKEUP:
+	case H8_CTL_CHG_THRESHOLD:
+	case H8_CTL_TURBO_MODE:
+	case H8_SET_DIAG_STATUS:
+	case H8_SOFTWARE_RESET:
+	case H8_RECAL_PTR:
+	case H8_SET_INT_BATT_PERCENT:
+	case H8_WRT_CFG_INTERFACE_REG:
+	case H8_WRT_EVENT_STATUS_MASK:
+	case H8_ENTER_POST_MODE:
+	case H8_EXIT_POST_MODE:
+	case H8_RD_EEPROM:
+	case H8_WRT_EEPROM:
+	case H8_WRT_TO_STATUS_DISP:
+	    printk("H8: Write IO status display command done\n");
+	    break;
+
+	case H8_DEFINE_SPC_CHAR:
+	case H8_DEFINE_TABLE_STRING_ENTRY:
+	case H8_PERFORM_EMU_CMD:
+	case H8_EMU_RD_REG:
+	case H8_EMU_WRT_REG:
+	case H8_EMU_RD_RAM:
+	case H8_EMU_WRT_RAM:
+	case H8_BQ_RD_REG:
+	case H8_BQ_WRT_REG:
+	case H8_PWR_OFF:
+	    printk ("H8: misc command completed\n");
+	    break;
+        }
+        return;
+}
+
+/*
+ * Retrieve the current cpu temperature and case temperature.  Provides
+ * the feedback for the thermal control algorithm.  Synchcronized via 
+ * sleep() for priority so that no other actions in the process will take
+ * place before the data becomes available.
+ */
+int
+h8_get_curr_temp(u_char curr_temp[])
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+        unsigned long flags;
+
+        memset(buf, 0, H8_MAX_CMD_SIZE); 
+        buf[0] = H8_RD_CURR_TEMP;
+
+        h8_q_cmd(buf, 1, 2);
+
+	save_flags(flags); cli();
+
+        while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
+                sleep_on(&h8_sync_wait); 
+
+        restore_flags(flags);
+
+        h8_sync_channel &= ~H8_RD_CURR_TEMP;
+        curr_temp[0] = xx.byte[0];
+        curr_temp[1] = xx.byte[1];
+        xx.word = 0;
+
+        if(h8_debug & 0x8) 
+                printk("H8: curr CPU temp %d, Sys temp %d\n",
+		       curr_temp[0], curr_temp[1]);
+        return 0;
+}
+
+static void
+h8_get_max_temp(void)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        buf[0] = H8_RD_MAX_TEMP;
+        h8_q_cmd(buf, 1, 2);
+}
+
+/*
+ * Assigns an upper limit to the value of the H8 thermal interrupt.
+ * As an example setting a value of 115 F here will cause the 
+ * interrupt to trigger when the cpu temperature reaches 115 F.
+ */
+static void
+h8_set_upper_therm_thold(int thold)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        /* write 0 to reinitialize interrupt */
+        buf[0] = H8_CTL_UPPER_TEMP;
+        buf[1] = 0x0;
+        buf[2] = 0x0;
+        h8_q_cmd(buf, 3, 1); 
+
+        /* Do it for real */
+        buf[0] = H8_CTL_UPPER_TEMP;
+        buf[1] = 0x0;
+        buf[2] = thold;
+        h8_q_cmd(buf, 3, 1); 
+}
+
+static void
+h8_get_upper_therm_thold(void)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        buf[0] = H8_CTL_UPPER_TEMP;
+        buf[1] = 0xff;
+        buf[2] = 0;
+        h8_q_cmd(buf, 3, 1); 
+}
+
+/*
+ * The external status word contains information on keyboard controller,
+ * power button, changes in external batt status, change in DC state,
+ * docking station, etc. General purpose querying use.
+ */
+int
+h8_get_ext_status(u_char stat_word[])
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+	unsigned long flags;
+
+        memset(buf, 0, H8_MAX_CMD_SIZE); 
+        buf[0] = H8_RD_EXT_STATUS;
+
+        h8_q_cmd(buf, 1, 2);
+
+	save_flags(flags); cli();
+
+        while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
+                sleep_on(&h8_sync_wait); 
+
+        restore_flags(flags);
+
+        h8_sync_channel &= ~H8_GET_EXT_STATUS;
+        stat_word[0] = xx.byte[0];
+        stat_word[1] = xx.byte[1];
+        xx.word = 0;
+
+        if(h8_debug & 0x8) 
+                printk("H8: curr ext status %x,  %x\n",
+		       stat_word[0], stat_word[1]);
+
+        return 0;
+}
+
+/*
+ * Thread attached to task 0 manages thermal/physcial state of Alphabook. 
+ * When a condition is detected by the interrupt service routine, the
+ * isr does a wakeup() on h8_monitor_wait.  The mask value is then
+ * screened for the appropriate action.
+ */
+
+int
+h8_monitor_thread(void * unused)
+{
+        u_char curr_temp[2];
+
+        /*
+         * Need a logic based safety valve here. During boot when this thread is
+         * started and the thermal interrupt is not yet initialized this logic 
+         * checks the temperature and acts accordingly.  When this path is acted
+         * upon system boot is painfully slow, however, the priority associated 
+         * with overheating is high enough to warrant this action.
+         */
+        h8_get_curr_temp(curr_temp);
+
+        printk("H8: Initial CPU temp: %d\n", curr_temp[0]);
+
+        if(curr_temp[0] >= h8_uthermal_threshold) {
+                h8_set_event_mask(H8_MANAGE_UTHERM);
+                h8_manage_therm();
+        } else {
+                /*
+                 * Arm the upper thermal limit of the H8 so that any temp in
+                 * excess will trigger the thermal control mechanism.
+                 */
+                h8_set_upper_therm_thold(h8_uthermal_threshold);
+        }
+
+        for(;;) {
+		sleep_on(&h8_monitor_wait);
+
+                if(h8_debug & 0x2)
+                        printk("h8_monitor_thread awakened, mask:%x\n",
+                                h8_event_mask);
+
+                if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
+                        h8_manage_therm();
+                }
+
+#if 0
+                if (h8_event_mask & H8_POWER_BUTTON) {
+                        h8_system_down();
+                }
+
+		/*
+		 * If an external DC supply is removed or added make 
+		 * appropriate cpu speed adjustments.
+		 */
+                if (h8_event_mask & H8_MANAGE_BATTERY) {
+                          h8_run_level_3_manage(H8_RUN); 
+                          h8_clear_event_mask(H8_MANAGE_BATTERY);
+                }
+#endif
+        }
+}
+
+/* 
+ * Function implements the following policy. When the machine is booted
+ * the system is set to run at full clock speed. When the upper thermal
+ * threshold is reached as a result of full clock a damping factor is 
+ * applied to cool off the cpu.  The default value is one quarter clock
+ * (57 Mhz).  When as a result of this cooling a temperature lower by
+ * hmc_uthermal_window is reached, the machine is reset to a higher 
+ * speed, one half clock (115 Mhz).  One half clock is maintained until
+ * the upper thermal threshold is again reached restarting the cycle.
+ */
+
+int
+h8_manage_therm(void)
+{
+        u_char curr_temp[2];
+
+        if(h8_event_mask & H8_MANAGE_UTHERM) {
+		/* Upper thermal interrupt received, need to cool down. */
+		if(h8_debug & 0x10)
+                        printk("H8: Thermal threshold %d F reached\n",
+			       h8_uthermal_threshold);
+		h8_set_cpu_speed(h8_udamp); 
+                h8_clear_event_mask(H8_MANAGE_UTHERM);
+                h8_set_event_mask(H8_MANAGE_LTHERM);
+                /* Check again in 30 seconds for cpu temperature */
+                h8_start_monitor_timer(H8_TIMEOUT_INTERVAL); 
+        } else if (h8_event_mask & H8_MANAGE_LTHERM) {
+		/* See how cool the system has become as a result
+		   of the reduction in speed. */
+                h8_get_curr_temp(curr_temp);
+                last_temp = curr_temp[0];
+                if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
+		{
+			/* System cooling has progressed to a point
+			   that the cpu may be speeded up. */
+                        h8_set_upper_therm_thold(h8_uthermal_threshold);
+                        h8_set_cpu_speed(h8_ldamp); /* adjustable */ 
+                        if(h8_debug & 0x10)
+                            printk("H8: CPU cool, applying cpu_divisor: %d \n",
+				   h8_ldamp);
+                        h8_clear_event_mask(H8_MANAGE_LTHERM);
+                }
+		else /* Not cool enough yet, check again in 30 seconds. */
+                        h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
+        } else {
+                
+        }
+	return 0;
+}
+
+/* 
+ * Function conditions the value of global_rpb_counter before
+ * calling the primitive which causes the actual speed change.
+ */
+void
+h8_set_cpu_speed(int speed_divisor)
+{
+
+#ifdef NOT_YET
+/*
+ * global_rpb_counter is consumed by alpha_delay() in determining just
+ * how much time to delay.  It is necessary that the number of microseconds
+ * in DELAY(n) be kept consistent over a variety of cpu clock speeds.
+ * To that end global_rpb_counter is here adjusted.
+ */ 
+        
+        switch (speed_divisor) {
+                case 0:
+                        global_rpb_counter = rpb->rpb_counter * 2L;
+                        break;
+                case 1:
+                        global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
+                        break;
+                case 3:
+                        global_rpb_counter = rpb->rpb_counter / 2L;
+                        break;
+                case 4:
+                        global_rpb_counter = rpb->rpb_counter / 4L;
+                        break;
+                case 5:
+                        global_rpb_counter = rpb->rpb_counter / 8L;
+                        break;
+                /* 
+                 * This case most commonly needed for cpu_speed_divisor 
+                 * of 2 which is the value assigned by the firmware. 
+                 */
+                default:
+                        global_rpb_counter = rpb->rpb_counter;
+                break;
+        }
+#endif /* NOT_YET */
+
+        if(h8_debug & 0x8)
+                printk("H8: Setting CPU speed to %d MHz\n",
+		       speed_tab[speed_divisor]); 
+
+         /* Make the actual speed change */
+        lca_clock_fiddle(speed_divisor);
+}
+
+/*
+ * Gets value stored in rpb representing cpu clock speed and adjusts this
+ * value based on the current clock speed divisor.
+ */
+u_long
+h8_get_cpu_speed(void)
+{
+        u_long speed = 0;
+        u_long counter;
+
+#ifdef NOT_YET
+        counter = rpb->rpb_counter / 1000000L;
+
+        switch (alphabook_get_clock()) {
+                case 0:
+                        speed = counter * 2L;
+                        break;
+                case 1:
+                        speed = counter * 4L / 3L ;
+                        break;
+                case 2:
+                        speed = counter;
+                        break;
+                case 3:
+                        speed = counter / 2L;
+                        break;
+                case 4:
+                        speed = counter / 4L;
+                        break;
+                case 5:
+                        speed = counter / 8L;
+                        break;
+                default:
+                break;
+        }
+        if(h8_debug & 0x8)
+                printk("H8: CPU speed current setting: %d MHz\n", speed); 
+#endif  /* NOT_YET */
+	return speed;
+}
+
+static void
+h8_activate_monitor(unsigned long unused)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	h8_monitor_timer_active = 0;
+	restore_flags(flags);
+
+	wake_up(&h8_monitor_wait);
+}
+
+static void
+h8_start_monitor_timer(unsigned long secs)
+{
+	unsigned long flags;
+
+	if (h8_monitor_timer_active)
+	    return;
+
+	save_flags(flags); cli();
+	h8_monitor_timer_active = 1;
+	restore_flags(flags);
+
+        init_timer(&h8_monitor_timer);
+        h8_monitor_timer.function = h8_activate_monitor;
+        h8_monitor_timer.expires = secs * HZ + jiffies;
+        add_timer(&h8_monitor_timer);
+}
+
+static void h8_set_event_mask(int mask)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	h8_event_mask |= mask;
+	restore_flags(flags);
+}
+
+static void h8_clear_event_mask(int mask)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	h8_event_mask &= (~mask);
+	restore_flags(flags);
+}
diff -u --recursive --new-file v2.0.33/linux/drivers/char/h8.h linux/drivers/char/h8.h
--- v2.0.33/linux/drivers/char/h8.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/h8.h	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,250 @@
+/*
+ */
+
+#ifndef __H8_H__
+#define __H8_H__
+
+/*
+ * Register address and offsets
+ */
+#define H8_BASE_ADDR                   0x170            /* default */
+#define H8_IRQ			       9                /* default */
+#define H8_STATUS_REG_OFF              0x4              
+#define H8_CMD_REG_OFF                 0x4
+#define H8_DATA_REG_OFF                0x0
+
+
+/* H8 register bit definitions */
+/* status register */
+#define H8_OFULL                       0x1              /* output data register full */
+#define H8_IFULL                       0x2              /* input data register full */
+#define H8_CMD                         0x8              /* command / not data */
+
+#define H8_INTR                        0xfa
+#define H8_NACK                        0xfc
+#define H8_BYTE_LEVEL_ACK              0xfd
+#define H8_CMD_ACK                     0xfe
+#define H8_SYNC_BYTE                   0x99
+
+/*
+ * H8 command definitions
+ */
+/* System info commands */
+#define H8_SYNC                         0x0
+#define H8_RD_SN                        0x1
+#define H8_RD_ENET_ADDR                 0x2
+#define H8_RD_HW_VER                    0x3
+#define H8_RD_MIC_VER                   0x4
+#define H8_RD_MAX_TEMP                  0x5
+#define H8_RD_MIN_TEMP                  0x6
+#define H8_RD_CURR_TEMP                 0x7
+#define H8_RD_SYS_VARIENT               0x8
+#define H8_RD_PWR_ON_CYCLES             0x9
+#define H8_RD_PWR_ON_SECS               0xa
+#define H8_RD_RESET_STATUS              0xb
+#define H8_RD_PWR_DN_STATUS             0xc
+#define H8_RD_EVENT_STATUS              0xd
+#define H8_RD_ROM_CKSM                  0xe
+#define H8_RD_EXT_STATUS                0xf
+#define H8_RD_USER_CFG                  0x10
+#define H8_RD_INT_BATT_VOLT             0x11
+#define H8_RD_DC_INPUT_VOLT             0x12
+#define H8_RD_HORIZ_PTR_VOLT            0x13
+#define H8_RD_VERT_PTR_VOLT             0x14
+#define H8_RD_EEPROM_STATUS             0x15
+#define H8_RD_ERR_STATUS                0x16
+#define H8_RD_NEW_BUSY_SPEED            0x17
+#define H8_RD_CONFIG_INTERFACE          0x18
+#define H8_RD_INT_BATT_STATUS           0x19
+#define H8_RD_EXT_BATT_STATUS           0x1a
+#define H8_RD_PWR_UP_STATUS             0x1b
+#define H8_RD_EVENT_STATUS_MASK         0x56
+
+/* Read/write/modify commands */
+#define H8_CTL_EMU_BITPORT              0x32
+#define H8_DEVICE_CONTROL               0x21
+#define H8_CTL_TFT_BRT_DC               0x22
+#define H8_CTL_WATCHDOG                 0x23
+#define H8_CTL_MIC_PROT                 0x24
+#define H8_CTL_INT_BATT_CHG             0x25
+#define H8_CTL_EXT_BATT_CHG             0x26
+#define H8_CTL_MARK_SPACE               0x27
+#define H8_CTL_MOUSE_SENSITIVITY        0x28
+#define H8_CTL_DIAG_MODE                0x29
+#define H8_CTL_IDLE_AND_BUSY_SPDS       0x2a
+#define H8_CTL_TFT_BRT_BATT             0x2b
+#define H8_CTL_UPPER_TEMP               0x2c
+#define H8_CTL_LOWER_TEMP               0x2d
+#define H8_CTL_TEMP_CUTOUT              0x2e
+#define H8_CTL_WAKEUP                   0x2f
+#define H8_CTL_CHG_THRESHOLD            0x30
+#define H8_CTL_TURBO_MODE               0x31
+#define H8_SET_DIAG_STATUS              0x40
+#define H8_SOFTWARE_RESET               0x41
+#define H8_RECAL_PTR                    0x42
+#define H8_SET_INT_BATT_PERCENT         0x43
+#define H8_WRT_CFG_INTERFACE_REG        0x45
+#define H8_WRT_EVENT_STATUS_MASK        0x57
+#define H8_ENTER_POST_MODE              0x46
+#define H8_EXIT_POST_MODE               0x47
+
+/* Block transfer commands */
+#define H8_RD_EEPROM                    0x50
+#define H8_WRT_EEPROM                   0x51
+#define H8_WRT_TO_STATUS_DISP           0x52
+#define H8_DEFINE_SPC_CHAR              0x53
+ 
+/* Generic commands */
+#define H8_DEFINE_TABLE_STRING_ENTRY    0x60
+
+/* Battery control commands */
+#define H8_PERFORM_EMU_CMD              0x70
+#define H8_EMU_RD_REG                   0x71
+#define H8_EMU_WRT_REG                  0x72
+#define H8_EMU_RD_RAM                   0x73
+#define H8_EMU_WRT_RAM                  0x74
+#define H8_BQ_RD_REG                    0x75
+#define H8_BQ_WRT_REG                   0x76
+
+/* System admin commands */
+#define H8_PWR_OFF                      0x80
+
+/*
+ * H8 command related definitions
+ */
+
+/* device control argument bits */
+#define H8_ENAB_EXTSMI                  0x1
+#define H8_DISAB_IRQ                    0x2
+#define H8_ENAB_FLASH_WRT               0x4
+#define H8_ENAB_THERM                   0x8
+#define H8_ENAB_INT_PTR                 0x10
+#define H8_ENAB_LOW_SPD_IND             0x20
+#define H8_ENAB_EXT_PTR                 0x40
+#define H8_DISAB_PWR_OFF_SW             0x80
+#define H8_POWER_OFF			0x80
+
+/* H8 read event status bits */
+#define H8_DC_CHANGE                    0x1
+#define H8_INT_BATT_LOW                 0x2
+#define H8_INT_BATT_CHARGE_THRESHOLD    0x4
+#define H8_INT_BATT_CHARGE_STATE        0x8
+#define H8_INT_BATT_STATUS              0x10
+#define H8_EXT_BATT_CHARGE_STATE        0x20
+#define H8_EXT_BATT_LOW                 0x40
+#define H8_EXT_BATT_STATUS              0x80
+#define H8_THERMAL_THRESHOLD            0x100
+#define H8_WATCHDOG                     0x200
+#define H8_DOCKING_STATION_STATUS       0x400
+#define H8_EXT_MOUSE_OR_CASE_SWITCH     0x800
+#define H8_KEYBOARD                     0x1000
+#define H8_BATT_CHANGE_OVER             0x2000
+#define H8_POWER_BUTTON                 0x4000
+#define H8_SHUTDOWN                     0x8000
+
+/* H8 control idle and busy speeds */
+#define H8_SPEED_LOW                    0x1
+#define H8_SPEED_MED                    0x2
+#define H8_SPEED_HI                     0x3
+#define H8_SPEED_LOCKED                 0x80
+
+#define H8_MAX_CMD_SIZE                 18      
+#define H8_Q_ALLOC_AMOUNT               10      
+
+/* H8 state field values */
+#define H8_IDLE                         1
+#define H8_XMIT                         2
+#define H8_RCV                          3
+#define H8_RESYNC                       4
+#define H8_INTR_MODE                    5
+
+/* Mask values for control functions */
+#define UTH_HYSTERESIS                  5
+#define DEFAULT_UTHERMAL_THRESHOLD      115
+#define H8_TIMEOUT_INTERVAL		30
+#define H8_RUN                          4
+
+#define H8_GET_MAX_TEMP                 0x1
+#define H8_GET_CURR_TEMP                0x2
+#define H8_GET_UPPR_THRMAL_THOLD        0x4
+#define H8_GET_ETHERNET_ADDR            0x8
+#define H8_SYNC_OP                      0x10 
+#define H8_SET_UPPR_THRMAL_THOLD        0x20
+#define H8_GET_INT_BATT_STAT            0x40
+#define H8_GET_CPU_SPD                  0x80
+#define H8_MANAGE_UTHERM                0x100 
+#define H8_MANAGE_LTHERM                0x200 
+#define H8_HALT                         0x400 
+#define H8_CRASH                        0x800 
+#define H8_GET_EXT_STATUS               0x10000
+#define H8_MANAGE_QUIET                 0x20000
+#define H8_MANAGE_SPEEDUP               0x40000
+#define H8_MANAGE_BATTERY               0x80000
+#define H8_SYSTEM_DELAY_TEST            0x100000
+#define H8_POWER_SWITCH_TEST            0x200000
+
+/* cpu speeds and clock divisor values */
+#define MHZ_14                           5
+#define MHZ_28                           4
+#define MHZ_57                           3
+#define MHZ_115                          2
+#define MHZ_230                          0 
+
+/*
+ * H8 data
+ */
+struct h8_data {
+        u_int           ser_num;
+        u_char          ether_add[6];
+        u_short         hw_ver;
+        u_short         mic_ver;
+        u_short         max_tmp;
+        u_short         min_tmp;
+        u_short         cur_tmp;
+        u_int           sys_var;
+        u_int           pow_on;
+        u_int           pow_on_secs;
+        u_char          reset_status;
+        u_char          pwr_dn_status;
+        u_short         event_status;
+        u_short         rom_cksm;
+        u_short         ext_status;
+        u_short         u_cfg;
+        u_char          ibatt_volt;
+        u_char          dc_volt;
+        u_char          ptr_horiz;
+        u_char          ptr_vert;
+        u_char          eeprom_status;
+        u_char          error_status;
+        u_char          new_busy_speed;
+        u_char          cfg_interface;
+        u_short         int_batt_status;
+        u_short         ext_batt_status;
+        u_char          pow_up_status;
+        u_char          event_status_mask;
+};
+
+
+/*
+ * H8 command buffers
+ */
+typedef struct h8_cmd_q {
+        DLNODE(struct h8_cmd_q) link; /* double linked list */
+        int             ncmd;           /* number of bytes in command */
+        int             nrsp;           /* number of bytes in response */
+        int             cnt;            /* number of bytes sent/received */
+        int             nacks;          /* number of byte level acks */
+        u_char          cmdbuf[H8_MAX_CMD_SIZE]; /* buffer to store command */
+        u_char          rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */
+} h8_cmd_q_t;
+
+typedef struct __queue_head {
+	DLNODE(struct h8_cmd_q) link;
+} queue_head_t;
+
+union   intr_buf {
+        u_char  byte[2];
+        u_int   word;
+};
+
+#endif /* __H8_H_ */
diff -u --recursive --new-file v2.0.33/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.0.33/linux/drivers/char/mem.c	Tue Sep  9 16:06:48 1997
+++ linux/drivers/char/mem.c	Wed Jun  3 15:17:47 1998
@@ -333,6 +333,14 @@
 {
 	switch (MINOR(inode->i_rdev)) {
 		case 0:
+		case 1:
+		case 2:
+		case 4:
+			if(securelevel>0)
+				return -EPERM;
+	}
+	switch (MINOR(inode->i_rdev)) {
+		case 0:
 			filp->f_op = &ram_fops;
 			break;
 		case 1:
@@ -392,7 +400,7 @@
 #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
-    defined (CONFIG_PCWATCHDOG) || \
+    defined (CONFIG_PCWATCHDOG) || defined (CONFIG_H8) || \
     defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
 	misc_init();
 #endif
diff -u --recursive --new-file v2.0.33/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.0.33/linux/drivers/char/misc.c	Tue Aug 12 13:06:54 1997
+++ linux/drivers/char/misc.c	Wed Jun  3 15:17:47 1998
@@ -232,6 +232,9 @@
 #ifdef CONFIG_APM
 	apm_bios_init();
 #endif
+#ifdef CONFIG_H8
+	h8_init();
+#endif
 #ifdef CONFIG_RTC
 	rtc_init();
 #endif
diff -u --recursive --new-file v2.0.33/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v2.0.33/linux/drivers/char/psaux.c	Wed Sep 11 07:57:14 1996
+++ linux/drivers/char/psaux.c	Wed Jun  3 15:17:47 1998
@@ -561,7 +561,7 @@
 #ifdef MODULE
 int init_module(void)
 {
-	return psaux_init(); /*?? Bjorn */
+	return psaux_init(); /*??  Bjorn */
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v2.0.33/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.0.33/linux/drivers/char/random.c	Thu Aug 14 10:05:47 1997
+++ linux/drivers/char/random.c	Wed Jun  3 15:17:47 1998
@@ -226,6 +226,7 @@
  * Eastlake, Steve Crocker, and Jeff Schiller.
  */
 
+#include <linux/config.h> /* CONFIG_RST_COOKIES and CONFIG_SYN_COOKIES */
 #include <linux/utsname.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v2.0.33/linux/drivers/char/riscom8.c	Fri Apr 26 02:12:25 1996
+++ linux/drivers/char/riscom8.c	Wed Jun  3 15:17:47 1998
@@ -1,7 +1,7 @@
 /*
  *      linux/drivers/char/riscom.c  -- RISCom/8 multiport serial driver.
  *
- *      Copyright (C) 1994-1996  Dmitry Gorodchanin (begemot@bgm.rosprint.net)
+ *      Copyright (C) 1994-1996  Dmitry Gorodchanin (pgmdsg@ibi.com)
  *
  *      This code is loosely based on the Linux serial driver, written by
  *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
diff -u --recursive --new-file v2.0.33/linux/drivers/char/riscom8.h linux/drivers/char/riscom8.h
--- v2.0.33/linux/drivers/char/riscom8.h	Wed Oct 15 15:11:08 1997
+++ linux/drivers/char/riscom8.h	Wed Jun  3 15:17:47 1998
@@ -1,7 +1,7 @@
 /*
  *      linux/drivers/char/riscom8.h  -- RISCom/8 multiport serial driver.
  *
- *      Copyright (C) 1994-1996  Dmitry Gorodchanin (begemot@bgm.rosprint.net)
+ *      Copyright (C) 1994-1996  Dmitry Gorodchanin (pgmdsg@ibi.com)
  *
  *      This code is loosely based on the Linux serial driver, written by
  *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
diff -u --recursive --new-file v2.0.33/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.0.33/linux/drivers/char/rtc.c	Mon May 27 21:39:18 1996
+++ linux/drivers/char/rtc.c	Wed Jun  3 15:17:47 1998
@@ -28,9 +28,14 @@
  *	Based on other minimal char device drivers, like Alan's
  *	watchdog, Ted's random, etc. etc.
  *
+ *	1.07	Paul Gortmaker.
+ *	1.08	Miquel van Smoorenburg: disallow certain things on the
+ *		DEC Alpha as the CMOS clock is also used for other things.
+ *	1.09	Nikita Schmidt: epoch support and some Alpha cleanup.
+ *
  */
 
-#define RTC_VERSION		"1.07"
+#define RTC_VERSION		"1.09"
 
 #define RTC_IRQ 	8	/* Can't see this changing soon.	*/
 #define RTC_IO_EXTENT	0x10	/* Only really two ports, but...	*/
@@ -98,6 +103,13 @@
 unsigned long rtc_freq = 0;		/* Current periodic IRQ rate	*/
 unsigned long rtc_irq_data = 0;		/* our output to the world	*/
 
+/*
+ *	If this driver ever becomes modularised, it will be really nice
+ *	to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1900;	/* year corresponding to 0x00	*/
+
 unsigned char days_in_mo[] = 
 		{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
@@ -106,8 +118,12 @@
  *	so that there is no possibility of conflicting with the
  *	set_rtc_mmss() call that happens during some timer interrupts.
  *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
+ *
+ *	On Alpha we won't get any interrupts anyway, as they all end up
+ *	in the system timer code.
  */
 
+#ifndef __alpha__
 static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	/*
@@ -128,9 +144,11 @@
 		add_timer(&rtc_irq_timer);
 	}
 }
+#endif
 
 /*
  *	Now all the various file operations that we export.
+ *	They are all useless on Alpha...  *sigh*.
  */
 
 static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
@@ -141,6 +159,9 @@
 
 static int rtc_read(struct inode *inode, struct file *file, char *buf, int count)
 {
+#ifdef __alpha__
+	return -EIO;
+#else
 	struct wait_queue wait = { current, NULL };
 	int retval;
 	
@@ -182,6 +203,7 @@
 	remove_wait_queue(&rtc_wait, &wait);
 
 	return retval;
+#endif
 }
 
 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -191,6 +213,7 @@
 	unsigned long flags;
 
 	switch (cmd) {
+#ifndef __alpha__
 		case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
 		{
 			mask_rtc_irq_bit(RTC_AIE);
@@ -238,6 +261,7 @@
 			set_rtc_irq_bit(RTC_UIE);
 			return 0;
 		}
+#endif
 		case RTC_ALM_READ:	/* Read the present alarm time */
 		{
 			/*
@@ -342,7 +366,7 @@
 			min = rtc_tm.tm_min;
 			sec = rtc_tm.tm_sec;
 
-			if ((yrs < 1970) || (yrs > 2069))
+			if (yrs < 1970)
 				return -EINVAL;
 
 			leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
@@ -356,16 +380,19 @@
 			if ((hrs >= 24) || (min >= 60) || (sec >= 60))
 				return -EINVAL;
 
-			if (yrs >= 2000)
-				yrs -= 2000;	/* RTC (0, 1, ... 69) */
-			else
-				yrs -= 1900;	/* RTC (70, 71, ... 99) */
+			if ((yrs -= epoch) > 255)    /* They are unsigned */
+				return -EINVAL;
 
 			save_flags(flags);
 			cli();
-			if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
-							RTC_ALWAYS_BCD)
-			{
+			if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+				if (yrs > 169) {
+					restore_flags(flags);
+					return -EINVAL;
+				}
+				if (yrs >= 100)
+					yrs -= 100;
+
 				BIN_TO_BCD(sec);
 				BIN_TO_BCD(min);
 				BIN_TO_BCD(hrs);
@@ -403,6 +430,7 @@
 			memcpy_tofs((unsigned long*)arg, &rtc_freq, sizeof(unsigned long));
 			return 0;
 		}
+#ifndef __alpha__
 		case RTC_IRQP_SET:	/* Set periodic IRQ rate.	*/
 		{
 			int tmp = 0;
@@ -439,6 +467,34 @@
 			restore_flags(flags);
 			return 0;
 		}
+#endif
+#ifdef __alpha__
+		case RTC_EPOCH_READ:	/* Read the epoch.	*/
+		{
+			int retval;
+
+			retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long));
+			if (retval != 0)
+				return retval;
+
+			memcpy_tofs((unsigned long*)arg, &epoch, sizeof(unsigned long));
+			return 0;
+		}
+		case RTC_EPOCH_SET:	/* Set the epoch.	*/
+		{
+			/* 
+			 * There were no RTC clocks before 1900.
+			 */
+			if (arg < 1900)
+				return -EINVAL;
+
+			if (!suser())
+				return -EACCES;
+
+			epoch = arg;
+			return 0;
+		}
+#endif
 		default:
 			return -EINVAL;
 	}
@@ -448,16 +504,18 @@
  *	We enforce only one user at a time here with the open/close.
  *	Also clear the previous interrupt data on an open, and clean
  *	up things on a close.
+ *	On Alpha we just open, for we don't mess with interrups anyway.
  */
 
 static int rtc_open(struct inode *inode, struct file *file)
 {
-
+#ifndef __alpha__
 	if(rtc_status & RTC_IS_OPEN)
 		return -EBUSY;
 
 	rtc_status |= RTC_IS_OPEN;
 	rtc_irq_data = 0;
+#endif
 	return 0;
 }
 
@@ -469,6 +527,7 @@
 	 * in use, and clear the data.
 	 */
 
+#ifndef __alpha__
 	unsigned char tmp;
 	unsigned long flags;
 
@@ -489,8 +548,10 @@
 
 	rtc_irq_data = 0;
 	rtc_status &= ~RTC_IS_OPEN;
+#endif
 }
 
+#ifndef __alpha__
 static int rtc_select(struct inode *inode, struct file *file,
 			int sel_type, select_table *wait)
 {
@@ -501,6 +562,7 @@
 	}
 	return 0;
 }
+#endif
 
 /*
  *	The various file operations we support.
@@ -511,7 +573,11 @@
 	rtc_read,
 	NULL,		/* No write */
 	NULL,		/* No readdir */
+#ifdef __alpha__
+	NULL,		/* No select on Alpha */
+#else
 	rtc_select,
+#endif
 	rtc_ioctl,
 	NULL,		/* No mmap */
 	rtc_open,
@@ -528,17 +594,54 @@
 int rtc_init(void)
 {
 	unsigned long flags;
+#ifdef __alpha__
+	unsigned int year, ctrl;
+	unsigned long uip_watchdog;
+	char *guess = NULL;
+#endif
 
 	printk("Real Time Clock Driver v%s\n", RTC_VERSION);
+#ifndef __alpha__
 	if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
 	{
 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
 		printk("rtc: IRQ %d is not free.\n", RTC_IRQ);
 		return -EIO;
 	}
+#endif
 	misc_register(&rtc_dev);
 	/* Check region? Naaah! Just snarf it up. */
 	request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+#ifdef __alpha__
+	rtc_freq = HZ;
+
+	/* Each operating system on an Alpha uses its own epoch.
+	   Let's try to guess which one we are using now. */
+
+	uip_watchdog = jiffies;
+	if (rtc_is_updating() != 0)
+		while (jiffies - uip_watchdog < 2*HZ/100)
+			barrier();
+
+	save_flags(flags);
+	cli();
+	year = CMOS_READ(RTC_YEAR);
+	ctrl = CMOS_READ(RTC_CONTROL);
+	restore_flags(flags);
+
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+		BCD_TO_BIN(year);	/* This should never happen... */
+
+	if (year > 10 && year < 44) {
+		epoch = 1980;
+		guess = "ARC console";
+	} else if (year < 96) {
+		epoch = 1952;
+		guess = "Digital UNIX";
+	}
+	if (guess)
+		printk("rtc: %s epoch (%ld) detected\n", guess, epoch);
+#else
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
 	rtc_wait = NULL;
@@ -548,6 +651,7 @@
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
 	restore_flags(flags);
 	rtc_freq = 1024;
+#endif
 	return 0;
 }
 
@@ -563,6 +667,7 @@
  *	for something that requires a steady > 1KHz signal anyways.)
  */
 
+#ifndef __alpha__
 void rtc_dropped_irq(unsigned long data)
 {
 	unsigned long flags;
@@ -579,6 +684,7 @@
 	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */
 	restore_flags(flags);
 }
+#endif
 
 /*
  *	Info exported via "/proc/rtc".
@@ -723,7 +829,7 @@
 	 * Account for differences between how the RTC uses the values
 	 * and how they are defined in a struct rtc_time;
 	 */
-	if (rtc_tm->tm_year <= 69)
+	if ((rtc_tm->tm_year += epoch - 1900) <= 69)
 		rtc_tm->tm_year += 100;
 
 	rtc_tm->tm_mon--;
@@ -763,6 +869,8 @@
  * We also clear out any old irq data after an ioctl() that
  * meddles with the interrupt enable/disable bits.
  */
+
+#ifndef __alpha__
 void mask_rtc_irq_bit(unsigned char bit)
 {
 	unsigned char val;
@@ -792,4 +900,4 @@
 	rtc_irq_data = 0;
 	restore_flags(flags);
 }
-
+#endif
diff -u --recursive --new-file v2.0.33/linux/drivers/char/scc.c linux/drivers/char/scc.c
--- v2.0.33/linux/drivers/char/scc.c	Tue Aug 12 14:43:42 1997
+++ linux/drivers/char/scc.c	Wed Jun  3 15:17:47 1998
@@ -168,6 +168,7 @@
 
 /* ----------------------------------------------------------------------- */
 
+#include <linux/config.h> /* CONFIG_INET and CONFIG_SCC_* */
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
@@ -208,10 +209,6 @@
 #include <asm/segment.h>
 #include <asm/bitops.h>
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <time.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 
diff -u --recursive --new-file v2.0.33/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- v2.0.33/linux/drivers/char/selection.h	Wed Oct 15 15:22:39 1997
+++ linux/drivers/char/selection.h	Wed Jun  3 15:17:47 1998
@@ -61,10 +61,15 @@
 /* how to access screen memory */
 
 #include <linux/config.h>
+#include <asm/io.h> 
 
 #ifdef CONFIG_TGA_CONSOLE
 
-extern int tga_blitc(unsigned int, unsigned long);
+# ifdef CONFIG_VGA_CONSOLE
+extern int curr_cons;
+extern const struct console_desc cons_devices[];
+# endif
+
 extern unsigned long video_mem_term;
 
 /*
@@ -83,24 +88,57 @@
  *
  * NOTE also: there's only *TWO* operations: to put/get a character/attribute.
  *  All the others needed by VGA support go away, as Not Applicable for TGA.
+ *
+ * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this
+ *  indicates a VC's backing store; otherwise, it's a bus memory address, for
+ *  the VGA's screen memory, so we do the Alpha "swizzle"... :-)
  */
+#define IS_VIDEO_MEMORY(a) \
+        ((unsigned long)(a) - video_mem_base < video_mem_term - video_mem_base)
+
 static inline void scr_writew(unsigned short val, unsigned short * addr)
 {
+        if ((long) addr < 0) {
 	/*
-	 * always deposit the char/attr, then see if it was to "screen" mem.
+		 * always deposit the char/attr, then see if it was to
+		 * "screen" mem.
 	 * if so, then render the char/attr onto the real screen.
 	 */
         *addr = val;
-        if ((unsigned long)addr < video_mem_term &&
-	    (unsigned long)addr >= video_mem_base) {
-                tga_blitc(val, (unsigned long) addr);
-        }
+
+                /*
+		 * TGA might need the char blitted to the screen,
+		 * but check first, we could be running on a VGA.
+		 */
+                if (con_blitc && IS_VIDEO_MEMORY(addr))
+			con_blitc(val, (unsigned long) addr);
+        } else
+                writew(val, (unsigned long) addr);
 }
 
 static inline unsigned short scr_readw(unsigned short * addr)
 {
+	if ((long) addr < 0)
 	return *addr;
+	return readw((unsigned long) addr);
+}
+
+/* scr_writeb and scr_readb are not expected to be called with a TGA */
+static inline void scr_writeb(unsigned char val, unsigned char * addr)
+{
+	if ((long) addr < 0)
+		*addr = val;
+	else
+		writeb(val, (unsigned long) addr);
+}
+
+static inline unsigned char scr_readb(unsigned char * addr)
+{
+	if ((long) addr < 0)
+		return *addr;
+	return readb((unsigned long) addr);
 }
+
 #else /* CONFIG_TGA_CONSOLE */
 
 /*
@@ -109,8 +147,6 @@
  */ 
 
 #ifdef __alpha__
-
-#include <asm/io.h> 
 
 /*
  * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this
diff -u --recursive --new-file v2.0.33/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.0.33/linux/drivers/char/serial.c	Fri Sep  5 11:21:39 1997
+++ linux/drivers/char/serial.c	Wed Jun  3 15:17:47 1998
@@ -1170,6 +1170,7 @@
 	int	quot = 0;
 	unsigned cflag,cval,fcr;
 	int	i;
+	unsigned long flags;
 
 	if (!info->tty || !info->tty->termios)
 		return;
@@ -1208,15 +1209,15 @@
 	if (quot) {
 		info->MCR |= UART_MCR_DTR;
 		info->MCR_noint |= UART_MCR_DTR;
-		cli();
+		save_flags(flags); cli();
 		serial_out(info, UART_MCR, info->MCR);
-		sti();
+		restore_flags(flags);
 	} else {
 		info->MCR &= ~UART_MCR_DTR;
 		info->MCR_noint &= ~UART_MCR_DTR;
-		cli();
+		save_flags(flags); cli();
 		serial_out(info, UART_MCR, info->MCR);
-		sti();
+		restore_flags(flags);
 		return;
 	}
 	/* byte size and parity */
@@ -1302,13 +1303,13 @@
 				UART_LSR_PE | UART_LSR_FE;
 		}
 	}
-	cli();
+	save_flags(flags); cli();
 	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
 	serial_outp(info, UART_DLL, quot & 0xff);	/* LS of divisor */
 	serial_outp(info, UART_DLM, quot >> 8);		/* MS of divisor */
 	serial_outp(info, UART_LCR, cval);		/* reset DLAB */
 	serial_outp(info, UART_FCR, fcr); 	/* set fcr */
-	sti();
+	restore_flags(flags);
 }
 
 static void rs_put_char(struct tty_struct *tty, unsigned char ch)
diff -u --recursive --new-file v2.0.33/linux/drivers/char/specialix.c linux/drivers/char/specialix.c
--- v2.0.33/linux/drivers/char/specialix.c	Tue Aug 12 13:06:54 1997
+++ linux/drivers/char/specialix.c	Wed Jun  3 15:17:47 1998
@@ -2,7 +2,7 @@
  *      specialix.c  -- specialix IO8+ multiport serial driver.
  *
  *      Copyright (C) 1997  Roger Wolff (R.E.Wolff@BitWizard.nl)
- *      Copyright (C) 1994-1996  Dmitry Gorodchanin (begemot@bgm.rosprint.net)
+ *      Copyright (C) 1994-1996  Dmitry Gorodchanin (pgmdsg@ibi.com)
  *
  *      Specialix pays for the development and support of this driver.
  *      Please DO contact io8-linux@specialix.co.uk if you require
@@ -69,7 +69,7 @@
  */
 
 #include <linux/module.h>
-
+#include <linux/config.h> /* CONFIG_SPECIALIX_RTSCTS */
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/char/specialix_io8.h linux/drivers/char/specialix_io8.h
--- v2.0.33/linux/drivers/char/specialix_io8.h	Tue Aug 12 13:06:54 1997
+++ linux/drivers/char/specialix_io8.h	Wed Jun  3 15:17:47 1998
@@ -3,7 +3,7 @@
  *                                   Specialix IO8+ multiport serial driver.
  *
  *      Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl)
- *      Copyright (C) 1994-1996  Dmitry Gorodchanin (begemot@bgm.rosprint.net)
+ *      Copyright (C) 1994-1996  Dmitry Gorodchanin (pgmdsg@ibi.com)
  *
  *
  *      Specialix pays for the development and support of this driver.
diff -u --recursive --new-file v2.0.33/linux/drivers/char/tga.c linux/drivers/char/tga.c
--- v2.0.33/linux/drivers/char/tga.c	Mon Jun  3 20:06:37 1996
+++ linux/drivers/char/tga.c	Wed Jun  3 15:17:47 1998
@@ -201,7 +201,7 @@
 void tga_clear_screen(void);
 
 void
-set_palette (void)
+tga_set_palette (void)
 {
   int i, j;
 
@@ -233,7 +233,7 @@
 }
 
 void
-__set_origin(unsigned short offset)
+tga_set_origin(unsigned short offset)
 {
   /*
    * should not be called, but if so, do nothing...
@@ -244,7 +244,7 @@
  * Hide the cursor from view, during blanking, usually...
  */
 void
-hide_cursor(void)
+tga_hide_cursor(void)
 {
 	unsigned long flags;
 	save_flags(flags); cli();
@@ -259,7 +259,7 @@
 }
 
 void
-set_cursor(int currcons)
+tga_set_cursor(int currcons)
 {
   unsigned int idx, xt, yt, row, col;
   unsigned long flags;
@@ -267,8 +267,10 @@
   if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
     return;
 
+#if 0
   if (__real_origin != __origin)
-    __set_origin(__real_origin);
+    tga_set_origin(__real_origin);
+#endif
 
   save_flags(flags); cli();
 
@@ -300,12 +302,12 @@
     }
 
   } else
-    hide_cursor();
+    tga_hide_cursor();
   restore_flags(flags);
 }
 
 unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+tga_init(unsigned long kmem_start, const char **display_desc)
 {
         can_do_color = 1;
 
@@ -328,7 +330,7 @@
  * the VGA version of set_scrmem() has some direct VGA references.
  */
 void
-get_scrmem(int currcons)
+tga_get_scrmem(int currcons)
 {
 	memcpyw((unsigned short *)vc_scrbuf[currcons],
 		(unsigned short *)origin, video_screen_size);
@@ -338,7 +340,7 @@
 }
 
 void
-set_scrmem(int currcons, long offset)
+tga_set_scrmem(int currcons, long offset)
 {
 	if (video_mem_term - video_mem_base < offset + video_screen_size)
 	  offset = 0;	/* strange ... */
@@ -357,7 +359,7 @@
  * for now, we will use/allow *only* our built-in font...
  */
 int
-set_get_font(char * arg, int set, int ch512)
+tga_set_get_font(char * arg, int set, int ch512)
 {
 	return -EINVAL;
 }
@@ -371,7 +373,7 @@
  * for now, we only support the built-in font...
  */
 int
-con_adjust_height(unsigned long fontheight)
+tga_adjust_height(unsigned long fontheight)
 {
 	return -EINVAL;
 }
@@ -386,7 +388,7 @@
  */
 
 int
-set_get_cmap(unsigned char * arg, int set) {
+tga_set_get_cmap(unsigned char * arg, int set) {
 	int i;
 
 	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
@@ -424,16 +426,16 @@
  * dummy routines for the VESA blanking code, which is VGA only,
  * so we don't have to carry that stuff around for the TGA...
  */
-void vesa_powerdown(void)
+void tga_vesa_powerdown(void)
 {
 }
-void vesa_blank(void)
+void tga_vesa_blank(void)
 {
 }
-void vesa_unblank(void)
+void tga_vesa_unblank(void)
 {
 }
-void set_vesa_blanking(const unsigned long arg)
+void tga_set_vesa_blanking(const unsigned long arg)
 {
 }
 
@@ -441,9 +443,13 @@
  * video init code, called from within the PCI bus probing code;
  * when TGA console is configured, at the end of the probing code,
  * we call here to look for a TGA device, and proceed...
+ *
+ * note that this code MUST be called BEFORE console_init/con_init,
+ * so that either VGA or TGA are set up but not both. we had to move
+ * console_init to after pci_init in start_kernel to assure this.
  */
 void
-tga_console_init(void)
+tga_console_find(void)
 {
 	unsigned char pci_bus, pci_devfn;
 	int status;
@@ -477,10 +483,11 @@
 	tga_init_video();
 	tga_clear_screen();
 
-	/*
-	 * FINALLY, we can register TGA as console (whew!)
-	 */
-	register_console(console_print);
+#ifdef CONFIG_VGA_CONSOLE
+	/* if both are configured, we are using a dispatch table,
+	   so we must set the index */
+	curr_cons = 1;
+#endif
 }
 
 unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
diff -u --recursive --new-file v2.0.33/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.0.33/linux/drivers/char/tty_io.c	Tue Sep 16 09:36:49 1997
+++ linux/drivers/char/tty_io.c	Wed Jun  3 15:17:47 1998
@@ -1163,6 +1163,10 @@
 		}
 	}
 #endif
+
+	if (tty->driver.close)
+		tty->driver.close(tty, filp);
+
 	/*
 	 * Sanity check: if tty->count is going to zero, there shouldn't be
 	 * any waiters on tty->read_wait or tty->write_wait.  We test the
@@ -1219,9 +1223,6 @@
 	 * both sides, and we've completed the last operation that could 
 	 * block, so it's safe to proceed with closing.
 	 */
-
-	if (tty->driver.close)
-		tty->driver.close(tty, filp);
 
 	if (pty_master) {
 		if (--o_tty->count < 0) {
diff -u --recursive --new-file v2.0.33/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
--- v2.0.33/linux/drivers/char/wdt.c	Fri Apr 12 00:33:25 1996
+++ linux/drivers/char/wdt.c	Wed Jun  3 15:17:47 1998
@@ -42,8 +42,8 @@
  *	You must set these - there is no sane way to probe for this board.
  */
  
-int io=0x240;
-int irq=14;
+static int io=0x240;
+static int irq=14;
 
 #define WD_TIMO (100*60)		/* 1 minute */
 
diff -u --recursive --new-file v2.0.33/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c
--- v2.0.33/linux/drivers/isdn/avmb1/capiutil.c	Mon Aug  4 17:33:59 1997
+++ linux/drivers/isdn/avmb1/capiutil.c	Wed Jun  3 15:17:47 1998
@@ -25,6 +25,7 @@
  * Initial revision
  *
  */
+#include <linux/config.h> /* CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON */
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.0.33/linux/drivers/isdn/isdn_net.c	Mon Aug  4 17:34:00 1997
+++ linux/drivers/isdn/isdn_net.c	Wed Jun  3 15:17:47 1998
@@ -208,9 +208,7 @@
 #include <net/icmp.h>
 #include "isdn_common.h"
 #include "isdn_net.h"
-#ifdef CONFIG_ISDN_PPP
 #include "isdn_ppp.h"
-#endif
 
 /* Prototypes */
 
@@ -822,6 +820,9 @@
 
 	addinfo[0] = '\0';
 	switch (lp->p_encap) {
+                case ISDN_NET_ENCAP_SYNCPPP:
+                        p = &buf[IPPP_MAX_HEADER];
+                        break;
 		case ISDN_NET_ENCAP_IPTYP:
 			proto = ntohs(*(unsigned short *) &buf[0]);
 			p = &buf[2];
@@ -1344,6 +1345,7 @@
 	isdn_net_local *lp = dev->priv;
 	ushort len = 0;
 
+	skb->mac.raw = skb->data;
 	switch (lp->p_encap) {
 		case ISDN_NET_ENCAP_ETHER:
 			len = my_eth_header(skb, dev, type, daddr, saddr, plen);
@@ -2256,6 +2258,7 @@
 			p->local.chargeint = cfg->chargeint * HZ;
 		}
 		if (cfg->p_encap != p->local.p_encap) {
+			/* FIXME: What if there are alias devices too? */
 			if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
 				p->dev.hard_header = NULL;
 #if (LINUX_VERSION_CODE < 0x02010F)
@@ -2282,7 +2285,7 @@
 					p->dev.hard_header_cache = NULL;
 #endif
 					p->dev.header_cache_update = NULL;
-					p->dev.flags = IFF_NOARP;
+					p->dev.flags = IFF_NOARP | IFF_SOFTHEADERS;
 				}
 			}
 		}
diff -u --recursive --new-file v2.0.33/linux/drivers/isdn/sc/includes.h linux/drivers/isdn/sc/includes.h
--- v2.0.33/linux/drivers/isdn/sc/includes.h	Mon Aug  4 17:34:01 1997
+++ linux/drivers/isdn/sc/includes.h	Wed Jun  3 15:17:47 1998
@@ -1,6 +1,5 @@
 #include <linux/module.h>
 #include <linux/version.h>
-#include <stdio.h>
 #include <linux/errno.h>
 #include <asm/segment.h>
 #include <asm/io.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.0.33/linux/drivers/net/3c509.c	Fri Sep  5 11:20:20 1997
+++ linux/drivers/net/3c509.c	Wed Jun  3 15:17:47 1998
@@ -689,13 +689,13 @@
 				lp->stats.rx_packets++;
 				continue;
 			} else if (el3_debug)
-				printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+				printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n",
 					   dev->name, pkt_len);
 		}
 		lp->stats.rx_dropped++;
 		outw(RxDiscard, ioaddr + EL3_CMD);
 		while (inw(ioaddr + EL3_STATUS) & 0x1000)
-			printk("	Waiting for 3c509 to discard packet, status %x.\n",
+			printk(KERN_DEBUG "        Waiting for 3c509 to discard packet, status %x.\n",
 				   inw(ioaddr + EL3_STATUS) );
 	}
 
diff -u --recursive --new-file v2.0.33/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.0.33/linux/drivers/net/3c515.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/3c515.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,1502 @@
+/* 3c515.c: A 3Com ISA EtherLink XL "Corkscrew" ethernet driver for linux. */
+/*
+	Written 1997-1998 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This driver is for the 3Com ISA EtherLink XL "Corkscrew" 3c515 ethercard.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+*/
+
+static char *version = "3c515.c:v0.99 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
+#define CORKSCREW 1
+
+/* "Knobs" that adjust features and parameters. */
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1512 effectively disables this feature. */
+static const rx_copybreak = 200;
+/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
+static const mtu = 1500;
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Enable the automatic media selection code -- usually set. */
+#define AUTOMEDIA 1
+
+/* Allow the use of fragment bus master transfers instead of only
+   programmed-I/O for Vortex cards.  Full-bus-master transfers are always
+   enabled by default on Boomerang cards.  If VORTEX_BUS_MASTER is defined,
+   the feature may be turned on using 'options'. */
+#define VORTEX_BUS_MASTER
+
+/* A few values that may be tweaked. */
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	16
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/timer.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#else
+#define udelay(microsec)	do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
+
+/* Kernel version compatibility functions. */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#elif defined(MODULE)
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+#endif
+
+/* "Knobs" for adjusting internal parameters. */
+/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
+#define DRIVER_DEBUG 1
+/* Some values here only for performance evaluation and path-coverage
+   debugging. */
+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
+
+/* Number of times to check to see if the Tx FIFO has space, used in some
+   limited cases. */
+#define WAIT_TX_AVAIL 200
+
+/* Operational parameter that usually are not changed. */
+#define TX_TIMEOUT  40		/* Time in jiffies before concluding Tx hung */
+
+/* The size here is somewhat misleading: the Corkscrew also uses the ISA
+   aliased registers at <base>+0x400.
+   */
+#define CORKSCREW_TOTAL_SIZE 0x20
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry tc515_drv =
+{"3c515", tc515_probe, CORKSCREW_TOTAL_SIZE, NULL};
+#endif
+
+#ifdef DRIVER_DEBUG
+int vortex_debug = DRIVER_DEBUG;
+#else
+int vortex_debug = 1;
+#endif
+
+#define CORKSCREW_ID 10
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the 3Com 3c515 ISA Fast EtherLink XL,
+3Com's ISA bus adapter for Fast Ethernet.  Due to the unique I/O port layout,
+it's not practical to integrate this driver with the other EtherLink drivers.
+
+II. Board-specific settings
+
+The Corkscrew has an EEPROM for configuration, but no special settings are
+needed for Linux.
+
+III. Driver operation
+
+The 3c515 series use an interface that's very similar to the 3c900 "Boomerang"
+PCI cards, with the bus master interface extensively modified to work with
+the ISA bus.
+
+The card is capable of full-bus-master transfers with seperate
+lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
+DEC Tulip and Intel Speedo3.
+
+This driver uses a "RX_COPYBREAK" scheme rather than a fixed intermediate
+receive buffer.  This scheme allocates full-sized skbuffs as receive
+buffers.  The value RX_COPYBREAK is used as the copying breakpoint: it is
+chosen to trade-off the memory wasted by passing the full-sized skbuff to
+the queue layer for all frames vs. the copying cost of copying a frame to a
+correctly-sized skbuff.
+
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+IV. Notes
+
+Thanks to Terry Murphy of 3Com for providing documentation and a development
+board.
+
+The names "Vortex", "Boomerang" and "Corkscrew" are the internal 3Com
+project names.  I use these names to eliminate confusion -- 3Com product
+numbers and names are very similar and often confused.
+
+The new chips support both ethernet (1.5K) and FDDI (4.5K) frame sizes!
+This driver only supports ethernet frames because of the recent MTU limit
+of 1.5K, but the changes to support 4.5K are minimal.
+*/
+
+/* Operational definitions.
+   These are not used by other compilation units and thus are not
+   exported in a ".h" file.
+
+   First the windows.  There are eight register windows, with the command
+   and status registers available in each.
+   */
+#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
+#define EL3_CMD 0x0e
+#define EL3_STATUS 0x0e
+
+/* The top five bits written to EL3_CMD are a command, the lower
+   11 bits are the parameter, if applicable.
+   Note that 11 parameters bits was fine for ethernet, but the new chips
+   can handle FDDI length frames (~4500 octets) and now parameters count
+   32-bit 'Dwords' rather than octets. */
+
+enum vortex_cmd {
+	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
+	UpStall = 6<<11, UpUnstall = (6<<11)+1,
+	DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
+	RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+	SetTxThreshold = 18<<11, SetTxStart = 19<<11,
+	StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
+	StatsDisable = 22<<11, StopCoax = 23<<11,};
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
+
+/* Bits in the general status register. */
+enum vortex_status {
+	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+	IntReq = 0x0040, StatsFull = 0x0080,
+	DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
+	DMAInProgress = 1<<11,			/* DMA controller is still busy.*/
+	CmdInProgress = 1<<12,			/* EL3_CMD is still busy.*/
+};
+
+/* Register window 1 offsets, the window used in normal operation.
+   On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */
+enum Window1 {
+	TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
+	RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
+	TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
+};
+enum Window0 {
+  Wn0IRQ = 0x08,
+#if defined(CORKSCREW)
+	Wn0EepromCmd = 0x200A,		/* Corkscrew EEPROM command register. */
+	Wn0EepromData = 0x200C,		/* Corkscrew EEPROM results register. */
+#else
+	Wn0EepromCmd = 10,		/* Window 0: EEPROM command register. */
+	Wn0EepromData = 12,		/* Window 0: EEPROM results register. */
+#endif
+};
+enum Win0_EEPROM_bits {
+	EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
+	EEPROM_EWENB = 0x30,		/* Enable erasing/writing for 10 msec. */
+	EEPROM_EWDIS = 0x00,		/* Disable EWENB before 10 msec timeout. */
+};
+/* EEPROM locations. */
+enum eeprom_offset {
+	PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
+	EtherLink3ID=7, };
+
+enum Window3 {			/* Window 3: MAC/config bits. */
+	Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
+};
+union wn3_config {
+	int i;
+	struct w3_config_fields {
+		unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
+		int pad8:8;
+		unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
+		int pad24:7;
+	} u;
+};
+
+enum Window4 {
+	Wn4_NetDiag = 6, Wn4_Media = 10,		/* Window 4: Xcvr/media bits. */
+};
+enum Win4_Media_bits {
+	Media_SQE = 0x0008,		/* Enable SQE error counting for AUI. */
+	Media_10TP = 0x00C0,	/* Enable link beat and jabber for 10baseT. */
+	Media_Lnk = 0x0080,		/* Enable just link beat for 100TX/100FX. */
+	Media_LnkBeat = 0x0800,
+};
+enum Window7 {					/* Window 7: Bus Master control. */
+	Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
+};
+/* Boomerang-style bus master control registers.  Note ISA aliases! */
+enum MasterCtrl {
+	PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen = 0x40c,
+	TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418,
+};
+
+/* The Rx and Tx descriptor lists.
+   Caution Alpha hackers: these types are 32 bits!  Note also the 8 byte
+   alignment contraint on tx_ring[] and rx_ring[]. */
+struct boom_rx_desc {
+	u32 next;
+	s32 status;
+	u32 addr;
+	s32 length;
+};
+/* Values for the Rx status entry. */
+enum rx_desc_status {
+	RxDComplete=0x00008000, RxDError=0x4000,
+	/* See boomerang_rx() for actual error bits */
+};
+
+struct boom_tx_desc {
+	u32 next;
+	s32 status;
+	u32 addr;
+	s32 length;
+};
+
+struct vortex_private {
+	char devname[8];			/* "ethN" string, also for kernel debug. */
+	const char *product_name;
+	struct device *next_module;
+	/* The Rx and Tx rings are here to keep them quad-word-aligned. */
+	struct boom_rx_desc rx_ring[RX_RING_SIZE];
+	struct boom_tx_desc tx_ring[TX_RING_SIZE];
+	/* The addresses of transmit- and receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	struct enet_statistics stats;
+	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
+	struct timer_list timer;	/* Media selection timer. */
+	int capabilities;			/* Adapter capabilities word. */
+	int options;				/* User-settable misc. driver options. */
+	int last_rx_packets;		/* For media autoselection. */
+	unsigned int available_media:8,	/* From Wn3_Options */
+	  media_override:3, 			/* Passed-in media type. */
+	  default_media:3,			/* Read from the EEPROM. */
+	  full_duplex:1, autoselect:1,
+	  bus_master:1,				/* Vortex can only do a fragment bus-m. */
+	  full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang  */
+      tx_full:1;
+};
+
+/* The action to take with a media selection timer tick.
+   Note that we deviate from the 3Com order by checking 10base2 before AUI.
+ */
+enum xcvr_types {
+	XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
+	XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8,
+};
+
+static struct media_table {
+  char *name;
+  unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
+	mask:8,				/* The transceiver-present bit in Wn3_Config.*/
+	next:8;				/* The media type to try next. */
+  short wait;			/* Time before we check media status. */
+} media_tbl[] = {
+  {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
+  { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
+  { "undefined", 0,			0x80, XCVR_10baseT, 10000},
+  { "10base2",   0,			0x10, XCVR_AUI,		(1*HZ)/10},
+  { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
+  { "100baseFX", Media_Lnk, 0x04, XCVR_MII,		(14*HZ)/10},
+  { "MII",		 0,			0x40, XCVR_10baseT, 3*HZ },
+  { "undefined", 0,			0x01, XCVR_10baseT, 10000},
+  { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
+};
+
+static int vortex_scan(struct device *dev);
+static struct device *vortex_found_device(struct device *dev, int ioaddr,
+										  int irq, int product_index,
+										  int options);
+static int vortex_probe1(struct device *dev);
+static int vortex_open(struct device *dev);
+static void vortex_timer(unsigned long arg);
+static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
+static int vortex_rx(struct device *dev);
+static int boomerang_rx(struct device *dev);
+static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
+static int vortex_close(struct device *dev);
+static void update_stats(int addr, struct device *dev);
+static struct enet_statistics *vortex_get_stats(struct device *dev);
+static void set_rx_mode(struct device *dev);
+
+
+/* Unlike the other PCI cards the 59x cards don't need a large contiguous
+   memory region, so making the driver a loadable module is feasible.
+
+   Unfortunately maximizing the shared code between the integrated and
+   module version of the driver results in a complicated set of initialization
+   procedures.
+   init_module() -- modules /  tc59x_init()  -- built-in
+		The wrappers for vortex_scan()
+   vortex_scan()  		 The common routine that scans for PCI and EISA cards
+   vortex_found_device() Allocate a device structure when we find a card.
+					Different versions exist for modules and built-in.
+   vortex_probe1()		Fill in the device structure -- this is separated
+					so that the modules code can put it in dev->init.
+*/
+/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
+/* Note: this is the only limit on the number of cards supported!! */
+static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+
+#ifdef MODULE
+static int debug = -1;
+/* A list of all installed Vortex devices, for removing the driver module. */
+static struct device *root_vortex_dev = NULL;
+
+int
+init_module(void)
+{
+	int cards_found;
+
+	if (debug >= 0)
+		vortex_debug = debug;
+	if (vortex_debug)
+		printk(version);
+
+	root_vortex_dev = NULL;
+	cards_found = vortex_scan(0);
+	return cards_found ? 0 : -ENODEV;
+}
+
+#else
+int tc515_probe(struct device *dev)
+{
+	int cards_found = 0;
+
+	cards_found = vortex_scan(dev);
+
+	if (vortex_debug > 0  &&  cards_found)
+		printk(version);
+
+	return cards_found ? 0 : -ENODEV;
+}
+#endif  /* not MODULE */
+
+static int vortex_scan(struct device *dev)
+{
+	int cards_found = 0;
+	static int ioaddr = 0x100;
+
+	/* Check all locations on the ISA bus -- evil! */
+	for (; ioaddr < 0x400; ioaddr += 0x20) {
+	  int irq;
+	  if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE))
+		continue;
+	  /* Check the resource configuration for a matching ioaddr. */
+	  if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0))
+		continue;
+	  /* Verify by reading the device ID from the EEPROM. */
+	  {
+		int timer;
+		outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd);
+		/* Pause for at least 162 us. for the read to take place. */
+		for (timer = 4; timer >= 0; timer--) {
+		  udelay(162);
+		  if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
+			break;
+		}
+		if (inw(ioaddr + Wn0EepromData) != 0x6d50)
+		  continue;
+	  }
+	  printk("3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n",
+			 inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
+	  irq = inw(ioaddr + 0x2002) & 15;
+	  vortex_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev && dev->mem_start
+						  ? dev->mem_start : options[cards_found]);
+	  dev = 0;
+	  cards_found++;
+	}
+
+	if (vortex_debug)
+	  printk("%d 3c515 cards found.\n", cards_found);
+	return cards_found;
+}
+
+static struct device *vortex_found_device(struct device *dev, int ioaddr,
+										  int irq, int product_index,
+										  int options)
+{
+	struct vortex_private *vp;
+
+#ifdef MODULE
+	/* Allocate and fill new device structure. */
+	int dev_size = sizeof(struct device) +
+		sizeof(struct vortex_private) + 15;		/* Pad for alignment */
+	
+	dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
+	memset(dev, 0, dev_size);
+	/* Align the Rx and Tx ring entries.  */
+	dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
+	vp = (struct vortex_private *)dev->priv;
+	dev->name = vp->devname; /* An empty string. */
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0);
+	dev->init = vortex_probe1;
+	vp->product_name = "3c515";
+	vp->options = options;
+	if (options >= 0) {
+		vp->media_override = ((options & 7) == 2)  ?  0  :  options & 7;
+		vp->full_duplex = (options & 8) ? 1 : 0;
+		vp->bus_master = (options & 16) ? 1 : 0;
+	} else {
+		vp->media_override = 7;
+		vp->full_duplex = 0;
+		vp->bus_master = 0;
+	}
+	ether_setup(dev);
+	vp->next_module = root_vortex_dev;
+	root_vortex_dev = dev;
+	if (register_netdev(dev) != 0)
+		return 0;
+#else  /* not a MODULE */
+	if (dev) {
+		/* Caution: quad-word alignment required for rings! */
+		dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL);
+		memset(dev->priv, 0, sizeof (struct vortex_private));
+	}
+	dev = init_etherdev(dev, sizeof(struct vortex_private));
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0);
+	vp  = (struct vortex_private *)dev->priv;
+	vp->product_name = "3c515";
+	vp->options = options;
+	if (options >= 0) {
+		vp->media_override = ((options & 7) == 2)  ?  0  :  options & 7;
+		vp->full_duplex = (options & 8) ? 1 : 0;
+		vp->bus_master = (options & 16) ? 1 : 0;
+	} else {
+		vp->media_override = 7;
+		vp->full_duplex = 0;
+		vp->bus_master = 0;
+	}
+
+	vortex_probe1(dev);
+#endif /* MODULE */
+	return dev;
+}
+
+static int vortex_probe1(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
+	int i;
+
+	printk("%s: 3Com %s at %#3x,", dev->name,
+		   vp->product_name, ioaddr);
+
+	/* Read the station address from the EEPROM. */
+	EL3WINDOW(0);
+	for (i = 0; i < 0x18; i++) {
+		short *phys_addr = (short *)dev->dev_addr;
+		int timer;
+		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
+		/* Pause for at least 162 us. for the read to take place. */
+		for (timer = 4; timer >= 0; timer--) {
+			udelay(162);
+			if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
+				break;
+		}
+		eeprom[i] = inw(ioaddr + Wn0EepromData);
+		checksum ^= eeprom[i];
+		if (i < 3)
+			phys_addr[i] = htons(eeprom[i]);
+	}
+	checksum = (checksum ^ (checksum >> 8)) & 0xff;
+	if (checksum != 0x00)
+		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+	if (eeprom[16] == 0x11c7) { 		/* Corkscrew */
+	  if (request_dma(dev->dma, "3c515")) {
+		printk(", DMA %d allocation failed", dev->dma);
+		dev->dma = 0;
+	  } else 
+		printk(", DMA %d", dev->dma);
+	}
+	printk(", IRQ %d\n", dev->irq);
+	/* Tell them about an invalid IRQ. */
+	if (vortex_debug && (dev->irq <= 0 || dev->irq > 15))
+		printk(" *** Warning: this IRQ is unlikely to work! ***\n");
+
+	{
+		char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+		union wn3_config config;
+		EL3WINDOW(3);
+		vp->available_media = inw(ioaddr + Wn3_Options);
+		config.i = inl(ioaddr + Wn3_Config);
+		if (vortex_debug > 1)
+			printk("  Internal config register is %4.4x, transceivers %#x.\n",
+				   config.i, inw(ioaddr + Wn3_Options));
+		printk("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+			   8 << config.u.ram_size,
+			   config.u.ram_width ? "word" : "byte",
+			   ram_split[config.u.ram_split],
+			   config.u.autoselect ? "autoselect/" : "",
+			   media_tbl[config.u.xcvr].name);
+		dev->if_port = config.u.xcvr;
+		vp->default_media = config.u.xcvr;
+		vp->autoselect = config.u.autoselect;
+	}
+	if (vp->media_override != 7) {
+		printk("  Media override to transceiver type %d (%s).\n",
+			   vp->media_override, media_tbl[vp->media_override].name);
+		dev->if_port = vp->media_override;
+	}
+
+	vp->capabilities = eeprom[16];
+	vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0;
+	/* Rx is broken at 10mbps, so we always disable it. */
+	/* vp->full_bus_master_rx = 0;*/
+	vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
+
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, CORKSCREW_TOTAL_SIZE, vp->product_name);
+
+	/* The 3c59x-specific entries in the device structure. */
+	dev->open = &vortex_open;
+	dev->hard_start_xmit = &vortex_start_xmit;
+	dev->stop = &vortex_close;
+	dev->get_stats = &vortex_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+
+	return 0;
+}
+
+
+static int
+vortex_open(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	union wn3_config config;
+	int i;
+
+	/* Before initializing select the active media port. */
+	EL3WINDOW(3);
+	if (vp->full_duplex)
+		outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
+	config.i = inl(ioaddr + Wn3_Config);
+
+	if (vp->media_override != 7) {
+		if (vortex_debug > 1)
+			printk("%s: Media override to transceiver %d (%s).\n",
+				   dev->name, vp->media_override,
+				   media_tbl[vp->media_override].name);
+		dev->if_port = vp->media_override;
+	} else if (vp->autoselect) {
+		/* Find first available media type, starting with 100baseTx. */
+		dev->if_port = 4;
+		while (! (vp->available_media & media_tbl[dev->if_port].mask))
+			dev->if_port = media_tbl[dev->if_port].next;
+
+		if (vortex_debug > 1)
+			printk("%s: Initial media type %s.\n",
+				   dev->name, media_tbl[dev->if_port].name);
+
+		init_timer(&vp->timer);
+		vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+		vp->timer.data = (unsigned long)dev;
+		vp->timer.function = &vortex_timer;    /* timer handler */
+		add_timer(&vp->timer);
+	} else
+		dev->if_port = vp->default_media;
+
+	config.u.xcvr = dev->if_port;
+	outl(config.i, ioaddr + Wn3_Config);
+
+	if (vortex_debug > 1) {
+		printk("%s: vortex_open() InternalConfig %8.8x.\n",
+			dev->name, config.i);
+	}
+
+	outw(TxReset, ioaddr + EL3_CMD);
+	for (i = 20; i >= 0 ; i--)
+		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+			break;
+
+	outw(RxReset, ioaddr + EL3_CMD);
+	/* Wait a few ticks for the RxReset command to complete. */
+	for (i = 20; i >= 0 ; i--)
+		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+			break;
+
+	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
+
+	/* Use the now-standard shared IRQ implementation. */
+	if (vp->capabilities == 0x11c7) {
+	  /* Corkscrew: Cannot share ISA resources. */
+	  if (dev->irq == 0
+		  || dev->dma == 0
+		  || request_irq(dev->irq, &vortex_interrupt, 0,
+						 vp->product_name, dev))
+		return -EAGAIN;
+	  enable_dma(dev->dma);
+	  set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+	} else if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
+						   vp->product_name, dev)) {
+	  return -EAGAIN;
+	}
+
+	if (vortex_debug > 1) {
+		EL3WINDOW(4);
+		printk("%s: vortex_open() irq %d media status %4.4x.\n",
+			   dev->name, dev->irq, inw(ioaddr + Wn4_Media));
+	}
+
+	/* Set the station address and mask in window 2 each time opened. */
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+	for (; i < 12; i+=2)
+		outw(0, ioaddr + i);
+
+	if (dev->if_port == 3)
+		/* Start the thinnet transceiver. We should really wait 50ms...*/
+		outw(StartCoax, ioaddr + EL3_CMD);
+	EL3WINDOW(4);
+	outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
+		 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+
+	/* Switch to the stats window, and clear all stats by reading. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	EL3WINDOW(6);
+	for (i = 0; i < 10; i++)	
+		inb(ioaddr + i);
+	inw(ioaddr + 10);
+	inw(ioaddr + 12);
+	/* New: On the Vortex we must also clear the BadSSD counter. */
+	EL3WINDOW(4);
+	inb(ioaddr + 12);
+	/* ..and on the Boomerang we enable the extra statistics bits. */
+	outw(0x0040, ioaddr + Wn4_NetDiag);
+
+	/* Switch to register set 7 for normal use. */
+	EL3WINDOW(7);
+
+	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+		vp->cur_rx = vp->dirty_rx = 0;
+		if (vortex_debug > 2)
+			printk("%s:  Filling in the Rx ring.\n", dev->name);
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			struct sk_buff *skb;
+			if (i < (RX_RING_SIZE - 1))
+			  vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
+			else
+			  vp->rx_ring[i].next = 0;
+			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
+			vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000;
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			vp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[i].addr = virt_to_bus(skb->tail);
+		}
+		vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
+		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
+	}
+	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
+		vp->cur_tx = vp->dirty_tx = 0;
+		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
+		/* Clear the Tx ring. */
+		for (i = 0; i < TX_RING_SIZE; i++)
+			vp->tx_skbuff[i] = 0;
+		outl(0, ioaddr + DownListPtr);
+	}
+	/* Set reciever mode: presumably accept b-case and phys addr only. */
+	set_rx_mode(dev);
+	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+	/* Allow status bits to be seen. */
+	outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull | 
+		 (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+		 (vp->full_bus_master_rx ? UpComplete : RxComplete) | 
+		 (vp->bus_master ? DMADone : 0),
+		 ioaddr + EL3_CMD);
+	/* Ack all pending events, and set active indicator mask. */
+	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+		 ioaddr + EL3_CMD);
+	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+		 | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
+			ioaddr + EL3_CMD);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static void vortex_timer(unsigned long data)
+{
+#ifdef AUTOMEDIA
+	struct device *dev = (struct device *)data;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	unsigned long flags;
+	int ok = 0;
+
+	if (vortex_debug > 1)
+		printk("%s: Media selection timer tick happened, %s.\n",
+			   dev->name, media_tbl[dev->if_port].name);
+
+	save_flags(flags);	cli(); {
+	  int old_window = inw(ioaddr + EL3_CMD) >> 13;
+	  int media_status;
+	  EL3WINDOW(4);
+	  media_status = inw(ioaddr + Wn4_Media);
+	  switch (dev->if_port) {
+	  case 0:  case 4:  case 5:		/* 10baseT, 100baseTX, 100baseFX  */
+		if (media_status & Media_LnkBeat) {
+		  ok = 1;
+		  if (vortex_debug > 1)
+			printk("%s: Media %s has link beat, %x.\n",
+				   dev->name, media_tbl[dev->if_port].name, media_status);
+		} else if (vortex_debug > 1)
+		  printk("%s: Media %s is has no link beat, %x.\n",
+				   dev->name, media_tbl[dev->if_port].name, media_status);
+ 
+		break;
+	  default:					/* Other media types handled by Tx timeouts. */
+		if (vortex_debug > 1)
+		  printk("%s: Media %s is has no indication, %x.\n",
+				 dev->name, media_tbl[dev->if_port].name, media_status);
+		ok = 1;
+	  }
+	  if ( ! ok) {
+		union wn3_config config;
+
+		do {
+			dev->if_port = media_tbl[dev->if_port].next;
+		} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
+		if (dev->if_port == 8) { /* Go back to default. */
+		  dev->if_port = vp->default_media;
+		  if (vortex_debug > 1)
+			printk("%s: Media selection failing, using default %s port.\n",
+				   dev->name, media_tbl[dev->if_port].name);
+		} else {
+		  if (vortex_debug > 1)
+			printk("%s: Media selection failed, now trying %s port.\n",
+				   dev->name, media_tbl[dev->if_port].name);
+		  vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+		  add_timer(&vp->timer);
+		}
+		outw((media_status & ~(Media_10TP|Media_SQE)) |
+			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+
+		EL3WINDOW(3);
+		config.i = inl(ioaddr + Wn3_Config);
+		config.u.xcvr = dev->if_port;
+		outl(config.i, ioaddr + Wn3_Config);
+
+		outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+	  }
+	  EL3WINDOW(old_window);
+	}   restore_flags(flags);
+	if (vortex_debug > 1)
+	  printk("%s: Media selection timer finished, %s.\n",
+			 dev->name, media_tbl[dev->if_port].name);
+
+#endif /* AUTOMEDIA*/
+	return;
+}
+
+static int
+vortex_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		int i;
+
+		/* Min. wait before assuming a Tx failed == 400ms. */
+
+		if (tickssofar < 400*HZ/1000)		/* We probably aren't empty. */
+			return 1;
+		printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+			   dev->name, inb(ioaddr + TxStatus),
+			   inw(ioaddr + EL3_STATUS));
+		/* Slight code bloat to be user friendly. */
+		if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
+			printk("%s: Transmitter encountered 16 collisions -- network"
+				   " network cable problem?\n", dev->name);
+#ifndef final_version
+		printk("  Flags; bus-master %d, full %d; dirty %d current %d.\n",
+			   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+		printk("  Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+			   &vp->tx_ring[0]);
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			printk("  %d: %p  length %8.8x status %8.8x\n", i,
+				   &vp->tx_ring[i],
+				   vp->tx_ring[i].length,
+				   vp->tx_ring[i].status);
+		}
+#endif
+		/* Issue TX_RESET and TX_START commands. */
+		outw(TxReset, ioaddr + EL3_CMD);
+		for (i = 20; i >= 0 ; i--)
+			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+				break;
+		outw(TxEnable, ioaddr + EL3_CMD);
+		dev->trans_start = jiffies;
+		/* dev->tbusy = 0;*/
+		vp->stats.tx_errors++;
+		vp->stats.tx_dropped++;
+		return 0;			/* Yes, silently *drop* the packet! */
+	}
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	   If this ever occurs the queue layer is doing something evil! */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
+
+	if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */
+		/* Calculate the next Tx descriptor entry. */
+		int entry = vp->cur_tx % TX_RING_SIZE;
+		struct boom_tx_desc *prev_entry;
+		unsigned long flags, i;
+
+		if (vp->tx_full) /* No room to transmit with */
+		  return 1;
+		if (vp->cur_tx != 0)
+		  prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
+		else
+		  prev_entry = NULL;
+		if (vortex_debug > 3)
+			printk("%s: Trying to send a packet, Tx index %d.\n",
+				   dev->name, vp->cur_tx);
+		/* vp->tx_full = 1; */
+		vp->tx_skbuff[entry] = skb;
+		vp->tx_ring[entry].next = 0;
+		vp->tx_ring[entry].addr = virt_to_bus(skb->data);
+		vp->tx_ring[entry].length = skb->len | 0x80000000;
+		vp->tx_ring[entry].status = skb->len | 0x80000000;
+
+		save_flags(flags);
+		cli();
+		outw(DownStall, ioaddr + EL3_CMD);
+		/* Wait for the stall to complete. */
+		for (i = 20; i >= 0 ; i--)
+			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
+				break;
+		if (prev_entry)
+		  prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
+		if (inl(ioaddr + DownListPtr) == 0) {
+			outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
+			queued_packet++;
+		}
+		outw(DownUnstall, ioaddr + EL3_CMD);
+		restore_flags(flags);
+
+		vp->cur_tx++;
+		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
+			vp->tx_full = 1;
+		else {					/* Clear previous interrupt enable. */
+		  if (prev_entry)
+			prev_entry->status &= ~0x80000000;
+		  dev->tbusy = 0;
+		}
+		dev->trans_start = jiffies;
+		return 0;
+	}
+	/* Put out the doubleword header... */
+	outl(skb->len, ioaddr + TX_FIFO);
+#ifdef VORTEX_BUS_MASTER
+	if (vp->bus_master) {
+		/* Set the bus-master controller to transfer the packet. */
+		outl((int)(skb->data), ioaddr + Wn7_MasterAddr);
+		outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
+		vp->tx_skb = skb;
+		outw(StartDMADown, ioaddr + EL3_CMD);
+		/* dev->tbusy will be cleared at the DMADone interrupt. */
+	} else {
+		/* ... and the packet rounded to a doubleword. */
+		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+		dev_kfree_skb (skb, FREE_WRITE);
+		if (inw(ioaddr + TxFree) > 1536) {
+			dev->tbusy = 0;
+		} else
+			/* Interrupt us when the FIFO has room for max-sized packet. */
+			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+	}
+#else
+	/* ... and the packet rounded to a doubleword. */
+	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+	dev_kfree_skb (skb, FREE_WRITE);
+	if (inw(ioaddr + TxFree) > 1536) {
+		dev->tbusy = 0;
+	} else
+		/* Interrupt us when the FIFO has room for max-sized packet. */
+		outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+#endif  /* bus master */
+
+	dev->trans_start = jiffies;
+
+	/* Clear the Tx status stack. */
+	{
+		short tx_status;
+		int i = 4;
+
+		while (--i > 0	&&	(tx_status = inb(ioaddr + TxStatus)) > 0) {
+			if (tx_status & 0x3C) {		/* A Tx-disabling error occurred.  */
+				if (vortex_debug > 2)
+				  printk("%s: Tx error, status %2.2x.\n",
+						 dev->name, tx_status);
+				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
+				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
+				if (tx_status & 0x30) {
+					int j;
+					outw(TxReset, ioaddr + EL3_CMD);
+					for (j = 20; j >= 0 ; j--)
+						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+							break;
+				}
+				outw(TxEnable, ioaddr + EL3_CMD);
+			}
+			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
+		}
+	}
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* Use the now-standard shared IRQ implementation. */
+	struct device *dev = dev_id;
+	struct vortex_private *lp;
+	int ioaddr, status;
+	int latency;
+	int i = max_interrupt_work;
+
+	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	latency = inb(ioaddr + Timer);
+	lp = (struct vortex_private *)dev->priv;
+
+	status = inw(ioaddr + EL3_STATUS);
+
+	if (vortex_debug > 4)
+		printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name,
+			   status, latency);
+	if ((status & 0xE000) != 0xE000) {
+		static int donedidthis=0;
+		/* Some interrupt controllers store a bogus interrupt from boot-time.
+		   Ignore a single early interrupt, but don't hang the machine for
+		   other interrupt problems. */
+		if (donedidthis++ > 100) {
+			printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
+				   dev->name, status, dev->start);
+			FREE_IRQ(dev->irq, dev);
+		}
+	}
+
+	do {
+		if (vortex_debug > 5)
+				printk("%s: In interrupt loop, status %4.4x.\n",
+					   dev->name, status);
+		if (status & RxComplete)
+			vortex_rx(dev);
+
+		if (status & TxAvailable) {
+			if (vortex_debug > 5)
+				printk("	TX room bit was handled.\n");
+			/* There's room in the FIFO for a full-sized packet. */
+			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+		if (status & DownComplete) {
+			unsigned int dirty_tx = lp->dirty_tx;
+
+			while (lp->cur_tx - dirty_tx > 0) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				if (inl(ioaddr + DownListPtr) ==
+					virt_to_bus(&lp->tx_ring[entry]))
+					break;			/* It still hasn't been processed. */
+				if (lp->tx_skbuff[entry]) {
+					dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+					lp->tx_skbuff[entry] = 0;
+				}
+				dirty_tx++;
+			}
+			lp->dirty_tx = dirty_tx;
+			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
+			if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+				lp->tx_full= 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+		}
+#ifdef VORTEX_BUS_MASTER
+		if (status & DMADone) {
+			outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
+			dev->tbusy = 0;
+			dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
+			mark_bh(NET_BH);
+		}
+#endif
+		if (status & UpComplete) {
+			boomerang_rx(dev);
+			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+		}
+		if (status & (AdapterFailure | RxEarly | StatsFull)) {
+			/* Handle all uncommon interrupts at once. */
+			if (status & RxEarly) {				/* Rx early is unused. */
+				vortex_rx(dev);
+				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+			}
+			if (status & StatsFull) { 	/* Empty statistics. */
+				static int DoneDidThat = 0;
+				if (vortex_debug > 4)
+					printk("%s: Updating stats.\n", dev->name);
+				update_stats(ioaddr, dev);
+				/* DEBUG HACK: Disable statistics as an interrupt source. */
+				/* This occurs when we have the wrong media type! */
+				if (DoneDidThat == 0  &&
+					inw(ioaddr + EL3_STATUS) & StatsFull) {
+					int win, reg;
+					printk("%s: Updating stats failed, disabling stats as an"
+						   " interrupt source.\n", dev->name);
+					for (win = 0; win < 8; win++) {
+						EL3WINDOW(win);
+						printk("\n Vortex window %d:", win);
+						for (reg = 0; reg < 16; reg++)
+							printk(" %2.2x", inb(ioaddr+reg));
+					}
+					EL3WINDOW(7);
+					outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure
+						 | UpComplete | DownComplete | TxComplete,
+						 ioaddr + EL3_CMD);
+					DoneDidThat++;
+				}
+			}
+			if (status & AdapterFailure) {
+				/* Adapter failure requires Rx reset and reinit. */
+				outw(RxReset, ioaddr + EL3_CMD);
+				/* Set the Rx filter to the current state. */
+				set_rx_mode(dev);
+				outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+			}
+		}
+
+		if (--i < 0) {
+			printk("%s: Too much work in interrupt, status %4.4x.  "
+				   "Disabling functions (%4.4x).\n",
+				   dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
+			/* Disable all pending interrupts. */
+			outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
+			outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
+			break;
+		}
+		/* Acknowledge the IRQ. */
+		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+
+	} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+
+	if (vortex_debug > 4)
+		printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
+
+	dev->interrupt = 0;
+	return;
+}
+
+static int
+vortex_rx(struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+	short rx_status;
+
+	if (vortex_debug > 5)
+		printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
+		if (rx_status & 0x4000) { /* Error, update stats. */
+			unsigned char rx_error = inb(ioaddr + RxErrors);
+			if (vortex_debug > 2)
+				printk(" Rx error: status %2.2x.\n", rx_error);
+			vp->stats.rx_errors++;
+			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
+			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
+			if (rx_error & 0x04)  vp->stats.rx_frame_errors++;
+			if (rx_error & 0x08)  vp->stats.rx_crc_errors++;
+			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
+		} else {
+			/* The packet length: up to 4.5K!. */
+			short pkt_len = rx_status & 0x1fff;
+			struct sk_buff *skb;
+
+			skb = DEV_ALLOC_SKB(pkt_len + 5);
+			if (vortex_debug > 4)
+				printk("Receiving packet size %d status %4.4x.\n",
+					   pkt_len, rx_status);
+			if (skb != NULL) {
+				skb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x10300
+				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+				/* 'skb_put()' points to the start of sk_buff data area. */
+				insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
+					 (pkt_len + 3) >> 2);
+				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
+				skb->protocol = eth_type_trans(skb, dev);
+#else
+				skb->len = pkt_len;
+				/* 'skb->data' points to the start of sk_buff data area. */
+				insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2);
+				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
+#endif  /* KERNEL_1_3_0 */
+				netif_rx(skb);
+				dev->last_rx = jiffies;
+				vp->stats.rx_packets++;
+				/* Wait a limited time to go to next packet. */
+				for (i = 200; i >= 0; i--)
+					if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+						break;
+				continue;
+			} else if (vortex_debug)
+				printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+					   dev->name, pkt_len);
+		}
+		outw(RxDiscard, ioaddr + EL3_CMD);
+		vp->stats.rx_dropped++;
+		/* Wait a limited time to skip this packet. */
+		for (i = 200; i >= 0; i--)
+			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+				break;
+	}
+
+	return 0;
+}
+
+static int
+boomerang_rx(struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int entry = vp->cur_rx % RX_RING_SIZE;
+	int ioaddr = dev->base_addr;
+	int rx_status;
+
+	if (vortex_debug > 5)
+		printk("   In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
+			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+	while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
+		if (rx_status & RxDError) { /* Error, update stats. */
+			unsigned char rx_error = rx_status >> 16;
+			if (vortex_debug > 2)
+				printk(" Rx error: status %2.2x.\n", rx_error);
+			vp->stats.rx_errors++;
+			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
+			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
+			if (rx_error & 0x04)  vp->stats.rx_frame_errors++;
+			if (rx_error & 0x08)  vp->stats.rx_crc_errors++;
+			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
+		} else {
+			/* The packet length: up to 4.5K!. */
+			short pkt_len = rx_status & 0x1fff;
+			struct sk_buff *skb;
+
+			if (vortex_debug > 4)
+				printk("Receiving packet size %d status %4.4x.\n",
+					   pkt_len, rx_status);
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+				/* 'skb_put()' points to the start of sk_buff data area. */
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(vp->rx_ring[entry].addr),
+					   pkt_len);
+				rx_copy++;
+			} else{
+				void *temp;
+				/* Pass up the skbuff already on the Rx ring. */
+				skb = vp->rx_skbuff[entry];
+				vp->rx_skbuff[entry] = NULL;
+				temp = skb_put(skb, pkt_len);
+				/* Remove this checking code for final release. */
+				if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
+					printk("%s: Warning -- the skbuff addresses do not match"
+						   " in boomerang_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(vp->rx_ring[entry].addr),
+						   skb->head, temp);
+				rx_nocopy++;
+			}
+#if LINUX_VERSION_CODE > 0x10300
+			skb->protocol = eth_type_trans(skb, dev);
+#else
+			skb->len = pkt_len;
+#endif
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			vp->stats.rx_packets++;
+		}
+		entry = (++vp->cur_rx) % RX_RING_SIZE;
+	}
+	/* Refill the Rx ring buffers. */
+	for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
+		struct sk_buff *skb;
+		entry = vp->dirty_rx % RX_RING_SIZE;
+		if (vp->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[entry].addr = virt_to_bus(skb->tail);
+#else
+			vp->rx_ring[entry].addr = virt_to_bus(skb->data);
+#endif
+			vp->rx_skbuff[entry] = skb;
+		}
+		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
+	}
+	return 0;
+}
+
+static int
+vortex_close(struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (vortex_debug > 1) {
+		printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
+			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
+		printk("%s: vortex close stats: rx_nocopy %d rx_copy %d"
+			   " tx_queued %d.\n",
+			   dev->name, rx_nocopy, rx_copy, queued_packet);
+	}
+
+	del_timer(&vp->timer);
+
+	/* Turn off statistics ASAP.  We update lp->stats below. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+
+	/* Disable the receiver and transmitter. */
+	outw(RxDisable, ioaddr + EL3_CMD);
+	outw(TxDisable, ioaddr + EL3_CMD);
+
+	if (dev->if_port == XCVR_10base2)
+		/* Turn off thinnet power.  Green! */
+		outw(StopCoax, ioaddr + EL3_CMD);
+
+#ifdef SA_SHIRQ
+	free_irq(dev->irq, dev);
+#else
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = 0;
+#endif
+
+	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
+
+	update_stats(ioaddr, dev);
+	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+		outl(0, ioaddr + UpListPtr);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			if (vp->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+				vp->rx_skbuff[i]->free = 1;
+#endif
+				dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE);
+				vp->rx_skbuff[i] = 0;
+			}
+	}
+	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
+		outl(0, ioaddr + DownListPtr);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			if (vp->tx_skbuff[i]) {
+				dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE);
+				vp->tx_skbuff[i] = 0;
+			}
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics *
+vortex_get_stats(struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	unsigned long flags;
+
+	if (dev->start) {
+		save_flags(flags);
+		cli();
+		update_stats(dev->base_addr, dev);
+		restore_flags(flags);
+	}
+	return &vp->stats;
+}
+
+/*  Update statistics.
+	Unlike with the EL3 we need not worry about interrupts changing
+	the window setting from underneath us, but we must still guard
+	against a race condition with a StatsUpdate interrupt updating the
+	table.  This is done by checking that the ASM (!) code generated uses
+	atomic updates with '+='.
+	*/
+static void update_stats(int ioaddr, struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+
+	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
+	/* Switch to the stats window, and read everything. */
+	EL3WINDOW(6);
+	vp->stats.tx_carrier_errors		+= inb(ioaddr + 0);
+	vp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
+	/* Multiple collisions. */		inb(ioaddr + 2);
+	vp->stats.collisions			+= inb(ioaddr + 3);
+	vp->stats.tx_window_errors		+= inb(ioaddr + 4);
+	vp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
+	vp->stats.tx_packets			+= inb(ioaddr + 6);
+	vp->stats.tx_packets			+= (inb(ioaddr + 9)&0x30) << 4;
+	/* Rx packets	*/				inb(ioaddr + 7);   /* Must read to clear */
+	/* Tx deferrals */				inb(ioaddr + 8);
+	/* Don't bother with register 9, an extension of registers 6&7.
+	   If we do use the 6&7 values the atomic update assumption above
+	   is invalid. */
+	inw(ioaddr + 10);	/* Total Rx and Tx octets. */
+	inw(ioaddr + 12);
+	/* New: On the Vortex we must also clear the BadSSD counter. */
+	EL3WINDOW(4);
+	inb(ioaddr + 12);
+
+	/* We change back to window 7 (not 1) with the Vortex. */
+	EL3WINDOW(7);
+	return;
+}
+
+/* This new version of set_rx_mode() supports v1.4 kernels.
+   The Vortex chip has no documented multicast filter, so the only
+   multicast setting is to receive all multicast frames.  At least
+   the chip has a very clean way to set the mode, unlike many others. */
+static void
+set_rx_mode(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	short new_mode;
+
+	if (dev->flags & IFF_PROMISC) {
+		if (vortex_debug > 3)
+			printk("%s: Setting promiscuous mode.\n", dev->name);
+		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
+	} else	if ((dev->mc_list)  ||  (dev->flags & IFF_ALLMULTI)) {
+		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
+	} else
+		new_mode = SetRxFilter | RxStation | RxBroadcast;
+
+	outw(new_mode, ioaddr + EL3_CMD);
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_vortex_dev) {
+		next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module;
+		if (root_vortex_dev->dma)
+		  free_dma(root_vortex_dev->dma);
+		unregister_netdev(root_vortex_dev);
+		outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
+		release_region(root_vortex_dev->base_addr, CORKSCREW_TOTAL_SIZE);
+		kfree(root_vortex_dev);
+		root_vortex_dev = next_dev;
+	}
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c"
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.0.33/linux/drivers/net/3c59x.c	Tue Dec  2 13:52:31 1997
+++ linux/drivers/net/3c59x.c	Wed Jun  3 15:17:47 1998
@@ -1,6 +1,6 @@
 /* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
 /*
-	Written 1996-1997 by Donald Becker.
+	Written 1996-1998 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -15,7 +15,7 @@
 */
 
 static char *version =
-"3c59x.c:v0.46C 10/14/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99E 5/12/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -26,6 +26,17 @@
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
 
+/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
+#ifdef VORTEX_DEBUG
+static int vortex_debug = VORTEX_DEBUG;
+#else
+static int vortex_debug = 1;
+#endif
+
+/* Some values here only for performance evaluation and path-coverage
+   debugging. */
+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
+
 /* Enable the automatic media selection code -- usually set. */
 #define AUTOMEDIA 1
 
@@ -33,7 +44,9 @@
    programmed-I/O for Vortex cards.  Full-bus-master transfers are always
    enabled by default on Boomerang cards.  If VORTEX_BUS_MASTER is defined,
    the feature may be turned on using 'options'. */
+#if YOU_ARE_BRAVER_THAN_ME
 #define VORTEX_BUS_MASTER
+#endif
 
 /* A few values that may be tweaked. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -89,9 +102,15 @@
 #endif
 #define virt_to_bus(addr)  ((unsigned long)addr)
 #define bus_to_virt(addr) ((void*)addr)
+#define NR_IRQS 16
 #else  /* 1.3.0 and later */
 #define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len)
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
+#else  /* Grrr, unneeded incompatible change. */
+#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
 #endif
 
 #ifdef SA_SHIRQ
@@ -111,9 +130,10 @@
 #define udelay(microsec)	do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
 #endif
 
-#if (LINUX_VERSION_CODE < 0x20123)
+#if LINUX_VERSION_CODE < 0x20138
 #define test_and_set_bit(val, addr) set_bit(val, addr)
-#else
+#endif
+#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
 MODULE_PARM(debug, "i");
@@ -121,15 +141,11 @@
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(compaq_ioaddr, "i");
+MODULE_PARM(compaq_irq, "i");
+MODULE_PARM(compaq_prod_id, "i");
 #endif
 
-/* "Knobs" for adjusting internal parameters. */
-/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define VORTEX_DEBUG 1
-/* Some values here only for performance evaluation and path-coverage
-   debugging. */
-static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
-
 /* Operational parameter that usually are not changed. */
 
 /* The Vortex size is twice that of the original EtherLinkIII series: the
@@ -144,20 +160,19 @@
 {"Vortex", vortex_pci_probe, VORTEX_TOTAL_SIZE, NULL};
 #endif
 
-#ifdef VORTEX_DEBUG
-static int vortex_debug = VORTEX_DEBUG;
-#else
-static int vortex_debug = 1;
-#endif
-
-/* Set iff a MII transceiver on any interface requires mdio preamble. */
+/* Set iff a MII transceiver on any interface requires mdio preamble.
+   This only set with the original DP83840 on older 3c905 boards, so the extra
+   code size of a per-interface flag is not worthwhile. */
 static char mii_preamble_required = 0;
 
-/* Caution!  These entries must be consistent, with the EISA ones last. */
+/* Caution!  These entries must be consistent. */
 static const int product_ids[] = {
-	0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0, 0};
+	0x5900, 0x5920, 0x5970, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001,
+	0x9050, 0x9051, 0x9055,	0x5057, 0 };
 static const char *product_names[] = {
 	"3c590 Vortex 10Mbps",
+	"3c592 EISA 10mbps Demon/Vortex",
+	"3c597 EISA Fast Demon/Vortex",
 	"3c595 Vortex 100baseTX",
 	"3c595 Vortex 100baseT4",
 	"3c595 Vortex 100base-MII",
@@ -165,11 +180,9 @@
 	"3c900 Boomerang 10Mbps/Combo",
 	"3c905 Boomerang 100baseTx",
 	"3c905 Boomerang 100baseT4",
-	"3c592 EISA 10mbps Demon/Vortex",
-	"3c597 EISA Fast Demon/Vortex",
+	"3c905B Cyclone 100baseTx",
+	"3c575",						/* Cardbus Boomerang */
 };
-#define DEMON10_INDEX 8
-#define DEMON100_INDEX 9
 
 /*
 				Theory of Operation
@@ -283,7 +296,7 @@
 
 /* Bits in the general status register. */
 enum vortex_status {
-	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+	IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004,
 	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
 	IntReq = 0x0040, StatsFull = 0x0080,
 	DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
@@ -323,7 +336,7 @@
 	struct w3_config_fields {
 		unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
 		int pad8:8;
-		unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
+		unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
 		int pad24:7;
 	} u;
 };
@@ -353,13 +366,15 @@
 struct boom_rx_desc {
 	u32 next;					/* Last entry points to 0.   */
 	s32 status;
-	u32 addr;					/* Up to addr/len possible.. */
-	s32 length;					/* set high bit to indicate last pair. */
+	u32 addr;					/* Up to 63 addr/len pairs possible. */
+	s32 length;					/* Set LAST_FRAG to indicate last pair. */
 };
 /* Values for the Rx status entry. */
 enum rx_desc_status {
 	RxDComplete=0x00008000, RxDError=0x4000,
 	/* See boomerang_rx() for actual error bits */
+	IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
+	IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
 };
 
 struct boom_tx_desc {
@@ -372,9 +387,13 @@
 /* Values for the Tx status entry. */
 enum tx_desc_status {
 	CRCDisable=0x2000, TxDComplete=0x8000,
+	AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
 	TxIntrUploaded=0x80000000,		/* IRQ when in FIFO, but maybe not sent. */
 };
 
+/* Chip features we care about in vp->capabilities, read from the EEPROM. */
+enum ChipCaps { CapBusMaster=0x20 };
+
 struct vortex_private {
 	char devname[8];			/* "ethN" string, also for kernel debug. */
 	const char *product_name;
@@ -389,19 +408,28 @@
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	struct enet_statistics stats;
 	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
+
+	/* PCI configuration space information. */
+	u8 pci_bus, pci_dev_fn;		/* PCI bus location, for power management. */
+	u16 pci_device_id;
+
+	/* The remainder are related to chip state, mostly media selection. */
+	int in_interrupt;
 	struct timer_list timer;	/* Media selection timer. */
 	int options;				/* User-settable misc. driver options. */
-	int last_rx_packets;		/* For media autoselection. */
-	unsigned int available_media:8,	/* From Wn3_Options */
+	unsigned int
 	  media_override:3, 			/* Passed-in media type. */
-	  default_media:3,			/* Read from the EEPROM. */
+	  default_media:3,				/* Read from the EEPROM/Wn3_Config. */
 	  full_duplex:1, autoselect:1,
 	  bus_master:1,				/* Vortex can only do a fragment bus-m. */
 	  full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
+	  hw_csums:1,				/* Has hardware checksums. */
       tx_full:1;
-	u16 capabilities;			/* Adapter capabilities word. */
-	u16 info1, info2;			/* Software information information. */
-	unsigned char phys[2];		/* MII device addresses. */
+	u16 status_enable;
+	u16 available_media;				/* From Wn3_Options. */
+	u16 capabilities, info1, info2;		/* Various, from EEPROM. */
+	u16 advertising;					/* NWay media advertisement */
+	unsigned char phys[2];				/* MII device addresses. */
 };
 
 /* The action to take with a media selection timer tick.
@@ -409,15 +437,15 @@
  */
 enum xcvr_types {
 	XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
-	XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8,
+	XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
 };
 
 static struct media_table {
-  char *name;
-  unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
-	mask:8,				/* The transceiver-present bit in Wn3_Config.*/
-	next:8;				/* The media type to try next. */
-  short wait;			/* Time before we check media status. */
+	char *name;
+	unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
+		mask:8,				/* The transceiver-present bit in Wn3_Config.*/
+		next:8;				/* The media type to try next. */
+	int wait;			/* Time before we check media status. */
 } media_tbl[] = {
   {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
   { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
@@ -425,14 +453,16 @@
   { "10base2",   0,			0x10, XCVR_AUI,		(1*HZ)/10},
   { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
   { "100baseFX", Media_Lnk, 0x04, XCVR_MII,		(14*HZ)/10},
-  { "MII",		 0,			0x40, XCVR_10baseT, 3*HZ },
+  { "MII",		 0,			0x41, XCVR_10baseT, 3*HZ },
   { "undefined", 0,			0x01, XCVR_10baseT, 10000},
+  { "Autonegotiate", 0,		0x41, XCVR_10baseT, 3*HZ},
+  { "MII-External",	 0,		0x41, XCVR_10baseT, 3*HZ },
   { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
 };
 
 static int vortex_scan(struct device *dev);
 static struct device *vortex_found_device(struct device *dev, int ioaddr,
-										  int irq, int product_index,
+										  int irq, int device_id,
 										  int options, int card_idx);
 static int vortex_probe1(struct device *dev);
 static int vortex_open(struct device *dev);
@@ -480,25 +510,90 @@
 /* A list of all installed Vortex devices, for removing the driver module. */
 static struct device *root_vortex_dev = NULL;
 
+#ifdef MODULE
 /* Variables to work-around the Compaq PCI BIOS32 problem. */
-static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0;
+static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
 
-#ifdef MODULE
 static int debug = -1;
 
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *vortex_attach(dev_locator_t *loc)
+{
+	u16 dev_id;
+	u32 io;
+	u8 bus, devfn, irq;
+	struct device *dev;
+
+	if (loc->bus != LOC_PCI) return NULL;
+	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+	printk(KERN_INFO "vortex_attach(bus %d, function %d)\n", bus, devfn);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+	io &= ~3;
+	dev = vortex_found_device(NULL, io, irq, dev_id, 0, -1);
+	if (dev) {
+		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+		strcpy(node->dev_name, dev->name);
+		node->major = node->minor = 0;
+		node->next = NULL;
+		MOD_INC_USE_COUNT;
+		return node;
+	}
+	return NULL;
+}
+
+static void vortex_detach(dev_node_t *node)
+{
+	struct device **devp, **next;
+	printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
+	for (devp = &root_vortex_dev; *devp; devp = next) {
+		next = &((struct vortex_private *)(*devp)->priv)->next_module;
+		if (strcmp((*devp)->name, node->dev_name) == 0) break;
+	}
+	if (*devp) {
+		struct device *dev = *devp;
+		if (dev->flags & IFF_UP)
+			vortex_close(dev);
+		dev->flags &= ~(IFF_UP|IFF_RUNNING);
+		unregister_netdev(dev);
+		kfree(dev);
+		*devp = *next;
+		kfree(node);
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+struct driver_operations vortex_ops = {
+	"3c59x_cb", vortex_attach, NULL, NULL, vortex_detach
+};
+
+#endif  /* Cardbus support */
+
+
 int
 init_module(void)
 {
-	int cards_found;
-
 	if (debug >= 0)
 		vortex_debug = debug;
 	if (vortex_debug)
 		printk(version);
 
 	root_vortex_dev = NULL;
-	cards_found = vortex_scan(0);
-	return cards_found ? 0 : -ENODEV;
+#ifdef CARDBUS
+	register_driver(&vortex_ops);
+	return 0;
+#else
+	{
+		int cards_found = vortex_scan(0);
+		if (cards_found == 0)
+			printk("No 3Com Vortex/Boomerang cards found.\n");
+		return cards_found ? 0 : -ENODEV;
+	}
+#endif
 }
 
 #else
@@ -519,7 +614,8 @@
 {
 	int cards_found = 0;
 
-#ifndef NO_PCI					/* Allow an EISA-only driver. */
+	/* Allow an EISA-only driver. */
+#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
 	/* Ideally we would detect all cards in slot order.  That would
 	   be best done a central PCI probe dispatch, which wouldn't work
 	   well with the current structure.  So instead we detect 3Com cards
@@ -529,11 +625,11 @@
 		unsigned char pci_bus, pci_device_fn;
 
 		for (;pci_index < 0xff; pci_index++) {
-			unsigned char pci_irq_line, pci_latency;
-			unsigned short pci_command, vendor, device;
-			unsigned int pci_ioaddr;
+			u8 pci_latency;
+			u16 pci_command, new_command, vendor, device;
+			int irq;
+			long ioaddr;
 
-			int board_index = 0;
 			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
 									pci_index, &pci_bus, &pci_device_fn)
 				!= PCIBIOS_SUCCESSFUL)
@@ -542,56 +638,75 @@
 									 PCI_VENDOR_ID, &vendor);
 			pcibios_read_config_word(pci_bus, pci_device_fn,
 									 PCI_DEVICE_ID, &device);
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_INTERRUPT_LINE, &pci_irq_line);
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			{
+#if LINUX_VERSION_CODE >= 0x20155
+				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+				ioaddr = pdev->base_address[0];
+				irq = pdev->irq;
+#else
+				u32 pci_ioaddr;
+				u8 pci_irq_line;
+				pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_INTERRUPT_LINE, &pci_irq_line);
+				pcibios_read_config_dword(pci_bus, pci_device_fn,
+										  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+				ioaddr = pci_ioaddr;
+				irq = pci_irq_line;
+#endif
+			}
 			/* Remove I/O space marker in bit 0. */
-			pci_ioaddr &= ~3;
+			ioaddr &= ~3;
 
 			if (vendor != TCOM_VENDOR_ID)
 				continue;
 
-			for (board_index = 0; product_ids[board_index]; board_index++) {
-				if (device == product_ids[board_index])
-					break;
-			}
-			if (product_ids[board_index] == 0) {
-				printk("Unknown 3Com PCI ethernet adapter type %4.4x detected:"
-					   " not configured.\n", device);
+			if (ioaddr == 0) {
+				printk(KERN_WARNING "  A 3Com network adapter has been found, "
+					   "however it has not been assigned an I/O address.\n"
+					   "  You may need to power-cycle the machine for this "
+					   "device to work!\n");
 				continue;
 			}
-			if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE))
+
+			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
 				continue;
 
-			dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line,
-									  board_index, dev && dev->mem_start
+			/* Activate the card. */
+			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+			if (pci_command != new_command) {
+				printk(KERN_INFO "  The PCI BIOS has not enabled this"
+					   " device!  Updating PCI command %4.4x->%4.4x.\n",
+					   pci_command, new_command);
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, new_command);
+			}
+
+			dev = vortex_found_device(dev, ioaddr, irq,
+									  device, dev && dev->mem_start
 									  ? dev->mem_start : options[cards_found],
 									  cards_found);
 
 			if (dev) {
-				/* Get and check the bus-master and latency values.
-				   Some PCI BIOSes fail to set the master-enable bit, and
+				struct vortex_private *vp = (struct vortex_private *)dev->priv;
+				/* Get and check the latency values.  On the 3c590 series
 				   the latency timer must be set to the maximum value to avoid
 				   data corruption that occurs when the timer expires during
-				   a transfer -- a bug in the Vortex chip. */
-				pcibios_read_config_word(pci_bus, pci_device_fn,
-										 PCI_COMMAND, &pci_command);
-				if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-					printk("%s:  PCI Master Bit has not been set! "
-						   " Setting...\n", dev->name);
-					pci_command |= PCI_COMMAND_MASTER;
-					pcibios_write_config_word(pci_bus, pci_device_fn,
-											  PCI_COMMAND, pci_command);
-				}
+				   a transfer -- a bug in the Vortex chip only. */
+				u8 new_latency = (device&0xff00) == 0x5900 ? 248 : 32;
+				vp->pci_bus = pci_bus;
+				vp->pci_dev_fn = pci_device_fn;
+				vp->pci_device_id = device;
+				
 				pcibios_read_config_byte(pci_bus, pci_device_fn,
 										 PCI_LATENCY_TIMER, &pci_latency);
-				if (pci_latency != 248) {
-					printk("%s: Overriding PCI latency"
-						   " timer (CFLT) setting of %d, new value is 248.\n",
-						   dev->name, pci_latency);
+				if (pci_latency < new_latency) {
+					printk(KERN_INFO "%s: Overriding PCI latency"
+						   " timer (CFLT) setting of %d, new value is %d.\n",
+						   dev->name, pci_latency, new_latency);
 					pcibios_write_config_byte(pci_bus, pci_device_fn,
-											  PCI_LATENCY_TIMER, 248);
+											  PCI_LATENCY_TIMER, new_latency);
 				}
 				dev = 0;
 				cards_found++;
@@ -603,23 +718,19 @@
 	/* Now check all slots of the EISA bus. */
 	if (EISA_bus) {
 		static int ioaddr = 0x1000;
-		for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-			int product_id, product_index;
+		for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
+			int device_id;
 			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
 				continue;
 			/* Check the standard EISA ID register for an encoded '3Com'. */
 			if (inw(ioaddr + 0xC80) != 0x6d50)
 				continue;
 			/* Check for a product that we support, 3c59{2,7} any rev. */
-			product_id = inw(ioaddr + 0xC82) & 0xF0FF;
-			if (product_id == 0x7059) 		/* 597 */
-				product_index = DEMON100_INDEX;
-			else if (product_id == 0x2059)	/* 592 */
-				product_index = DEMON10_INDEX;
-			else
+			device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
+			if ((device_id & 0xFF00) != 0x5900)
 				continue;
 			vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
-								product_index,  dev && dev->mem_start
+								device_id,  dev && dev->mem_start
 								? dev->mem_start : options[cards_found],
 								cards_found);
 			dev = 0;
@@ -627,34 +738,58 @@
 		}
 	}
 
+#ifdef MODULE
 	/* Special code to work-around the Compaq PCI BIOS32 problem. */
 	if (compaq_ioaddr) {
-		vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_prod_id,
+		vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_device_id,
 							dev && dev->mem_start ? dev->mem_start
 							: options[cards_found], cards_found);
 		cards_found++;
 		dev = 0;
 	}
+#endif
 
-	/* Finally check for a 3c515 on the ISA bus. */
-	/* (3c515 support omitted on this version.) */
+	/* 3c515 cards are now supported by the 3c515.c driver. */
 
 	return cards_found;
 }
 
 static struct device *
 vortex_found_device(struct device *dev, int ioaddr, int irq,
-					int product_index, int options, int card_idx)
+					int device_id, int option, int card_idx)
 {
 	struct vortex_private *vp;
+	const char *product_name;
+	int board_index = 0;
+
+	for (board_index = 0; product_ids[board_index]; board_index++) {
+		if (device_id == product_ids[board_index])
+			break;
+	}
+	/* Handle products we don't recognize, but might still work with. */
+	if (product_ids[board_index])
+		product_name = product_names[board_index];
+	else if ((device_id & 0xff00) == 0x5900)
+		product_name = "3c590 Vortex";
+	else if ((device_id & 0xfff0) == 0x9000)
+		product_name = "3c900";
+	else if ((device_id & 0xfff0) == 0x9050)
+		product_name = "3c905";
+	else {
+		printk(KERN_WARNING "Unknown 3Com PCI ethernet adapter type %4.4x detected:"
+			   " not configured.\n", device_id);
+		return 0;
+	}
 
 #ifdef MODULE
 	/* Allocate and fill new device structure. */
-	int dev_size = sizeof(struct device) +
-		sizeof(struct vortex_private) + 15;		/* Pad for alignment */
+	{
+		int dev_size = sizeof(struct device) +
+			sizeof(struct vortex_private) + 15;		/* Pad for alignment */
 
-	dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
-	memset(dev, 0, dev_size);
+		dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
+		memset(dev, 0, dev_size);
+	}
 	/* Align the Rx and Tx ring entries.  */
 	dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
 	vp = (struct vortex_private *)dev->priv;
@@ -662,18 +797,18 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->init = vortex_probe1;
-	vp->product_name = product_names[product_index];
-	vp->options = options;
+	vp->product_name = product_name;
+	vp->options = option;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
 			vp->full_duplex = full_duplex[card_idx];
 	} else
-		vp->full_duplex = (options >= 0 && (options & 0x10) ? 1 : 0);
+		vp->full_duplex = (option > 0 && (option & 0x10) ? 1 : 0);
 
-	if (options >= 0) {
-		vp->media_override = ((options & 7) == XCVR_10baseTOnly) ?
-			XCVR_10baseT  :  options & 7;
-		vp->bus_master = (options & 16) ? 1 : 0;
+	if (option > 0) {
+		vp->media_override = ((option & 7) == XCVR_10baseTOnly) ?
+			XCVR_10baseT  :  option & 7;
+		vp->bus_master = (option & 16) ? 1 : 0;
 	} else {
 		vp->media_override = 7;
 		vp->bus_master = 0;
@@ -695,12 +830,12 @@
 	dev->mtu = mtu;
 
 	vp  = (struct vortex_private *)dev->priv;
-	vp->product_name = product_names[product_index];
-	vp->options = options;
-	if (options >= 0) {
-		vp->media_override = ((options & 7) == 2)  ?  0  :  options & 7;
-		vp->full_duplex = (options & 8) ? 1 : 0;
-		vp->bus_master = (options & 16) ? 1 : 0;
+	vp->product_name = product_name;
+	vp->options = option;
+	if (option >= 0) {
+		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 7;
+		vp->full_duplex = (option & 8) ? 1 : 0;
+		vp->bus_master = (option & 16) ? 1 : 0;
 	} else {
 		vp->media_override = 7;
 		vp->full_duplex = 0;
@@ -716,63 +851,87 @@
 {
 	int ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	u16 *ether_addr = (u16 *)dev->dev_addr;
 	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
 	int i;
 
-	printk("%s: 3Com %s at %#3x,", dev->name,
-		   vp->product_name, ioaddr);
+	printk(KERN_INFO "%s: 3Com %s at %#3x,",
+		   dev->name, vp->product_name, ioaddr);
 
 	/* Read the station address from the EEPROM. */
 	EL3WINDOW(0);
-	for (i = 0; i < 0x18; i++) {
-		u16 *phys_addr = (u16 *)dev->dev_addr;
+	for (i = 0; i < 0x40; i++) {
 		int timer;
+#ifdef CARDBUS
+		outw(0x230 + i, ioaddr + Wn0EepromCmd);
+#else
 		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
+#endif
 		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 4; timer >= 0; timer--) {
+		for (timer = 10; timer >= 0; timer--) {
 			udelay(162);
 			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
 				break;
 		}
 		eeprom[i] = inw(ioaddr + Wn0EepromData);
-		checksum ^= eeprom[i];
-		if (i >= 10 && i < 13)
-			phys_addr[i - 10] = htons(inw(ioaddr + Wn0EepromData));
 	}
+	for (i = 0; i < 0x18; i++)
+		checksum ^= eeprom[i];
 	checksum = (checksum ^ (checksum >> 8)) & 0xff;
+	if (checksum != 0x00) {		/* Grrr, needless incompatible change 3Com. */
+		while (i < 0x21)
+			checksum ^= eeprom[i++];
+		checksum = (checksum ^ (checksum >> 8)) & 0xff;
+	}
 	if (checksum != 0x00)
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
+
+	for (i = 0; i < 3; i++)
+		ether_addr[i] = htons(eeprom[i + 10]);
 	for (i = 0; i < 6; i++)
 		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
 	printk(", IRQ %d\n", dev->irq);
 	/* Tell them about an invalid IRQ. */
 	if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
-		printk(" *** Warning: this IRQ is unlikely to work! ***\n");
+		printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
+			   dev->irq);
+
+	/* Extract our information from the EEPROM data. */
+	vp->info1 = eeprom[13];
+	vp->info2 = eeprom[15];
+	vp->capabilities = eeprom[16];
+
+	if (vp->info1 & 0x8000)
+		vp->full_duplex = 1;
 
 	{
 		char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 		union wn3_config config;
 		EL3WINDOW(3);
 		vp->available_media = inw(ioaddr + Wn3_Options);
+		if ((vp->available_media & 0xff) == 0)		/* Broken 3c916 */
+			vp->available_media = 0x40;
 		config.i = inl(ioaddr + Wn3_Config);
 		if (vortex_debug > 1)
-			printk("  Internal config register is %4.4x, transceivers %#x.\n",
-				   config.i, inw(ioaddr + Wn3_Options));
-		printk("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+			printk(KERN_DEBUG "  Internal config register is %4.4x, "
+				   "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options));
+		printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
 			   8 << config.u.ram_size,
 			   config.u.ram_width ? "word" : "byte",
 			   ram_split[config.u.ram_split],
 			   config.u.autoselect ? "autoselect/" : "",
+			   config.u.xcvr ? "NWay Autonegotiation" :
 			   media_tbl[config.u.xcvr].name);
-		dev->if_port = config.u.xcvr;
 		vp->default_media = config.u.xcvr;
 		vp->autoselect = config.u.autoselect;
 	}
+
 	if (vp->media_override != 7) {
-		printk("  Media override to transceiver type %d (%s).\n",
+		printk(KERN_INFO "  Media override to transceiver type %d (%s).\n",
 			   vp->media_override, media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
-	}
+	} else
+		dev->if_port = vp->default_media;
 
 	if (dev->if_port == XCVR_MII) {
 		int phy, phy_idx = 0;
@@ -780,31 +939,34 @@
 		for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) {
 			int mii_status;
 			mdio_sync(ioaddr, 32);
-			mii_status = mdio_read(ioaddr, phy, 0);
-			if (mii_status != 0xffff) {
+			mii_status = mdio_read(ioaddr, phy, 1);
+			if (mii_status  &&  mii_status != 0xffff) {
 				vp->phys[phy_idx++] = phy;
-				printk("%s: MII transceiver found at address %d.\n",
-					   dev->name, phy);
+				printk(KERN_INFO "  MII transceiver found at address %d, status %4x.\n",
+					   phy, mii_status);
 				mdio_sync(ioaddr, 32);
 				if ((mdio_read(ioaddr, phy, 1) & 0x0040) == 0)
 					mii_preamble_required = 1;
 			}
 		}
 		if (phy_idx == 0) {
-			printk("%s: ***WARNING*** No MII transceivers found!\n",
-				   dev->name);
-			vp->phys[0] = 0;
+			printk(KERN_WARNING"  ***WARNING*** No MII transceivers found!\n");
+			vp->phys[0] = 24;
+		} else {
+			vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
+			if (vp->full_duplex) {
+				/* Only advertise the FD media types. */
+				vp->advertising &= 0x015F;
+				mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
+			}
 		}
 	}
 
-	vp->info1 = eeprom[13];
-	vp->info2 = eeprom[15];
-	vp->capabilities = eeprom[16];
-	if (vp->capabilities & 0x20) {
-	  vp->full_bus_master_tx = 1;
-	  printk("  Enabling bus-master transmits and %s receives.\n",
-			 (vp->info2 & 1) ? "early" : "whole-frame" );
-	  vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
+	if (vp->capabilities & CapBusMaster) {
+		vp->full_bus_master_tx = 1;
+		printk(KERN_INFO"  Enabling bus-master transmits and %s receives.\n",
+			   (vp->info2 & 1) ? "early" : "whole-frame" );
+		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
 	}
 
 	/* We do a request_region() to register /proc/ioports info. */
@@ -826,86 +988,6 @@
 
 	return 0;
 }
-
-/* Read and write the MII registers using software-generated serial
-   MDIO protocol.  The maxium data clock rate is 2.5 Mhz. */
-#define mdio_delay() udelay(1)
-
-#define MDIO_SHIFT_CLK	0x01
-#define MDIO_DIR_WRITE	0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ	0x02
-#define MDIO_ENB_IN		0x00
-
-static void mdio_sync(int ioaddr, int bits)
-{
-	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
-	/* Establish sync by sending at least 32 logic ones. */ 
-	while (-- bits >= 0) {
-		outw(MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-}
-static int mdio_read(int ioaddr, int phy_id, int location)
-{
-	int i;
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	unsigned int retval = 0;
-	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
-	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
-
-	/* Shift the read command bits out. */
-	for (i = 14; i >= 0; i--) {
-		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		outw(dataval, mdio_addr);
-		mdio_delay();
-		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outw(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return retval>>1 & 0xffff;
-}
-
-static void mdio_write(int ioaddr, int phy_id, int location, int value)
-{
-	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
-	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-	int i;
-
-	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
-
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		outw(dataval, mdio_addr);
-		mdio_delay();
-		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Leave the interface idle. */
-	for (i = 1; i >= 0; i--) {
-		outw(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-
-	return;
-}
 
 
 static int
@@ -922,7 +1004,7 @@
 
 	if (vp->media_override != 7) {
 		if (vortex_debug > 1)
-			printk("%s: Media override to transceiver %d (%s).\n",
+			printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
 				   dev->name, vp->media_override,
 				   media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
@@ -933,7 +1015,7 @@
 			dev->if_port = media_tbl[dev->if_port].next;
 
 		if (vortex_debug > 1)
-			printk("%s: Initial media type %s.\n",
+			printk(KERN_DEBUG "%s: Initial media type %s.\n",
 				   dev->name, media_tbl[dev->if_port].name);
 
 		init_timer(&vp->timer);
@@ -949,8 +1031,6 @@
 
 	if (dev->if_port == XCVR_MII) {
 		int mii_reg1, mii_reg5;
-		/* We cheat here: we know that we are using the 83840 transceiver
-		   which summarizes the FD status in an extended register. */
 		EL3WINDOW(4);
 		/* Read BMSR (reg1) only to clear old status. */
 		mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
@@ -961,7 +1041,7 @@
 				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
 			vp->full_duplex = 1;
 		if (vortex_debug > 1)
-			printk("%s: MII #%d status %4.4x, link partner capability %4.4x,"
+			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
 				   " setting %s-duplex.\n", dev->name, vp->phys[0],
 				   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
 		EL3WINDOW(3);
@@ -972,18 +1052,18 @@
 		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
 
 	if (vortex_debug > 1) {
-		printk("%s: vortex_open() InternalConfig %8.8x.\n",
+		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
 			dev->name, config.i);
 	}
 
 	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 20; i >= 0 ; i--)
+	for (i = 2000; i >= 0 ; i--)
 		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 			break;
 
 	outw(RxReset, ioaddr + EL3_CMD);
 	/* Wait a few ticks for the RxReset command to complete. */
-	for (i = 20; i >= 0 ; i--)
+	for (i = 2000; i >= 0 ; i--)
 		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 			break;
 
@@ -991,8 +1071,7 @@
 
 #ifdef SA_SHIRQ
 	/* Use the now-standard shared IRQ implementation. */
-	if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
-					vp->product_name, dev)) {
+	if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
 		return -EAGAIN;
 	}
 #else
@@ -1007,7 +1086,7 @@
 
 	if (vortex_debug > 1) {
 		EL3WINDOW(4);
-		printk("%s: vortex_open() irq %d media status %4.4x.\n",
+		printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
 			   dev->name, dev->irq, inw(ioaddr + Wn4_Media));
 	}
 
@@ -1047,19 +1126,23 @@
 		outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
 		outl(0x0020, ioaddr + PktStatus);
 		if (vortex_debug > 2)
-			printk("%s:  Filling in the Rx ring.\n", dev->name);
+			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			struct sk_buff *skb;
 			vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
 			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
 			vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG;
-			skb = dev_alloc_skb(PKT_BUF_SZ);
+			skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
 			vp->rx_skbuff[i] = skb;
 			if (skb == NULL)
 				break;			/* Bad news!  */
 			skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE >= 0x10300
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			vp->rx_ring[i].addr = virt_to_bus(skb->tail);
+#else
+			vp->rx_ring[i].addr = virt_to_bus(skb->data);
+#endif
 		}
 		vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
 		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
@@ -1077,6 +1160,7 @@
 	set_rx_mode(dev);
 	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
+	vp->in_interrupt = 0;
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
@@ -1084,16 +1168,16 @@
 	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
 	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
 	/* Allow status bits to be seen. */
-	outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull|TxComplete|
-		 (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
-		 (vp->full_bus_master_rx ? UpComplete : RxComplete) |
-		 (vp->bus_master ? DMADone : 0),
-		 ioaddr + EL3_CMD);
+	vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
+		(vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+		(vp->full_bus_master_rx ? UpComplete : RxComplete) |
+		(vp->bus_master ? DMADone : 0);
+	outw(vp->status_enable, ioaddr + EL3_CMD);
 	/* Ack all pending events, and set active indicator mask. */
 	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
 		 ioaddr + EL3_CMD);
 	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
-		 | AdapterFailure | TxComplete
+		 | HostError | TxComplete
 		 | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
 			ioaddr + EL3_CMD);
 
@@ -1112,7 +1196,7 @@
 	int ok = 0;
 
 	if (vortex_debug > 1)
-		printk("%s: Media selection timer tick happened, %s.\n",
+		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
 			   dev->name, media_tbl[dev->if_port].name);
 
 	save_flags(flags);	cli(); {
@@ -1125,10 +1209,10 @@
 		if (media_status & Media_LnkBeat) {
 		  ok = 1;
 		  if (vortex_debug > 1)
-			printk("%s: Media %s has link beat, %x.\n",
+			printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
 		} else if (vortex_debug > 1)
-		  printk("%s: Media %s is has no link beat, %x.\n",
+		  printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
 
 		break;
@@ -1137,7 +1221,7 @@
 			  int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
 			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
 			  if (vortex_debug > 1)
-				  printk("%s: MII #%d status register is %4.4x, "
+				  printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, "
 						 "link partner capability %4.4x.\n",
 						 dev->name, vp->phys[0], mii_reg1, mii_reg5);
 			  if (mii_reg1 & 0x0004)
@@ -1146,7 +1230,7 @@
 		  }
 	  default:					/* Other media types handled by Tx timeouts. */
 		if (vortex_debug > 1)
-		  printk("%s: Media %s is has no indication, %x.\n",
+		  printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
 				 dev->name, media_tbl[dev->if_port].name, media_status);
 		ok = 1;
 	  }
@@ -1159,11 +1243,13 @@
 		if (dev->if_port == XCVR_Default) { /* Go back to default. */
 		  dev->if_port = vp->default_media;
 		  if (vortex_debug > 1)
-			printk("%s: Media selection failing, using default %s port.\n",
+			printk(KERN_DEBUG "%s: Media selection failing, using default "
+				   "%s port.\n",
 				   dev->name, media_tbl[dev->if_port].name);
 		} else {
 		  if (vortex_debug > 1)
-			printk("%s: Media selection failed, now trying %s port.\n",
+			printk(KERN_DEBUG "%s: Media selection failed, now trying "
+				   "%s port.\n",
 				   dev->name, media_tbl[dev->if_port].name);
 		  vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
 		  add_timer(&vp->timer);
@@ -1182,7 +1268,7 @@
 	  EL3WINDOW(old_window);
 	}   restore_flags(flags);
 	if (vortex_debug > 1)
-	  printk("%s: Media selection timer finished, %s.\n",
+	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
 #endif /* AUTOMEDIA*/
@@ -1193,84 +1279,59 @@
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	int ioaddr = dev->base_addr;
-	int i;
+	int j;
 
-	printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 		   dev->name, inb(ioaddr + TxStatus),
 		   inw(ioaddr + EL3_STATUS));
 	/* Slight code bloat to be user friendly. */
 	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
-		printk("%s: Transmitter encountered 16 collisions --"
+		printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
 			   " network cable problem?\n", dev->name);
 	if (inw(ioaddr + EL3_STATUS) & IntLatch) {
-		printk("%s: Interrupt posted but not handled --"
+		printk(KERN_ERR "%s: Interrupt posted but not delivered --"
 			   " IRQ blocked by another device?\n", dev->name);
 		/* Bad idea here.. but we might as well handle a few events. */
 		vortex_interrupt IRQ(dev->irq, dev, 0);
 	}
-#ifndef final_version
+	outw(TxReset, ioaddr + EL3_CMD);
+	for (j = 200; j >= 0 ; j--)
+		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+			break;
+
+#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300
 	if (vp->full_bus_master_tx) {
-		printk("  Flags; bus-master %d, full %d; dirty %d current %d.\n",
+		int i;
+		printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
+			   "current %d.\n",
 			   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
-		printk("  Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+		printk(KERN_DEBUG "  Transmit list %8.8x vs. %p.\n",
+			   inl(ioaddr + DownListPtr),
 			   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
 		for (i = 0; i < TX_RING_SIZE; i++) {
-			printk("  %d: @%p  length %8.8x status %8.8x\n", i,
+			printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
 				   &vp->tx_ring[i],
 				   vp->tx_ring[i].length,
 				   vp->tx_ring[i].status);
 		}
 	}
-#ifdef notdef
-	if (vp->full_bus_master_rx) {
-		printk("  Switching to non-bus-master receives.\n");
-		outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull |
-			 (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
-			 RxComplete | (vp->bus_master ? DMADone : 0),
-			 ioaddr + EL3_CMD);
-	}
-	/* Issue TX_RESET and TX_START commands. */
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 20; i >= 0 ; i--)
-	  if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-		break;
-#endif
 #endif
+	vp->stats.tx_errors++;
 	if (vp->full_bus_master_tx) {
-	  /*  Change 6/25/97 Michael Sievers sieversm@mail.desy.de
-              The card has been resetted, but the Tx Ring is still full.
-		 Since the card won't know where to resume, 'update' the
-		 Tx Ring. Probably, we'll lose 16 packets this way, these
-		 will be accounted for as 'dropped'. The code to update the
-		 Tx Ring is taken from the Interrupt handler. */
-   
-	  unsigned int dirty_tx = vp->dirty_tx;
-	  
-	  if (vortex_debug > 0)
-		  printk("%s: Freeing Tx ring entries:", dev->name);
-	  while (vp->cur_tx - dirty_tx > 0) {
-		int entry = dirty_tx % TX_RING_SIZE;
-		if (inl(ioaddr + DownListPtr) ==
-			virt_to_bus(&vp->tx_ring[entry]))
-		  break;			/* It still hasn't been processed. */
-		if (vp->tx_skbuff[entry]) {
-			if (vortex_debug > 0)
-				printk(" %d\n", entry);
-			dev_kfree_skb(vp->tx_skbuff[entry], FREE_WRITE);
-			vp->tx_skbuff[entry] = 0;
-			vp->stats.tx_dropped++;
-		}
 		if (vortex_debug > 0)
-			printk(".\n");
-		vp->stats.tx_errors++;
-		dirty_tx++;
-	  }
-	  vp->dirty_tx = dirty_tx;
-	  vp->tx_full= 0;
-	} else {     /* not bus-master, no Tx ring to clear */
-	  vp->stats.tx_errors++;
-	  vp->stats.tx_dropped++;
-	}
+			printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n",
+				   dev->name);
+		if (vp->cur_tx - vp->dirty_tx > 0  &&  inl(ioaddr + DownListPtr) == 0)
+			outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]),
+				 ioaddr + DownListPtr);
+		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
+			vp->tx_full = 0;
+			clear_bit(0, (void*)&dev->tbusy);
+		}
+		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
+		outw(DownUnstall, ioaddr + EL3_CMD);
+	} else
+		vp->stats.tx_dropped++;
 	
 	/* Issue Tx Enable */
 	outw(TxEnable, ioaddr + EL3_CMD);
@@ -1278,35 +1339,105 @@
 	
 	/* Switch to register set 7 for normal use. */
 	EL3WINDOW(7);
-	
-	/* The TxFreeThreshold has to be set again after a reset! */
-	if (vp->full_bus_master_tx) {  
-	  outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
-	  /* This is to be sure that all bus-master Tx features
-		 are correctly re-initialized after a reset, although
-		 the DownListPtr should already be 0 at this point. */
-	  outl(0, ioaddr + DownListPtr);
+}
+
+/*
+ * Handle uncommon interrupt sources.  This is a seperate routine to minimize
+ * the cache impact.
+ */
+static void
+vortex_error(struct device *dev, int status)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int do_tx_reset = 0;
+	int i;
+
+	if (status & TxComplete) {			/* Really "TxError" for us. */
+		unsigned char tx_status = inb(ioaddr + TxStatus);
+		/* Presumably a tx-timeout. We must merely re-enable. */
+		if (vortex_debug > 2
+			|| (tx_status != 0x88 && vortex_debug > 0))
+			printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
+				   dev->name, tx_status);
+		if (tx_status & 0x14)  vp->stats.tx_fifo_errors++;
+		if (tx_status & 0x38)  vp->stats.tx_aborted_errors++;
+		outb(0, ioaddr + TxStatus);
+		if (tx_status & 0x30)
+			do_tx_reset = 1;
+		else					/* Merely re-enable the transmitter. */
+			outw(TxEnable, ioaddr + EL3_CMD);
 	}
-	/* finally, allow new Transmits */
-	dev->tbusy = 0;
-	/* End of Michael Sievers <sieversm@mail.desy.de> changes. */
+	if (status & RxEarly) {				/* Rx early is unused. */
+		vortex_rx(dev);
+		outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+	}
+	if (status & StatsFull) {			/* Empty statistics. */
+		static int DoneDidThat = 0;
+		if (vortex_debug > 4)
+			printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);
+		update_stats(ioaddr, dev);
+		/* HACK: Disable statistics as an interrupt source. */
+		/* This occurs when we have the wrong media type! */
+		if (DoneDidThat == 0  &&
+			inw(ioaddr + EL3_STATUS) & StatsFull) {
+			printk(KERN_WARNING "%s: Updating statistics failed, disabling "
+				   "stats as an interrupt source.\n", dev->name);
+			EL3WINDOW(5);
+			outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
+			EL3WINDOW(7);
+			DoneDidThat++;
+		}
+	}
+	if (status & IntReq)		/* Restore all interrupt sources.  */
+		outw(ioaddr + EL3_CMD, vp->status_enable);
+	if (status & HostError) {
+		u16 fifo_diag;
+		EL3WINDOW(4);
+		fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+		if (vortex_debug > 0)
+			printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
+				   dev->name, fifo_diag);
+		/* Adapter failure requires Tx/Rx reset and reinit. */
+		if (vp->full_bus_master_tx) {
+			outw(TotalReset | 0xff, ioaddr + EL3_CMD);
+			for (i = 2000; i >= 0 ; i--)
+				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+					break;
+			/* Re-enable the receiver. */
+			outw(RxEnable, ioaddr + EL3_CMD);
+			outw(TxEnable, ioaddr + EL3_CMD);
+		} else if (fifo_diag & 0x0400)
+			do_tx_reset = 1;
+		if (fifo_diag & 0x3000) {
+			outw(RxReset, ioaddr + EL3_CMD);
+			for (i = 2000; i >= 0 ; i--)
+				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+					break;
+			/* Set the Rx filter to the current state. */
+			set_rx_mode(dev);
+			outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+			outw(AckIntr | HostError, ioaddr + EL3_CMD);
+		}
+	}
+	if (do_tx_reset) {
+		int j;
+		outw(TxReset, ioaddr + EL3_CMD);
+		for (j = 200; j >= 0 ; j--)
+			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+				break;
+		outw(TxEnable, ioaddr + EL3_CMD);
+	}
+
 }
 
+
 static int
 vortex_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	int ioaddr = dev->base_addr;
 
-#ifndef final_version
-	if (skb == NULL || skb->len <= 0) {
-		printk("%s: Obsolete driver layer request made: skbuff==NULL.\n",
-			   dev->name);
-		dev_tint(dev);
-		return 0;
-	}
-#endif
-
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		if (jiffies - dev->trans_start >= TX_TIMEOUT)
 			vortex_tx_timeout(dev);
@@ -1318,7 +1449,7 @@
 #ifdef VORTEX_BUS_MASTER
 	if (vp->bus_master) {
 		/* Set the bus-master controller to transfer the packet. */
-		outl((int)(skb->data), ioaddr + Wn7_MasterAddr);
+		outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr);
 		outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
 		vp->tx_skb = skb;
 		outw(StartDMADown, ioaddr + EL3_CMD);
@@ -1326,9 +1457,9 @@
 	} else {
 		/* ... and the packet rounded to a doubleword. */
 		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-		dev_kfree_skb (skb, FREE_WRITE);
+		DEV_FREE_SKB(skb);
 		if (inw(ioaddr + TxFree) > 1536) {
-			dev->tbusy = 0;
+			clear_bit(0, (void*)&dev->tbusy);
 		} else
 			/* Interrupt us when the FIFO has room for max-sized packet. */
 			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1336,9 +1467,9 @@
 #else
 	/* ... and the packet rounded to a doubleword. */
 	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-	dev_kfree_skb (skb, FREE_WRITE);
+	DEV_FREE_SKB(skb);
 	if (inw(ioaddr + TxFree) > 1536) {
-		dev->tbusy = 0;
+		clear_bit(0, (void*)&dev->tbusy);
 	} else
 		/* Interrupt us when the FIFO has room for max-sized packet. */
 		outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1348,20 +1479,20 @@
 
 	/* Clear the Tx status stack. */
 	{
-		short tx_status;
-		int i = 4;
+		int tx_status;
+		int i = 32;
 
 		while (--i > 0	&&	(tx_status = inb(ioaddr + TxStatus)) > 0) {
 			if (tx_status & 0x3C) {		/* A Tx-disabling error occurred.  */
 				if (vortex_debug > 2)
-				  printk("%s: Tx error, status %2.2x.\n",
+				  printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n",
 						 dev->name, tx_status);
 				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
 				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
 				if (tx_status & 0x30) {
 					int j;
 					outw(TxReset, ioaddr + EL3_CMD);
-					for (j = 20; j >= 0 ; j--)
+					for (j = 200; j >= 0 ; j--)
 						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 							break;
 				}
@@ -1379,15 +1510,6 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	int ioaddr = dev->base_addr;
 
-#ifndef final_version
-	if (skb == NULL || skb->len <= 0) {
-		printk("%s: Obsolete driver layer request made: skbuff==NULL.\n",
-			   dev->name);
-		dev_tint(dev);
-		return 0;
-	}
-#endif
-
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		if (jiffies - dev->trans_start >= TX_TIMEOUT)
 			vortex_tx_timeout(dev);
@@ -1401,11 +1523,11 @@
 		int i;
 
 		if (vortex_debug > 3)
-			printk("%s: Trying to send a packet, Tx index %d.\n",
+			printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
 				   dev->name, vp->cur_tx);
 		if (vp->tx_full) {
 			if (vortex_debug >0)
-				printk("%s: Tx Ring full, refusing to send buffer.\n",
+				printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
 					   dev->name);
 			return 1;
 		} 
@@ -1420,7 +1542,7 @@
 		cli();
 		outw(DownStall, ioaddr + EL3_CMD);
 		/* Wait for the stall to complete. */
-		for (i = 60; i >= 0 ; i--)
+		for (i = 600; i >= 0 ; i--)
 			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
 				break;
 		prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
@@ -1436,7 +1558,7 @@
 			vp->tx_full = 1;
 		else {					/* Clear previous interrupt enable. */
 			prev_entry->status &= ~TxIntrUploaded;
-			dev->tbusy = 0;
+			clear_bit(0, (void*)&dev->tbusy);
 		}
 		dev->trans_start = jiffies;
 		return 0;
@@ -1452,176 +1574,108 @@
 #else
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
 #endif
-	struct vortex_private *lp;
+	struct vortex_private *vp;
 	int ioaddr, status;
 	int latency;
-	int i = max_interrupt_work;
+	int work_done = max_interrupt_work;
 
-	if (dev->interrupt)
-		printk("%s: Re-entering the interrupt handler.\n", dev->name);
-	dev->interrupt = 1;
+	vp = (struct vortex_private *)dev->priv;
+	if (test_and_set_bit(0, (void*)&vp->in_interrupt)) {
+		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+		return;
+	}
 
+	dev->interrupt = 1;
 	ioaddr = dev->base_addr;
 	latency = inb(ioaddr + Timer);
-	lp = (struct vortex_private *)dev->priv;
 
 	status = inw(ioaddr + EL3_STATUS);
 
 	if (vortex_debug > 4)
-		printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name,
-			   status, latency);
-#ifdef notdef
-	/* This code guard against bogus hangs, but fails with shared IRQs. */
-	if ((status & ~0xE000) == 0x0000) {
-		static int donedidthis=0;
-		/* Some interrupt controllers store a bogus interrupt from boot-time.
-		   Ignore a single early interrupt, but don't hang the machine for
-		   other interrupt problems. */
-		if (donedidthis++ > 100) {
-			printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
-				   dev->name, status, dev->start);
-			FREE_IRQ(dev->irq, dev);
-		}
-	}
-#endif
-
+		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+			   dev->name, status, latency);
 	do {
 		if (vortex_debug > 5)
-				printk("%s: In interrupt loop, status %4.4x.\n",
+				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
 					   dev->name, status);
 		if (status & RxComplete)
 			vortex_rx(dev);
+		if (status & UpComplete) {
+			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+			boomerang_rx(dev);
+		}
 
 		if (status & TxAvailable) {
 			if (vortex_debug > 5)
-				printk("	TX room bit was handled.\n");
+				printk(KERN_DEBUG "	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			dev->tbusy = 0;
+			clear_bit(0, (void*)&dev->tbusy);
 			mark_bh(NET_BH);
 		}
-		if (status & TxComplete) { /* Really "TxError" for us. */
-			unsigned char tx_status = inb(ioaddr + TxStatus);
-			/* Presumably a tx-timeout. We must merely re-enable. */
-			if (vortex_debug > 2
-				|| (tx_status != 0x88 && vortex_debug > 0))
-				printk("%s: Transmit error, Tx status register %2.2x.\n",
-					   dev->name, tx_status);
-			if (tx_status & 0x04) lp->stats.tx_fifo_errors++;
-			if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
-			outb(0, ioaddr + TxStatus);
-			outw(TxEnable, ioaddr + EL3_CMD);
-		}
+
 		if (status & DownComplete) {
-			unsigned int dirty_tx = lp->dirty_tx;
+			unsigned int dirty_tx = vp->dirty_tx;
 
-			while (lp->cur_tx - dirty_tx > 0) {
+			while (vp->cur_tx - dirty_tx > 0) {
 				int entry = dirty_tx % TX_RING_SIZE;
 				if (inl(ioaddr + DownListPtr) ==
-					virt_to_bus(&lp->tx_ring[entry]))
+					virt_to_bus(&vp->tx_ring[entry]))
 					break;			/* It still hasn't been processed. */
-				if (lp->tx_skbuff[entry]) {
-					dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
-					lp->tx_skbuff[entry] = 0;
+				if (vp->tx_skbuff[entry]) {
+					DEV_FREE_SKB(vp->tx_skbuff[entry]);
+					vp->tx_skbuff[entry] = 0;
 				}
-				/* lp->stats.tx_packets++;  Counted below. */
+				/* vp->stats.tx_packets++;  Counted below. */
 				dirty_tx++;
 			}
-			lp->dirty_tx = dirty_tx;
+			vp->dirty_tx = dirty_tx;
 			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
-			if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
-				lp->tx_full= 0;
-				dev->tbusy = 0;
+			if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+				vp->tx_full= 0;
+				clear_bit(0, (void*)&dev->tbusy);
 				mark_bh(NET_BH);
 			}
 		}
 #ifdef VORTEX_BUS_MASTER
 		if (status & DMADone) {
 			outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-			dev->tbusy = 0;
-			dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
+			clear_bit(0, (void*)&dev->tbusy);
+			DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
 			mark_bh(NET_BH);
 		}
 #endif
-		if (status & UpComplete) {
-			boomerang_rx(dev);
-			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
-		}
-		if (status & (AdapterFailure | RxEarly | StatsFull)) {
-			/* Handle all uncommon interrupts at once. */
-			if (status & RxEarly) {				/* Rx early is unused. */
-				vortex_rx(dev);
-				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
-			}
-			if (status & StatsFull) { 	/* Empty statistics. */
-				static int DoneDidThat = 0;
-				if (vortex_debug > 4)
-					printk("%s: Updating stats.\n", dev->name);
-				update_stats(ioaddr, dev);
-				/* DEBUG HACK: Disable statistics as an interrupt source. */
-				/* This occurs when we have the wrong media type! */
-				if (DoneDidThat == 0  &&
-					inw(ioaddr + EL3_STATUS) & StatsFull) {
-					int win, reg;
-					printk("%s: Updating stats failed, disabling stats as an"
-						   " interrupt source.\n", dev->name);
-					for (win = 0; win < 8; win++) {
-						EL3WINDOW(win);
-						printk("\n Vortex window %d:", win);
-						for (reg = 0; reg < 16; reg++)
-							printk(" %2.2x", inb(ioaddr+reg));
-					}
-					EL3WINDOW(7);
-					outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure
-						 | UpComplete | DownComplete | TxComplete,
-						 ioaddr + EL3_CMD);
-					DoneDidThat++;
-				}
-			}
-			if (status & AdapterFailure) {
-				u16 fifo_diag;
-				EL3WINDOW(4);
-				fifo_diag = inw(ioaddr + Wn4_FIFODiag);
-				if (vortex_debug > 0)
-					printk("%s: Host error, FIFO diagnostic register %4.4x.\n",
-						   dev->name, fifo_diag);
-				/* Adapter failure requires Tx/Rx reset and reinit. */
-				if (fifo_diag & 0x0400) {
-					int j;
-					outw(TxReset, ioaddr + EL3_CMD);
-					for (j = 20; j >= 0 ; j--)
-						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-							break;
-					outw(TxEnable, ioaddr + EL3_CMD);
-				}
-				if (fifo_diag & 0x2000) {
-					outw(RxReset, ioaddr + EL3_CMD);
-					/* Set the Rx filter to the current state. */
-					set_rx_mode(dev);
-					outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
-					outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
-				}
+		/* Check for all uncommon interrupts at once. */
+		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq))
+			vortex_error(dev, status);
+
+		if (--work_done < 0) {
+			if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) {
+				/* Just ack these and return. */
+				outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD);
+			} else {
+				printk(KERN_WARNING "%s: Too much work in interrupt, status "
+					   "%4.4x.  Temporarily disabling functions (%4.4x).\n",
+					   dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
+				/* Disable all pending interrupts. */
+				outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
+				outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
+				/* Set a timer to reenable interrupts. */
+				
+				break;
 			}
 		}
-
-		if (--i < 0) {
-			printk("%s: Too much work in interrupt, status %4.4x.  "
-				   "Disabling functions (%4.4x).\n",
-				   dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
-			/* Disable all pending interrupts. */
-			outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
-			outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
-			break;
-		}
 		/* Acknowledge the IRQ. */
 		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
 
 	} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
 
 	if (vortex_debug > 4)
-		printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
+		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
+			   dev->name, status);
 
 	dev->interrupt = 0;
+	clear_bit(0, (void*)&vp->in_interrupt);
 	return;
 }
 
@@ -1634,13 +1688,13 @@
 	short rx_status;
 
 	if (vortex_debug > 5)
-		printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+		printk(KERN_DEBUG"   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
 	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
 		if (rx_status & 0x4000) { /* Error, update stats. */
 			unsigned char rx_error = inb(ioaddr + RxErrors);
 			if (vortex_debug > 2)
-				printk(" Rx error: status %2.2x.\n", rx_error);
+				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
 			vp->stats.rx_errors++;
 			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
 			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
@@ -1649,12 +1703,12 @@
 			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
 		} else {
 			/* The packet length: up to 4.5K!. */
-			short pkt_len = rx_status & 0x1fff;
+			int pkt_len = rx_status & 0x1fff;
 			struct sk_buff *skb;
 
 			skb = DEV_ALLOC_SKB(pkt_len + 5);
 			if (vortex_debug > 4)
-				printk("Receiving packet size %d status %4.4x.\n",
+				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
 			if (skb != NULL) {
 				skb->dev = dev;
@@ -1680,8 +1734,8 @@
 						break;
 				continue;
 			} else if (vortex_debug)
-				printk("%s: Couldn't allocate a sk_buff of size %d.\n",
-					   dev->name, pkt_len);
+				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
+					   "size %d.\n", dev->name, pkt_len);
 		}
 		outw(RxDiscard, ioaddr + EL3_CMD);
 		vp->stats.rx_dropped++;
@@ -1701,15 +1755,17 @@
 	int entry = vp->cur_rx % RX_RING_SIZE;
 	int ioaddr = dev->base_addr;
 	int rx_status;
+	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
 
 	if (vortex_debug > 5)
-		printk("   In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
+		printk(KERN_DEBUG "  In boomerang_rx(), status %4.4x, rx_status "
+			   "%4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
 	while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
 		if (rx_status & RxDError) { /* Error, update stats. */
 			unsigned char rx_error = rx_status >> 16;
 			if (vortex_debug > 2)
-				printk(" Rx error: status %2.2x.\n", rx_error);
+				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
 			vp->stats.rx_errors++;
 			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
 			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
@@ -1718,11 +1774,11 @@
 			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
 		} else {
 			/* The packet length: up to 4.5K!. */
-			short pkt_len = rx_status & 0x1fff;
+			int pkt_len = rx_status & 0x1fff;
 			struct sk_buff *skb;
 
 			if (vortex_debug > 4)
-				printk("Receiving packet size %d status %4.4x.\n",
+				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
 
 			/* Check if the packet is long enough to just accept without
@@ -1730,28 +1786,45 @@
 			if (pkt_len < rx_copybreak
 				&& (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
 				skb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x10300
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				memcpy(skb_put(skb, pkt_len),
 					   bus_to_virt(vp->rx_ring[entry].addr),
 					   pkt_len);
+#else
+				memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr), pkt_len);
+				skb->len = pkt_len;
+#endif
 				rx_copy++;
 			} else{
 				void *temp;
 				/* Pass up the skbuff already on the Rx ring. */
 				skb = vp->rx_skbuff[entry];
 				vp->rx_skbuff[entry] = NULL;
+#if LINUX_VERSION_CODE >= 0x10300
 				temp = skb_put(skb, pkt_len);
+#else
+				temp = skb->data;
+#endif
 				/* Remove this checking code for final release. */
 				if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
-					printk("%s: Warning -- the skbuff addresses do not match"
-						   " in boomerang_rx: %p vs. %p / %p.\n", dev->name,
-						   bus_to_virt(vp->rx_ring[entry].addr),
-						   skb->head, temp);
+					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
+						   " in boomerang_rx: %p vs. %p.\n", dev->name,
+						   bus_to_virt(vp->rx_ring[entry].addr), temp);
 				rx_nocopy++;
 			}
 #if LINUX_VERSION_CODE > 0x10300
 			skb->protocol = eth_type_trans(skb, dev);
+			{					/* Use hardware checksum info. */
+				int csum_bits = rx_status & 0xee000000;
+				if (csum_bits &&
+					(csum_bits == (IPChksumValid | TCPChksumValid) ||
+					 csum_bits == (IPChksumValid | UDPChksumValid))) {
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+					rx_csumhits++;
+				}
+			}
 #else
 			skb->len = pkt_len;
 #endif
@@ -1760,13 +1833,15 @@
 			vp->stats.rx_packets++;
 		}
 		entry = (++vp->cur_rx) % RX_RING_SIZE;
+		if (--rx_work_limit < 0)
+			break;
 	}
 	/* Refill the Rx ring buffers. */
 	for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
 		struct sk_buff *skb;
 		entry = vp->dirty_rx % RX_RING_SIZE;
 		if (vp->rx_skbuff[entry] == NULL) {
-			skb = dev_alloc_skb(PKT_BUF_SZ);
+			skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
 			if (skb == NULL)
 				break;			/* Bad news!  */
 			skb->dev = dev;			/* Mark as being used by this device. */
@@ -1779,6 +1854,7 @@
 			vp->rx_skbuff[entry] = skb;
 		}
 		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
+		outw(UpUnstall, ioaddr + EL3_CMD);
 	}
 	return 0;
 }
@@ -1794,16 +1870,16 @@
 	dev->tbusy = 1;
 
 	if (vortex_debug > 1) {
-		printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
+		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
 			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
-		printk("%s: vortex close stats: rx_nocopy %d rx_copy %d"
-			   " tx_queued %d.\n",
-			   dev->name, rx_nocopy, rx_copy, queued_packet);
+		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
+			   " tx_queued %d Rx pre-checksummed %d.\n",
+			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
 	}
 
 	del_timer(&vp->timer);
 
-	/* Turn off statistics ASAP.  We update lp->stats below. */
+	/* Turn off statistics ASAP.  We update vp->stats below. */
 	outw(StatsDisable, ioaddr + EL3_CMD);
 
 	/* Disable the receiver and transmitter. */
@@ -1831,7 +1907,7 @@
 #if LINUX_VERSION_CODE < 0x20100
 				vp->rx_skbuff[i]->free = 1;
 #endif
-				dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE);
+				DEV_FREE_SKB(vp->rx_skbuff[i]);
 				vp->rx_skbuff[i] = 0;
 			}
 	}
@@ -1839,7 +1915,7 @@
 		outl(0, ioaddr + DownListPtr);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			if (vp->tx_skbuff[i]) {
-				dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE);
+				DEV_FREE_SKB(vp->tx_skbuff[i]);
 				vp->tx_skbuff[i] = 0;
 			}
 	}
@@ -1911,7 +1987,7 @@
 	int phy = vp->phys[0] & 0x1f;
 
 	if (vortex_debug > 2)
-		printk("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
+		printk(KERN_DEBUG "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
 			   dev->name, rq->ifr_ifrn.ifrn_name, cmd,
 			   data[0], data[1], data[2], data[3]);
 
@@ -1941,11 +2017,11 @@
 set_rx_mode(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
-	short new_mode;
+	int new_mode;
 
 	if (dev->flags & IFF_PROMISC) {
-		if (vortex_debug > 3)
-			printk("%s: Setting promiscuous mode.\n", dev->name);
+		if (vortex_debug > 0)
+			printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
 		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
 	} else	if ((dev->mc_list)  ||  (dev->flags & IFF_ALLMULTI)) {
 		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
@@ -1962,6 +2038,97 @@
 	set_rx_mode(dev);
 }
 #endif
+
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues. */
+#define mdio_delay() udelay(1)
+
+#define MDIO_SHIFT_CLK	0x01
+#define MDIO_DIR_WRITE	0x04
+#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+#define MDIO_DATA_READ	0x02
+#define MDIO_ENB_IN		0x00
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(int ioaddr, int bits)
+{
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	/* Establish sync by sending at least 32 logic ones. */ 
+	while (-- bits >= 0) {
+		outw(MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+}
+
+static int mdio_read(int ioaddr, int phy_id, int location)
+{
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	unsigned int retval = 0;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the read command bits out. */
+	for (i = 14; i >= 0; i--) {
+		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		mdio_delay();
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return retval>>1 & 0xffff;
+}
+
+static void mdio_write(int ioaddr, int phy_id, int location, int value)
+{
+	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int i;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		mdio_delay();
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Leave the interface idle. */
+	for (i = 1; i >= 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+
+	return;
+}
+
 
 #ifdef MODULE
 void
@@ -1969,6 +2136,10 @@
 {
 	struct device *next_dev;
 
+#ifdef CARDBUS
+	unregister_driver(&vortex_ops);
+#endif
+
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_vortex_dev) {
 		next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module;
@@ -1984,7 +2155,9 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
+ *  compile-command-alt1: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c59x_cb.o"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.0.33/linux/drivers/net/Changelog.tlan linux/drivers/net/Changelog.tlan
--- v2.0.33/linux/drivers/net/Changelog.tlan	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/Changelog.tlan	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,96 @@
+TLan Device Driver change log.
+
+0.38	- Added code to isolate the external PHY if the internal PHY is
+	  being used for AUI/BNC connectivity.  Also set the aui and
+	  debug variables from mem_start and mem_end if the driver is
+	  built into the kernel.
+
+0.37	- Added TLAN_PHY_ACTIVITY flag for Unmanaged PHY.
+        - If aui is selected and the card is not a 0xF130 (unmanaged phy),
+	  select the builtin PHY and put it in AUI mode.  I don't know if
+	  this will work, but it is my best guess as to how AUI/BNC
+	  functionality is being provided for the external managed PHYs,
+	  which don't support AUI/BNC.
+	- If aui is set and the card is a 0xF130, set the MTXD1 bit in
+	  the ACOMMIT register, to select AUI mode on the unmanaged PHY.
+	  I don't know if this is necessary.
+
+0.36	- Changed AN_ADV register to not advertise full duplex modes.
+	  100Mbs should work now on 0xAE32.
+	- Fixed a small bug where heartbeat and PHY interrupts were
+	  always being enabled.
+	- Force the driver into Unmanaged PHY mode for 0xF130 devices,
+	  even if a managed (ie, the built-in one) PHY is detected.
+	- Moved the PHY initialization to after the onboard PHY is enabled,
+	  if selected.
+
+0.35	- Added entry for Level One LXT970 PHY.
+	- Commented out instruction to set phyOnline to 1 in DP Check.
+
+0.34	- Revised Reset routine.
+	- Added support for 0xF130 device.
+	- Added entry for NS DP83840A Rev 0 PHY.
+
+0.33	- Major Reformatting of comments to fit in 80 columns.
+	- Changed tabs to 8 spaces, reformatted accordingly.
+	- Added code to check and change polarity.
+	- Added caveats to README.
+	- Small fix to Makefile to make unversioned modules correctly.
+	- Redid PhySelect to list all phy ids then choose one.
+
+0.32	- Put in another change for BNC stuff that I mistakenly
+	  omitted in 0.31.
+
+0.31	- Completed BNC changes (at least one person had it working).
+	- Added another device id.
+	- Changed debugging messages to hopefully be more useful.
+
+0.30	- Added PCI device IDs provided by Don Dupuis of Compaq.
+	- Turned of MINTEN when using 10/100 PHY.
+	- Added ability to select AUI at insmod time.  What will this do
+	  for BNC, if anything?
+	- Tweaked with names.  
+
+0.29	Fixed problem with older TLAN chips (pre-PG3.0 didn't have
+	EOC bit in lists nor INTDIS register).  Added support for NetFlex
+	card.
+
+0.28	Changed a lot of commented out printfs to debugging statements.
+	Added detail to product names.  Added 2nd reset to open command.
+	Don't know why, just have to, at least for Netelligent 10 card.
+
+0.27	Created a tlan_probe function for compiled-in-kernel use.
+	Also added debugging macro, which could be reviewed.  Is there
+	a kernel variable which stores desired verbosity/debug level?
+
+0.26	Change Invalid interrupt handler to return 0, not print out debug
+	message.  This was causing lots of messages to be printed out with
+	shared interrupts.
+
+0.25
+	Added IDs for integrated NetFlex-3 controller.  Not sure if it is even
+	TLAN yet, but we'll see.
+
+0.24
+	Increased second delay in internal PHY check routine, as driver wasn't
+	starting on the first insmod.
+
+0.23
+	Added documentation to function preambles.
+	Removed some commented out printk's.
+	Tested Rx and Tx busy frequency with current queue sizes (no busies).
+
+0.22
+	Cleared tbusy flag at adapter check.
+	Removed some commented out printk's.
+	Added TLan_SetMulticastList routine.
+
+0.21
+	Got all virt_to_bus calls in place for 2.1 kernels.
+
+0.20
+	Rewrote buffer/list subsystem to use bounce buffers as DMA
+	  doesn't work over 16 Meg.  Why?  This is PCI not ISA.
+	Fixed a problem with buffers stalling due to a race condition
+	  in the kernel.
+
diff -u --recursive --new-file v2.0.33/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.0.33/linux/drivers/net/Config.in	Tue Aug 12 20:29:26 1997
+++ linux/drivers/net/Config.in	Wed Jun  3 15:17:47 1998
@@ -41,7 +41,7 @@
 #
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
-  bool '3COM cards' CONFIG_NET_VENDOR_3COM
+  bool '3COM ISA, EISA and PCI cards' CONFIG_NET_VENDOR_3COM
   if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
     tristate '3c501 support' CONFIG_EL1
     tristate '3c503 support' CONFIG_EL2
@@ -50,24 +50,35 @@
       tristate '3c507 support' CONFIG_EL16
     fi
     tristate '3c509/3c579 support' CONFIG_EL3
+    tristate '3c515 ISA Fast EtherLink' CONFIG_3C515
     tristate '3c590/3c900 series (592/595/597/900/905) "Vortex/Boomerang" support' CONFIG_VORTEX
   fi
-  bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
-  if [ "$CONFIG_LANCE" = "y" ]; then
-    bool 'AMD PCInet32 (VLB and PCI) support' CONFIG_LANCE32
-  fi  
-  bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
+  bool 'Western Digital/SMC ISA and EISA cards' CONFIG_NET_VENDOR_SMC
   if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
     tristate 'WD80*3 support' CONFIG_WD80x3
     tristate 'SMC Ultra support' CONFIG_ULTRA
     tristate 'SMC Ultra32 support' CONFIG_ULTRA32
     tristate 'SMC 9194 support' CONFIG_SMC9194
   fi
+  bool 'PCI Ethernet adapters' CONFIG_NET_PCI
+  if [ "$CONFIG_NET_PCI" = "y" ]; then
+    tristate 'AMD PCI PCnet32 (PCI bus NE2100 cards) support' CONFIG_PCNET32
+    tristate 'Intel EtherExpressPro PCI 10+/100B/100+ support' CONFIG_EEXPRESS_PRO100B
+    tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
+    tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
+    tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
+    tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
+    tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
+    tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
+    tristate 'SMC EPIC/100 (EtherPower II) support' CONFIG_EPIC
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
+   fi
+  fi
   bool 'Other ISA cards' CONFIG_NET_ISA
   if [ "$CONFIG_NET_ISA" = "y" ]; then
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'AT1700 support (EXPERIMENTAL)' CONFIG_AT1700
-    fi
+    tristate 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+    tristate 'AT1700 (Fujitsu 86965) support' CONFIG_AT1700
     tristate 'Cabletron E21xx support' CONFIG_E2100
     tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
     tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
@@ -82,7 +93,7 @@
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
     fi
-    tristate 'NE2000/NE1000 support' CONFIG_NE2000
+    tristate 'NE2000/NE1000 ISA support' CONFIG_NE2000
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'NI5210 support' CONFIG_NI52
       tristate 'NI6510 support' CONFIG_NI65
@@ -92,23 +103,19 @@
     fi
     bool 'SK_G16 support' CONFIG_SK_G16
   fi
-  bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
+  bool 'EISA, VLB and other board controllers' CONFIG_NET_EISA
   if [ "$CONFIG_NET_EISA" = "y" ]; then
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
     tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
-    tristate 'Intel EtherExpress/Pro 100B support' CONFIG_EEXPRESS_PRO100B
-    tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
-    tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
-    tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
     fi
   fi
   bool 'Pocket and portable adaptors' CONFIG_NET_POCKET
   if [ "$CONFIG_NET_POCKET" = "y" ]; then
-    bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
+    tristate 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
     tristate 'D-Link DE600 pocket adaptor support' CONFIG_DE600
     tristate 'D-Link DE620 pocket adaptor support' CONFIG_DE620
   fi
diff -u --recursive --new-file v2.0.33/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.0.33/linux/drivers/net/Makefile	Tue Aug 12 20:29:26 1997
+++ linux/drivers/net/Makefile	Wed Jun  3 15:17:47 1998
@@ -148,7 +148,7 @@
 L_OBJS += smc-ultra32.o
 CONFIG_8390_BUILTIN = y
 else
-  ifeq ($(CONFIG_ULTRA),m)
+  ifeq ($(CONFIG_ULTRA32),m)
   CONFIG_8390_MODULE = y
   M_OBJS += smc-ultra32.o
   endif
@@ -247,8 +247,9 @@
 
 ifeq ($(CONFIG_LANCE),y)
 L_OBJS += lance.o
-  ifeq ($(CONFIG_LANCE32),y)
-  L_OBJS += lance32.o
+else
+  ifeq ($(CONFIG_LANCE),m)
+  M_OBJS += lance.o
   endif
 endif
 
@@ -296,6 +297,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_3C515),y)
+L_OBJS += 3c515.o
+else
+  ifeq ($(CONFIG_3C515),m)
+  M_OBJS += 3c515.o
+  endif
+endif
+
 ifeq ($(CONFIG_VORTEX),y)
 L_OBJS += 3c59x.o
 else
@@ -328,6 +337,47 @@
   endif
 endif
 
+ifeq ($(CONFIG_EPIC),y)
+L_OBJS += epic100.o
+else
+  ifeq ($(CONFIG_EPIC),m)
+  M_OBJS += epic100.o
+  endif
+endif
+
+ifeq ($(CONFIG_NE2K_PCI),y)
+L_OBJS += ne2k-pci.o
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_NE2K_PCI),m)
+  CONFIG_8390_MODULE = y
+  M_OBJS += ne2k-pci.o
+  endif
+endif
+
+ifeq ($(CONFIG_PCNET32),y)
+L_OBJS += pcnet32.o
+else
+  ifeq ($(CONFIG_PCNET32),m)
+  M_OBJS += pcnet32.o
+  endif
+endif
+
+ifeq ($(CONFIG_RTL8139),y)
+L_OBJS += rtl8139.o
+else
+  ifeq ($(CONFIG_RTL8139),m)
+  M_OBJS += rtl8139.o
+  endif
+endif
+
+ifeq ($(CONFIG_YELLOWFIN),y)
+L_OBJS += yellowfin.o
+else
+  ifeq ($(CONFIG_YELLOWFIN),m)
+  M_OBJS += yellowfin.o
+  endif
+endif
 
 ifeq ($(CONFIG_WAVELAN),y)
 L_OBJS += wavelan.o
@@ -359,6 +409,10 @@
 
 ifeq ($(CONFIG_ATP),y)
 L_OBJS += atp.o
+else
+  ifeq ($(CONFIG_ATP),m)
+  M_OBJS += atp.o
+  endif
 endif
 
 ifeq ($(CONFIG_DE4X5),y)
@@ -420,6 +474,14 @@
 else
   ifeq ($(CONFIG_DEC_ELCP),m)
   M_OBJS += tulip.o
+  endif
+endif
+
+ifeq ($(CONFIG_TLAN),y)
+L_OBJS += tlan.o
+else
+  ifeq ($(CONFIG_TLAN),m)
+  M_OBJS += tlan.o
   endif
 endif
 
diff -u --recursive --new-file v2.0.33/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.0.33/linux/drivers/net/Space.c	Tue Aug 12 20:29:26 1997
+++ linux/drivers/net/Space.c	Wed Jun  3 15:17:47 1998
@@ -45,12 +45,12 @@
 extern int wd_probe(struct device *dev);
 extern int el2_probe(struct device *dev);
 extern int ne_probe(struct device *dev);
+extern int ne2k_pci_probe(struct device *dev);
 extern int hp_probe(struct device *dev);
 extern int hp_plus_probe(struct device *dev);
 extern int znet_probe(struct device *);
 extern int express_probe(struct device *);
 extern int eepro_probe(struct device *);
-extern int eepro100_probe(struct device *);
 extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
@@ -80,7 +80,14 @@
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
-
+extern int yellowfin_probe(struct device *);
+extern int eepro100_probe(struct device *);
+extern int epic100_probe(struct device *);
+extern int rtl8139_probe(struct device *);
+extern int tlan_probe(struct device *);
+extern int isa515_probe(struct device *);
+extern int pcnet32_probe(struct device *);
+extern int lance_probe(struct device *);
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
 extern int de600_probe(struct device *);
@@ -95,27 +102,54 @@
 	return 1;		/* ENXIO */
 
     if (1
+	/* All PCI probes are safe, and thus should be first. */
+#ifdef CONFIG_DE4X5             /* DEC DE425, DE434, DE435 adapters */
+	&& de4x5_probe(dev)
+#endif
 #ifdef CONFIG_DGRS
 	&& dgrs_probe(dev)
 #endif
+#ifdef CONFIG_EEXPRESS_PRO100B	/* Intel EtherExpress Pro100B */
+	&& eepro100_probe(dev)
+#endif
+#ifdef CONFIG_EPIC
+	&& epic100_probe(dev)
+#endif
+#if defined(CONFIG_HP100)
+	&& hp100_probe(dev)
+#endif	
+#if defined(CONFIG_NE2K_PCI)
+	&& ne2k_pci_probe(dev)
+#endif
+#ifdef CONFIG_PCNET32
+	&& pcnet32_probe(dev)
+#endif
+#ifdef CONFIG_RTL8139
+	&& rtl8139_probe(dev)
+#endif
 #if defined(CONFIG_VORTEX)
 	&& tc59x_probe(dev)
 #endif
-#if defined(CONFIG_SEEQ8005)
-	&& seeq8005_probe(dev)
-#endif
 #if defined(CONFIG_DEC_ELCP)
 	&& tulip_probe(dev)
 #endif
-#if defined(CONFIG_HP100)
-	&& hp100_probe(dev)
-#endif	
-#if defined(CONFIG_ULTRA)
-	&& ultra_probe(dev)
+#ifdef CONFIG_YELLOWFIN
+	&& yellowfin_probe(dev)
+#endif
+	/* Next mostly-safe EISA-only drivers. */
+#ifdef CONFIG_AC3200		/* Ansel Communications EISA 3200. */
+	&& ac3200_probe(dev)
 #endif
 #if defined(CONFIG_ULTRA32)
 	&& ultra32_probe(dev)
 #endif
+	/* Third, sensitive ISA boards. */
+#ifdef CONFIG_AT1700
+	&& at1700_probe(dev)
+#endif
+#if defined(CONFIG_ULTRA)
+	&& ultra_probe(dev)
+#endif
 #if defined(CONFIG_SMC9194)
 	&& smc_init(dev)
 #endif
@@ -131,21 +165,18 @@
 #if defined(CONFIG_HPLAN_PLUS)
 	&& hp_plus_probe(dev)
 #endif
-#ifdef CONFIG_AC3200		/* Ansel Communications EISA 3200. */
-	&& ac3200_probe(dev)
+#if defined(CONFIG_SEEQ8005)
+	&& seeq8005_probe(dev)
 #endif
 #ifdef CONFIG_E2100		/* Cabletron E21xx series. */
 	&& e2100_probe(dev)
 #endif
-#if defined(CONFIG_NE2000) || defined(NE2000)
+#if defined(CONFIG_NE2000)
 	&& ne_probe(dev)
 #endif
 #ifdef CONFIG_AT1500
 	&& at1500_probe(dev)
 #endif
-#ifdef CONFIG_AT1700
-	&& at1700_probe(dev)
-#endif
 #ifdef CONFIG_FMV18X		/* Fujitsu FMV-181/182 */
 	&& fmv18x_probe(dev)
 #endif
@@ -155,6 +186,9 @@
 #ifdef CONFIG_EL3		/* 3c509 */
 	&& el3_probe(dev)
 #endif
+#ifdef CONFIG_3C515		/* 3c515 */
+	&& tc515_probe(dev)
+#endif
 #ifdef CONFIG_ZNET		/* Zenith Z-Note and some IBM Thinkpads. */
 	&& znet_probe(dev)
 #endif
@@ -164,18 +198,12 @@
 #ifdef CONFIG_EEXPRESS_PRO	/* Intel EtherExpress Pro/10 */
 	&& eepro_probe(dev)
 #endif
-#ifdef CONFIG_EEXPRESS_PRO100B	/* Intel EtherExpress Pro100B */
-	&& eepro100_probe(dev)
-#endif
 #ifdef CONFIG_DEPCA		/* DEC DEPCA */
 	&& depca_probe(dev)
 #endif
 #ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
         && ewrk3_probe(dev)
 #endif
-#ifdef CONFIG_DE4X5             /* DEC DE425, DE434, DE435 adapters */
-        && de4x5_probe(dev)
-#endif
 #ifdef CONFIG_APRICOT		/* Apricot I82596 */
 	&& apricot_probe(dev)
 #endif
@@ -206,6 +234,9 @@
 #ifdef CONFIG_NI65
 	&& ni65_probe(dev)
 #endif
+#ifdef CONFIG_LANCE	/* ISA LANCE boards */
+	&& lance_probe(dev)
+#endif
 #ifdef CONFIG_ATARILANCE	/* Lance-based Atari ethernet boards */
 	&& atarilance_probe(dev)
 #endif
@@ -220,6 +251,15 @@
 #endif
 #ifdef CONFIG_SUNLANCE
 	&& sparc_lance_probe(dev)
+#endif
+#ifdef CONFIG_TLAN
+	&& tlan_probe(dev)
+#endif
+#ifdef CONFIG_PCNET32
+	&& pcnet32_probe(dev)
+#endif
+#ifdef CONFIG_LANCE
+	&& lance_probe(dev)
 #endif
 	&& 1 ) {
 	return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.0.33/linux/drivers/net/arcnet.c	Sat Oct 19 00:36:20 1996
+++ linux/drivers/net/arcnet.c	Wed Jun  3 15:17:47 1998
@@ -373,7 +373,7 @@
 
 /* macros to simplify debug checking */
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
-#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg, ## args)
+#define BUGMSG2(x,msg,args...) do{BUGLVL(x) printk(msg, ## args);}while(0)
 #define BUGMSG(x,msg,args...) BUGMSG2(x,"%s%6s: " msg, \
             x==D_NORMAL	? KERN_WARNING : \
       x<=D_INIT_REASONS	? KERN_INFO    : KERN_DEBUG , \
diff -u --recursive --new-file v2.0.33/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.0.33/linux/drivers/net/at1700.c	Thu Feb 29 21:50:43 1996
+++ linux/drivers/net/at1700.c	Wed Jun  3 15:17:47 1998
@@ -1,6 +1,6 @@
 /* at1700.c: A network device driver for  the Allied Telesis AT1700.
 
-	Written 1993-94 by Donald Becker.
+	Written 1993-98 by Donald Becker.
 
 	Copyright 1993 United States Government as represented by the
 	Director, National Security Agency.
@@ -29,7 +29,7 @@
 */
 
 static const char *version =
-	"at1700.c:v1.12 1/18/95  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+	"at1700.c:v1.15 4/7/98  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
 
@@ -53,9 +53,17 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-/* This unusual address order is used to verify the CONFIG register. */
+/* Tunable parameters. */
+
+/* When to switch from the 64-entry multicast filter to Rx-all-multicast. */
+#define MC_FILTERBREAK 64
+
+/* These unusual address orders are used to verify the CONFIG register. */
 static int at1700_probe_list[] =
 {0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0};
+static int fmv18x_probe_list[] =
+{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};
+
 
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
@@ -68,7 +76,10 @@
 /* Information that need to be kept for each board. */
 struct net_local {
 	struct enet_statistics stats;
-	uint tx_started:1;			/* Number of packet on the Tx queue. */
+	unsigned char mc_filter[8];
+	uint jumpered:1;			/* Set iff the board has jumper config. */
+	uint tx_started:1;			/* Packets are on the Tx queue. */
+	uint invalid_irq:1;
 	uchar tx_queue;				/* Number of packet on the Tx queue. */
 	ushort tx_queue_len;		/* Current length of the Tx queue. */
 };
@@ -88,32 +99,19 @@
 #define DATAPORT		8		/* Word-wide DMA or programmed-I/O dataport. */
 #define TX_START		10
 #define MODE13			13
+/* Configuration registers only on the '865A/B chips. */
 #define EEPROM_Ctrl 	16
 #define EEPROM_Data 	17
-#define IOCONFIG		19
+#define IOCONFIG		18		/* Either read the jumper, or move the I/O. */
+#define IOCONFIG1		19
+#define	SAPROM			20		/* The station address PROM, if no EEPROM. */
 #define RESET			31		/* Write to reset some parts of the chip. */
 #define AT1700_IO_EXTENT	32
-
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK	0x40	/* EEPROM shift clock, in reg. 16. */
-#define EE_CS			0x20	/* EEPROM chip select, in reg. 16. */
-#define EE_DATA_WRITE	0x80	/* EEPROM chip data in, in reg. 17. */
-#define EE_DATA_READ	0x80	/* EEPROM chip data out, in reg. 17. */
-
-/* Delay between EEPROM clock transitions. */
-#define eeprom_delay()	do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD	(5 << 6)
-#define EE_READ_CMD		(6 << 6)
-#define EE_ERASE_CMD	(7 << 6)
-
-
 /* Index to functions, as function prototypes. */
 
 extern int at1700_probe(struct device *dev);
 
-static int at1700_probe1(struct device *dev, short ioaddr);
+static int at1700_probe1(struct device *dev, int ioaddr);
 static int read_eeprom(int ioaddr, int location);
 static int net_open(struct device *dev);
 static int	net_send_packet(struct sk_buff *skb, struct device *dev);
@@ -121,7 +119,7 @@
 static void net_rx(struct device *dev);
 static int net_close(struct device *dev);
 static struct enet_statistics *net_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev);
+static void set_rx_mode(struct device *dev);
 
 
 /* Check for a network adaptor of this type, and return '0' iff one exists.
@@ -167,10 +165,11 @@
    that can be done is checking a few bits and then diving right into an
    EEPROM read. */
 
-int at1700_probe1(struct device *dev, short ioaddr)
+int at1700_probe1(struct device *dev, int ioaddr)
 {
-	char irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
-	unsigned int i, irq;
+	char fmv_irqmap[4] = {3, 7, 10, 15};
+	char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
+	unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
 
 	/* Resetting the chip doesn't reset the ISA interface, so don't bother.
 	   That means we have to be careful with the register values we probe for.
@@ -180,38 +179,42 @@
 		   ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5),
 		   read_eeprom(ioaddr, 6), inw(ioaddr + EEPROM_Ctrl));
 #endif
-	if (at1700_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr
-		|| read_eeprom(ioaddr, 4) != 0x0000
-		|| (read_eeprom(ioaddr, 5) & 0xff00) != 0xF400)
+	/* We must check for the EEPROM-config boards first, else accessing
+	   IOCONFIG0 will move the board! */
+	if (at1700_probe_list[inb(ioaddr + IOCONFIG1) & 0x07] == ioaddr
+		&& read_eeprom(ioaddr, 4) == 0x0000
+		&& (read_eeprom(ioaddr, 5) & 0xff00) == 0xF400)
+		is_at1700 = 1;
+	else if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] == ioaddr
+		&& inb(ioaddr + SAPROM    ) == 0x00
+		&& inb(ioaddr + SAPROM + 1) == 0x00
+		&& inb(ioaddr + SAPROM + 2) == 0x0e)
+		is_fmv18x = 1;
+	else
 		return -ENODEV;
 
 	/* Reset the internal state machines. */
 	outb(0, ioaddr + RESET);
 
-	irq = irqmap[(read_eeprom(ioaddr, 12)&0x04)
-				 | (read_eeprom(ioaddr, 0)>>14)];
-
-	/* Snarf the interrupt vector now. */
-	if (request_irq(irq, &net_interrupt, 0, "at1700", NULL)) {
-		printk ("AT1700 found at %#3x, but it's unusable due to a conflict on"
-				"IRQ %d.\n", ioaddr, irq);
-		return EAGAIN;
-	}
-
 	/* Allocate a new 'dev' if needed. */
 	if (dev == NULL)
 		dev = init_etherdev(0, sizeof(struct net_local));
 
+	if (is_at1700)
+		irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
+						   | (read_eeprom(ioaddr, 0)>>14)];
+	else
+		irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
+
 	/* Grab the region so that we can find another board if the IRQ request
 	   fails. */
-	request_region(ioaddr, AT1700_IO_EXTENT, "at1700");
+	request_region(ioaddr, AT1700_IO_EXTENT, dev->name);
 
 	printk("%s: AT1700 found at %#3x, IRQ %d, address ", dev->name,
 		   ioaddr, irq);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
-	irq2dev_map[irq] = dev;
 
 	for(i = 0; i < 3; i++) {
 		unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
@@ -234,12 +237,12 @@
 	}
 
 	/* Set the station address in bank zero. */
-	outb(0xe0, ioaddr + 7);
+	outb(0xe0, ioaddr + CONFIG_1);
 	for (i = 0; i < 6; i++)
 		outb(dev->dev_addr[i], ioaddr + 8 + i);
 
 	/* Switch to bank 1 and set the multicast table to accept none. */
-	outb(0xe4, ioaddr + 7);
+	outb(0xe4, ioaddr + CONFIG_1);
 	for (i = 0; i < 8; i++)
 		outb(0x00, ioaddr + 8 + i);
 
@@ -248,7 +251,7 @@
 	outb(0xda, ioaddr + CONFIG_0);
 
 	/* Switch to bank 2 and lock our I/O address. */
-	outb(0xe8, ioaddr + 7);
+	outb(0xe8, ioaddr + CONFIG_1);
 	outb(dev->if_port, MODE13);
 
 	/* Power-down the chip.  Aren't we green! */
@@ -267,50 +270,72 @@
 	dev->stop		= net_close;
 	dev->hard_start_xmit = net_send_packet;
 	dev->get_stats	= net_get_stats;
-	dev->set_multicast_list = &set_multicast_list;
+	dev->set_multicast_list = &set_rx_mode;
 
 	/* Fill in the fields of 'dev' with ethernet-generic values. */
-	   
 	ether_setup(dev);
+
+	{
+		struct net_local *lp = (struct net_local *)dev->priv;
+		lp->jumpered = is_fmv18x;
+		/* Snarf the interrupt vector now. */
+		if (request_irq(irq, &net_interrupt, 0, dev->name, dev)) {
+			printk ("  AT1700 at %#3x is unusable due to a conflict on"
+					"IRQ %d.\n", ioaddr, irq);
+			lp->invalid_irq = 1;
+			return 0;
+		}
+	}
+
 	return 0;
 }
 
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x40	/* EEPROM shift clock, in reg. 16. */
+#define EE_CS			0x20	/* EEPROM chip select, in reg. 16. */
+#define EE_DATA_WRITE	0x80	/* EEPROM chip data in, in reg. 17. */
+#define EE_DATA_READ	0x80	/* EEPROM chip data out, in reg. 17. */
+
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay()	do {} while (0);
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
 static int read_eeprom(int ioaddr, int location)
 {
 	int i;
 	unsigned short retval = 0;
-	short ee_addr = ioaddr + EEPROM_Ctrl;
-	short ee_daddr = ioaddr + EEPROM_Data;
+	int ee_addr = ioaddr + EEPROM_Ctrl;
+	int ee_daddr = ioaddr + EEPROM_Data;
 	int read_cmd = location | EE_READ_CMD;
-	short ctrl_val = EE_CS;
-	
-	outb(ctrl_val, ee_addr);
-	
+
 	/* Shift the read command bits out. */
 	for (i = 9; i >= 0; i--) {
 		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outb(EE_CS, ee_addr);
 		outb(dataval, ee_daddr);
-		outb(EE_CS | EE_SHIFT_CLK, ee_addr);	/* EEPROM clock tick. */
 		eeprom_delay();
-		outb(EE_CS, ee_addr);	/* Finish EEPROM a clock tick. */
+		outb(EE_CS | EE_SHIFT_CLK, ee_addr);	/* EEPROM clock tick. */
 		eeprom_delay();
 	}
-	outb(EE_CS, ee_addr);
-	
+	outb(EE_DATA_WRITE, ee_daddr);
 	for (i = 16; i > 0; i--) {
+		outb(EE_CS, ee_addr);
+		eeprom_delay();
 		outb(EE_CS | EE_SHIFT_CLK, ee_addr);
 		eeprom_delay();
 		retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
-		outb(EE_CS, ee_addr);
-		eeprom_delay();
 	}
 
 	/* Terminate the EEPROM access. */
-	ctrl_val &= ~EE_CS;
-	outb(ctrl_val | EE_SHIFT_CLK, ee_addr);
-	eeprom_delay();
-	outb(ctrl_val, ee_addr);
+	outb(EE_CS, ee_addr);
 	eeprom_delay();
+	outb(EE_SHIFT_CLK, ee_addr);
+	outb(0, ee_addr);
 	return retval;
 }
 
@@ -330,7 +355,7 @@
 		outb(dev->dev_addr[i], ioaddr + 8 + i);
 
 	/* Switch to bank 1 and set the multicast table to accept none. */
-	outb(0xe4, ioaddr + 7);
+	outb(0xe4, ioaddr + CONFIG_1);
 	for (i = 0; i < 8; i++)
 		outb(0x00, ioaddr + 8 + i);
 
@@ -338,10 +363,8 @@
 	   bus access, and two 4K Tx queues. */
 	outb(0xda, ioaddr + CONFIG_0);
 
-	/* Same config 0, except enable the Rx and Tx. */
-	outb(0x5a, ioaddr + CONFIG_0);
-	/* Switch to register bank 2 for the run-time registers. */
-	outb(0xe8, ioaddr + CONFIG_1);
+	/* Switch to register bank 2, enable the Rx and Tx. */
+	outw(0xe85a, ioaddr + CONFIG_0);
 
 	lp->tx_started = 0;
 	lp->tx_queue = 0;
@@ -410,7 +433,7 @@
 
 		/* Turn off the possible Tx interrupts. */
 		outb(0x00, ioaddr + TX_INTR);
-		
+
 		outw(length, ioaddr + DATAPORT);
 		outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
 
@@ -442,7 +465,7 @@
 static void
 net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct device *dev = dev_id;
 	struct net_local *lp;
 	int ioaddr, status;
 
@@ -563,7 +586,7 @@
 		}
 
 		if (net_debug > 5)
-			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n", 
+			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
 				   dev->name, inb(ioaddr + RX_MODE), i);
 	}
 	return;
@@ -572,6 +595,7 @@
 /* The inverse routine to net_open(). */
 static int net_close(struct device *dev)
 {
+	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 
 	dev->tbusy = 1;
@@ -580,7 +604,15 @@
 	/* Set configuration register 0 to disable Tx and Rx. */
 	outb(0xda, ioaddr + CONFIG_0);
 
-	/* Update the statistics -- ToDo. */
+	/* No statistic counters on the chip to update. */
+
+#if 0
+	/* Disable the IRQ on boards where it is feasible. */
+	if (lp->jumpered) {
+		outb(0x00, ioaddr + IOCONFIG1);
+		free_irq(dev->irq, dev);
+	}
+#endif
 
 	/* Power-down the chip.  Green, green, green! */
 	outb(0x00, ioaddr + CONFIG_1);
@@ -590,44 +622,90 @@
 	return 0;
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
+/* Get the current statistics.
+   This may be called with the card open or closed.
+   There are no on-chip counters, so this function is trivial.
+*/
 static struct enet_statistics *
 net_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
+	return &lp->stats;
+}
 
-	cli();
-	/* ToDo: Update the statistics from the device registers. */
-	sti();
+/*
+  Set the multicast/promiscuous mode for this adaptor.
+*/
 
-	return &lp->stats;
+/* The little-endian AUTODIN II ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
 }
 
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1	Promiscuous mode, receive all packets
-   num_addrs == 0	Normal mode, clear multicast list
-   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
-			best-effort filtering.
- */
 static void
-set_multicast_list(struct device *dev)
+set_rx_mode(struct device *dev)
 {
-	short ioaddr = dev->base_addr;
-	if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) 
-	{
-		/*
-		 *	We must make the kernel realise we had to move
-		 *	into promisc mode or we start all out war on
-		 *	the cable. - AC
-		 */
-		dev->flags|=IFF_PROMISC;		
-	
+	int ioaddr = dev->base_addr;
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned char mc_filter[8];		 /* Multicast hash filter */
+	long flags;
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Unconditionally log net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		memset(mc_filter, 0xff, sizeof(mc_filter));
 		outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
-	} 
-	else
-		outb(2, ioaddr + RX_MODE);	/* Disable promiscuous, use normal mode */
+	} else if (dev->mc_count > MC_FILTERBREAK
+			   ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
+	} else if (dev->mc_count == 0) {
+		memset(mc_filter, 0x00, sizeof(mc_filter));
+		outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
+	} else {
+		struct dev_mc_list *mclist;
+		int i;
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next)
+			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26,
+					mc_filter);
+	}
+
+	save_flags(flags);
+	cli();
+	if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
+		int saved_bank = inw(ioaddr + CONFIG_0);
+		/* Switch to bank 1 and set the multicast table. */
+		outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
+		for (i = 0; i < 8; i++)
+			outb(mc_filter[i], ioaddr + 8 + i);
+		memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
+		outw(saved_bank, ioaddr + CONFIG_0);
+	}
+	restore_flags(flags);
+	return;
 }
+
 #ifdef MODULE
 static char devicename[9] = { 0, };
 static struct device dev_at1700 = {
@@ -661,17 +739,16 @@
 
 	/* If we don't do this, we can't re-insmod it later. */
 	free_irq(dev_at1700.irq, NULL);
-	irq2dev_map[dev_at1700.irq] = NULL;
 	release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
 }
 #endif /* MODULE */
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c at1700.c"
- *  version-control: t
- *  kept-new-versions: 5
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c"
+ *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c"
  *  tab-width: 4
+ *  c-basic-offset: 4
  *  c-indent-level: 4
  * End:
  */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c
--- v2.0.33/linux/drivers/net/auto_irq.c	Mon Aug  4 12:10:18 1997
+++ linux/drivers/net/auto_irq.c	Wed Jun  3 15:17:47 1998
@@ -39,7 +39,7 @@
 #include <asm/irq.h>
 #include <linux/netdevice.h>
 
-struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */};
+struct device *irq2dev_map[NR_IRQS] = {0, 0, /* ... zeroed */};
 
 unsigned long irqs_busy = 0x2147;		/* The set of fixed IRQs (keyboard, timer, etc) */
 unsigned long irqs_used = 0x0001;		/* The set of fixed IRQs sometimes enabled. */
@@ -65,8 +65,8 @@
 int autoirq_setup(int waittime)
 {
 	int i;
-	int timeout = jiffies + waittime;
-	int boguscount = (waittime*loops_per_sec) / 100;
+	unsigned long timeout = jiffies + waittime;
+	unsigned long boguscount = (waittime*loops_per_sec) / 100;
 
 	irq_handled = 0;
 	irq_bitmap = 0;
@@ -93,8 +93,8 @@
 int autoirq_report(int waittime)
 {
 	int i;
-	int timeout = jiffies+waittime;
-	int boguscount = (waittime*loops_per_sec) / 100;
+	unsigned long timeout = jiffies+waittime;
+	unsigned long boguscount = (waittime*loops_per_sec) / 100;
 
 	/* Hang out at least <waittime> jiffies waiting for the IRQ. */
 
diff -u --recursive --new-file v2.0.33/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.0.33/linux/drivers/net/de4x5.c	Tue Aug 12 13:21:12 1997
+++ linux/drivers/net/de4x5.c	Wed Jun  3 15:17:47 1998
@@ -41,12 +41,13 @@
     Digital Semiconductor   SROM   Specification.    The  driver   currently
     recognises the following chips:
 
-        DC21040     (no SROM)
-	DC21041[A]
-	DC21140[A]
+        DC21040  (no SROM) 
+	DC21041[A]  
+	DC21140[A] 
+	DC21142 
+	DC21143 
 
-    I plan to  add DC2114[23]  support ASAP,  time permitting.   So far  the
-    driver is known to work with the following cards:
+    So far the driver is known to work with the following cards:
 
         KINGSTON
 	Linksys
@@ -101,7 +102,7 @@
     1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
     2) for fixed  autoprobes (not  recommended),  edit the source code  near
-    line 5005 to reflect the I/O address  you're using, or assign these when
+    line 5594 to reflect the I/O address  you're using, or assign these when
     loading by:
 
                    insmod de4x5 io=0xghh           where g = bus number
@@ -179,9 +180,53 @@
     INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
     run on the same interrupt. PCMCIA/CardBus is another can of worms...
 
+    Finally, I think  I have really  fixed  the module  loading problem with
+    more than one DECchip based  card.  As a  side effect, I don't mess with
+    the  device structure any  more which means that  if more than 1 card in
+    2.0.x is    installed (4  in   2.1.x),  the  user   will have   to  edit
+    linux/drivers/net/Space.c  to make room for  them. Hence, module loading
+    is  the preferred way to use   this driver, since  it  doesn't have this
+    limitation.
+
+    Where SROM media  detection is used and  full duplex is specified in the
+    SROM,  the feature is  ignored unless  lp->params.fdx  is set at compile
+    time  OR during  a   module load  (insmod  de4x5   args='eth??:fdx' [see
+    below]).  This is because there  is no way  to automatically detect full
+    duplex   links  except through   autonegotiation.    When I  include the
+    autonegotiation feature in  the SROM autoconf  code, this detection will
+    occur automatically for that case.
+
+    Command  line arguments are  now  allowed, similar  to passing arguments
+    through LILO. This will allow a per adapter board  set up of full duplex
+    and media. The only lexical constraints  are: the board name (dev->name)
+    appears in the list before its  parameters.  The list of parameters ends
+    either at the end of the parameter list or with another board name.  The
+    following parameters are allowed:
+
+            fdx        for full duplex
+	    autosense  to set the media/speed; with the following 
+	               sub-parameters:
+		       TP, TP_NW, BNC, AUI, BNC_AUI, 100Mb, 10Mb, AUTO
+
+    Case sensitivity is important  for  the sub-parameters. They *must*   be
+    upper case. Examples:
+
+        insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
+
+    For a compiled in driver, in linux/drivers/net/CONFIG, place e.g.
+	DE4X5_OPTS = -DDE4X5_PARM='"eth0:fdx autosense=AUI eth2:autosense=TP"' 
+
+    Yes,  I know full duplex  isn't permissible on BNC  or AUI; they're just
+    examples. By default, full duplex is turned  off and AUTO is the default
+    autosense setting. In  reality, I expect only the  full duplex option to
+    be used. Note the use of single quotes in the two examples above and the
+    lack of commas to separate items.
+
     TO DO:
     ------
 
+    o check what revision numbers the 21142 and 21143 have
+    o
 
     Revision History
     ----------------
@@ -300,11 +345,38 @@
 			  Added byte counters from <phil@tazenda.demon.co.uk>
 			  Added SA_INTERRUPT temporary fix from 
 			   <mjacob@feral.com>.
+      0.53   12-Nov-97    Fix the *_probe() to include 'eth??' name during
+                           module load: bug reported by
+			   <Piete.Brooks@cl.cam.ac.uk>
+			  Fix multi-MAC, one SROM, to work with 2114x chips:
+			   bug reported by <cmetz@inner.net>.
+			  Make above search independent of BIOS device scan
+			   direction.
+			  Completed DC2114[23] autosense functions.
+      0.531  21-Dec-97    Fix DE500-XA 100Mb/s bug reported by 
+                           <robin@intercore.com
+			  Fix type1_infoblock() bug introduced in 0.53, from
+			   problem reports by 
+			   <parmee@postecss.ncrfran.france.ncr.com> and
+			   <jo@ice.dillingen.baynet.de>.
+			  Added argument list to set up each board from either
+			   a module's command line or a compiled in #define.
+			  Added generic MII PHY functionality to deal with
+			   newer PHY chips.
+			  Fix the mess in 2.1.67.
+      0.532   5-Jan-98    Fix bug in mii_get_phy() reported by 
+                           <redhat@cococo.net>.
+                          Fix bug in pci_probe() for 64 bit systems reported
+			   by <belliott@accessone.com>.
+      0.533   9-Jan-98    Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
+      0.534  24-Jan-98    Fix last (?) endian bug from 
+                           <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+      0.535  21-Feb-98    Fix Ethernet Address PROM reset bug for DC21040.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.535 1998/2/21 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -339,25 +411,28 @@
 #define c_char const char
 
 #include <linux/version.h>
-#if	LINUX_VERSION_CODE < ((2 << 16) | (1 << 8))
-#define        net_device_stats      enet_statistics
-#define copy_to_user(a,b,c)   memcpy_tofs(a,b,c)
-#define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
-#define le16_to_cpu(a) cpu_to_le16(a) 
-#define le32_to_cpu(a) cpu_to_le32(a) 
-#ifdef __powerpc__
-#define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
-#define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
-		        (((a) & 0x0000ff00U) <<  8) |\
-		        (((a) & 0x00ff0000U) >>  8) |\
-		        (((a) & 0xff000000U) >> 24))
+#if	LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+#  define __initfunc(__arginit) __arginit
+#  define test_and_set_bit      set_bit
+#  define net_device_stats      enet_statistics
+#  define copy_to_user(a,b,c)   memcpy_tofs(a,b,c)
+#  define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
+#  define le16_to_cpu(a)        cpu_to_le16(a) 
+#  define le32_to_cpu(a)        cpu_to_le32(a) 
+#  ifdef __powerpc__
+#    define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
+#    define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
+		            (((a) & 0x0000ff00U) <<  8) |\
+		            (((a) & 0x00ff0000U) >>  8) |\
+		            (((a) & 0xff000000U) >> 24))
+#  else
+#    define cpu_to_le16(a)      (a)
+#    define cpu_to_le32(a)      (a)
+#  endif  /* __powerpc__ */
+#  include <asm/segment.h>
 #else
-#define cpu_to_le16(a) (a)
-#define cpu_to_le32(a) (a)
-#endif  /* __powerpc__ */
-#include	<asm/segment.h>
-#else
-#include	<asm/uaccess.h>
+#  include <asm/uaccess.h>
+#  include <linux/init.h>
 #endif  /* LINUX_VERSION_CODE */
 #define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
 
@@ -391,6 +466,7 @@
     u_int ana;              /* NWay Advertisement                        */
     u_int fdx;              /* Full DupleX capabilites for each media    */
     u_int ttm;              /* Transmit Threshold Mode for each media    */
+    u_int mci;              /* 21142 MII Connector Interrupt info        */
 };
 
 #define DE4X5_MAX_PHY 8     /* Allow upto 8 attached PHY devices per board */
@@ -407,16 +483,26 @@
 
 /*
 ** Define the know universe of PHY devices that can be
-** recognised by this driver
+** recognised by this driver.
 */
 static struct phy_table phy_info[] = {
-    {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}},   /* National TX */
-    {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}},   /* Broadcom T4 */
-    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},   /* SEEQ T4     */
-    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}}    /* Cypress T4  */
+    {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}},       /* National TX */
+    {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}},       /* Broadcom T4 */
+    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},       /* SEEQ T4     */
+    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}},       /* Cypress T4  */
+    {0, 0x7810     , 1, {0x05, 0x0380, 0x0380}}    /* Level One?  */
 };
 
 /*
+** These GENERIC values assumes that the PHY devices follow 802.3u and
+** allow parallel detection to set the link partner ability register.
+** Detection of 100Base-TX [H/F Duplex] and 100Base-T4 is supported.
+*/
+#define GENERIC_REG   0x05      /* Autoneg. Link Partner Advertisement Reg. */
+#define GENERIC_MASK  MII_ANLPA_100M /* All 100Mb/s Technologies            */
+#define GENERIC_VALUE MII_ANLPA_100M /* 100B-TX, 100B-TX FDX, 100B-T4       */
+
+/*
 ** Define special SROM detection cases
 */
 static c_char enet_det[][ETH_ALEN] = {
@@ -443,21 +529,31 @@
 #ifdef DE4X5_DEBUG
 static int de4x5_debug = DE4X5_DEBUG;
 #else
-static int de4x5_debug = (0);
+/*static int de4x5_debug = (DEBUG_MII | DEBUG_SROM | DEBUG_PCICFG | DEBUG_MEDIA | DEBUG_VERSION);*/
+static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION);
 #endif
 
-#ifdef DE4X5_AUTOSENSE              /* Should be done on a per adapter basis */
-static int de4x5_autosense = DE4X5_AUTOSENSE;
+/*
+** Allow per adapter set up. For modules this is simply a command line
+** parameter, e.g.: 
+** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
+**
+** For a compiled in driver, place e.g.
+** DE4X5_OPTS = -DDE4X5_PARM='"eth0:fdx autosense=AUI eth2:autosense=TP"' 
+** in linux/drivers/net/CONFIG
+*/
+#ifdef DE4X5_PARM
+static char *args = DE4X5_PARM;
 #else
-static int de4x5_autosense = AUTO;  /* Do auto media/mode sensing */
+static char *args = NULL;
 #endif
-#define DE4X5_AUTOSENSE_MS 250      /* msec autosense tick (DE500) */
 
-#ifdef DE4X5_FULL_DUPLEX            /* Should be done on a per adapter basis */
-static s32 de4x5_full_duplex = 1;
-#else
-static s32 de4x5_full_duplex = 0;
-#endif
+struct parameters {
+    int fdx;
+    int autosense;
+};
+
+#define DE4X5_AUTOSENSE_MS 250      /* msec autosense tick (DE500) */
 
 #define DE4X5_NDA 0xffe0            /* No Device (I/O) Address */
 
@@ -497,11 +593,18 @@
 #define DE4X5_NAME_LENGTH 8
 
 /*
+** Ethernet PROM defines for DC21040
+*/
+#define PROBE_LENGTH    32
+#define ETH_PROM_SIG    0xAA5500FFUL
+
+/*
 ** PCI Bus defines
 */
 #define PCI_MAX_BUS_NUM      8
 #define DE4X5_PCI_TOTAL_SIZE 0x80       /* I/O address extent */
 #define DE4X5_CLASS_CODE     0x00020000 /* Network controller, Ethernet */
+#define NO_MORE_PCI          -2         /* PCI bus search all done */
 
 /*
 ** Memory Alignment. Each descriptor is 4 longwords long. To force a
@@ -674,7 +777,7 @@
     struct {
 	void *priv;                         /* Original kmalloc'd mem addr  */
 	void *buf;                          /* Original kmalloc'd mem addr  */
-	int lock;                           /* Lock the cache accesses      */
+	u_long lock;                        /* Lock the cache accesses      */
 	s32 csr0;                           /* Saved Bus Mode Register      */
 	s32 csr6;                           /* Saved Operating Mode Reg.    */
 	s32 csr7;                           /* Saved IRQ Mask Register      */
@@ -703,6 +806,7 @@
     int (*infoleaf_fn)(struct device *);    /* Pointer to infoleaf function */
     u_char *rst;                            /* Pointer to Type 5 reset info */
     u_char  ibn;                            /* Infoblock number             */
+    struct parameters params;               /* Command line/ #defined params */
 };
 
 /*
@@ -784,11 +888,13 @@
 static int     dc21040_autoconf(struct device *dev);
 static int     dc21041_autoconf(struct device *dev);
 static int     dc21140m_autoconf(struct device *dev);
+static int     dc2114x_autoconf(struct device *dev);
 static int     srom_autoconf(struct device *dev);
 static int     de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
 static int     dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
 static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
-static int     test_sym_link(struct device *dev, int msec);
+static int     test_for_100Mb(struct device *dev, int msec);
+static int     wait_for_link(struct device *dev);
 static int     test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec);
 static int     is_spd_100(struct device *dev);
 static int     is_100_up(struct device *dev);
@@ -799,7 +905,7 @@
 static void    de4x5_free_rx_buffs(struct device *dev);
 static void    de4x5_free_tx_buffs(struct device *dev);
 static void    de4x5_save_skbs(struct device *dev);
-static void    de4x5_restore_skbs(struct device *dev);
+static void    de4x5_rst_desc_ring(struct device *dev);
 static void    de4x5_cache_state(struct device *dev, int flag);
 static void    de4x5_put_cache(struct device *dev, struct sk_buff *skb);
 static void    de4x5_putb_cache(struct device *dev, struct sk_buff *skb);
@@ -813,6 +919,7 @@
 static int     EISA_signature(char *name, s32 eisa_id);
 static int     PCI_signature(char *name, struct bus_type *lp);
 static void    DevicePresent(u_long iobase);
+static void    enet_addr_rst(u_long aprom_addr);
 static int     de4x5_bad_srom(struct bus_type *lp);
 static short   srom_rd(u_long address, u_char offset);
 static void    srom_latch(u_int command, u_long address);
@@ -822,7 +929,7 @@
 /*static void    srom_busy(u_int command, u_long address);*/
 static void    sendto_srom(u_int command, u_long addr);
 static int     getfrom_srom(u_long addr);
-static void    srom_map_media(struct device *dev);
+static int     srom_map_media(struct device *dev);
 static int     srom_infoleaf_info(struct device *dev);
 static void    srom_init(struct device *dev);
 static void    srom_exec(struct device *dev, u_char *p);
@@ -841,20 +948,21 @@
 static int     get_hw_addr(struct device *dev);
 static void    srom_repair(struct device *dev, int card);
 static int     test_bad_enet(struct device *dev, int status);
-
+#ifndef __sparc_v9__
 static void    eisa_probe(struct device *dev, u_long iobase);
+#endif
 static void    pci_probe(struct device *dev, u_long iobase);
-static struct  device *alloc_device(struct device *dev, u_long iobase);
-static struct  device *insert_device(struct device *dev, u_long iobase,
-				     int (*init)(struct device *));
+static void    srom_search(int index);
 static char    *build_setup_frame(struct device *dev, int mode);
 static void    disable_ast(struct device *dev);
 static void    enable_ast(struct device *dev, u32 time_out);
 static long    de4x5_switch_mac_port(struct device *dev);
+static int     gep_rd(struct device *dev);
+static void    gep_wr(s32 data, struct device *dev);
 static void    timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec);
 static void    yawn(struct device *dev, int state);
-static int     de4x5_dev_index(char *s);
 static void    link_modules(struct device *dev, struct device *tmp);
+static void    de4x5_parse_params(struct device *dev);
 static void    de4x5_dbg_open(struct device *dev);
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
@@ -877,15 +985,27 @@
 int  init_module(void);
 void cleanup_module(void);
 static struct  device *unlink_modules(struct device *p);
-static int autoprobed = 0, loading_module = 1;
+static struct  device *insert_device(struct device *dev, u_long iobase,
+				     int (*init)(struct device *));
+static int count_adapters(void);
+static int loading_module = 1;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+MODULE_PARM(de4x5_debug, "i");
+MODULE_PARM(dec_only, "i");
+MODULE_PARM(args, "s");
+#endif /* LINUX_VERSION_CODE */
 # else
-static int autoprobed = 0, loading_module = 0;
+static int loading_module = 0;
 #endif /* MODULE */
 
 static char name[DE4X5_NAME_LENGTH + 1];
+#ifndef __sparc_v9__
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
-static int num_de4x5s = 0, num_eth = 0;
+#endif
+static int num_de4x5s = 0;
 static int cfrv = 0, useSROM = 0;
+static int lastEISA = 0, lastPCI = -1;
+static struct device *lastModule = NULL;
 
 /*
 ** List the SROM infoleaf functions and chipsets
@@ -942,32 +1062,23 @@
 
 /*
 ** Autoprobing in modules is allowed here. See the top of the file for
-** more info. Until I fix (un)register_netdevice() we won't be able to use it
-** though.
+** more info.
 */
-int
-de4x5_probe(struct device *dev)
+__initfunc(int
+de4x5_probe(struct device *dev))
 {
-    int status = -ENODEV;
     u_long iobase = dev->base_addr;
 
+#ifndef __sparc_v9__
     eisa_probe(dev, iobase);
+#endif
     pci_probe(dev, iobase);
     
-    /*
-    ** Walk the device list to check that at least one device
-    ** initialised OK
-    */
-    for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
-    
-    if (dev->priv) status = 0;
-    if (iobase == 0) autoprobed = 1;
-
-    return status;
+    return (dev->priv ? 0 : -ENODEV);
 }
 
-static int
-de4x5_hw_init(struct device *dev, u_long iobase)
+__initfunc(static int
+de4x5_hw_init(struct device *dev, u_long iobase))
 {
     struct bus_type *lp = &bus;
     int i, status=0;
@@ -1053,33 +1164,34 @@
 	lp->timeout = -1;
 	lp->useSROM = useSROM;
 	memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
+	de4x5_parse_params(dev);
 
 	/*
 	** Choose correct autosensing in case someone messed up
 	*/
-	if ((de4x5_autosense & AUTO) || lp->useSROM) {
+	if ((lp->params.autosense & AUTO) || lp->useSROM) {
 	    lp->autosense = AUTO;
 	} else {
 	    if (lp->chipset != DC21140) {
-		if ((lp->chipset == DC21040) && (de4x5_autosense & TP_NW)) {
-		    de4x5_autosense = TP;
+		if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
+		    lp->params.autosense = TP;
 		}
-		if ((lp->chipset == DC21041) && (de4x5_autosense & BNC_AUI)) {
-		    de4x5_autosense = BNC;
+		if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
+		    lp->params.autosense = BNC;
 		}
-		lp->autosense = de4x5_autosense & 0x001f;
+		lp->autosense = lp->params.autosense & 0x001f;
 	    } else {
-		lp->autosense = de4x5_autosense & 0x00c0;
+		lp->autosense = lp->params.autosense & 0x00c0;
 	    }
 	}
-	lp->fdx = de4x5_full_duplex;
+	lp->fdx = lp->params.fdx;
 	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
 	
 	/*
 	** Set up the RX descriptor ring (Intels)
 	** Allocate contiguous receive buffers, long word aligned (Alphas) 
 	*/
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(DE4X5_DO_MEMCPY)
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
 	for (i=0; i<NUM_RX_DESC; i++) {
 	    lp->rx_ring[i].status = 0;
 	    lp->rx_ring[i].des1 = RX_BUFF_SZ;
@@ -1139,7 +1251,6 @@
 	/* Initialise the SROM pointers if possible */
 	if (lp->useSROM) {
 	    lp->state = INITIALISED;
-	    de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
 	    if (srom_infoleaf_info(dev)) {
 		return -ENXIO;
 	    }
@@ -1155,7 +1266,11 @@
 	    mii_get_phy(dev);
 	}
 	
+#ifndef __sparc_v9__
 	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
+#else
+	printk("      and requires IRQ%x (provided by %s).\n", dev->irq,
+#endif
 	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
     }
     
@@ -1190,7 +1305,7 @@
     u_long iobase = dev->base_addr;
     int i, status = 0;
     s32 omr;
-    
+
     /* Allocate the RX buffers */
     for (i=0; i<lp->rxRingSize; i++) {
 	if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
@@ -1229,6 +1344,7 @@
 	    printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
 	}
     }
+
     dev->tbusy = 0;                         
     dev->start = 1;
     dev->interrupt = UNMASK_INTERRUPTS;
@@ -1266,7 +1382,7 @@
 de4x5_init(struct device *dev)
 {  
     /* Lock out other processes whilst setting up the hardware */
-    set_bit(0, (void *)&dev->tbusy);
+    test_and_set_bit(0, (void *)&dev->tbusy);
     
     de4x5_sw_reset(dev);
     
@@ -1287,9 +1403,9 @@
     /* Select the MII or SRL port now and RESET the MAC */
     if (!lp->useSROM) {
 	if (lp->phy[lp->active].id != 0) {
-	    lp->infoblock_csr6 = OMR_PS | OMR_HBD;
+	    lp->infoblock_csr6 = OMR_SDP | OMR_PS | OMR_HBD;
 	} else {
-	    lp->infoblock_csr6 = OMR_TTM;
+	    lp->infoblock_csr6 = OMR_SDP | OMR_TTM;
 	}
 	de4x5_switch_mac_port(dev);
     }
@@ -1300,8 +1416,9 @@
     ** without these values. Cache align 16 long.
     */
     bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
+    bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0);
     outl(bmr, DE4X5_BMR);
-    
+
     omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
     if (lp->chipset == DC21140) {
 	omr |= (OMR_SDP | OMR_SB);
@@ -1322,13 +1439,13 @@
     }
     
     barrier();
-    
+
     /* Build the setup frame depending on filtering mode */
     SetMulticastFilter(dev);
     
     load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
     outl(omr|OMR_ST, DE4X5_OMR);
-    
+
     /* Poll for setup frame completion (adapter interrupts are disabled now) */
     sti();                                       /* Ensure timer interrupts */
     for (j=0, i=0;(i<500) && (j==0);i++) {       /* Upto 500ms delay */
@@ -1336,7 +1453,7 @@
 	if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
     }
     outl(omr, DE4X5_OMR);                        /* Stop everything! */
-    
+
     if (j == 0) {
 	printk("%s: Setup frame timed out, status %08x\n", dev->name, 
 	       inl(DE4X5_STS));
@@ -1345,7 +1462,7 @@
     
     lp->tx_new = (++lp->tx_new) % lp->txRingSize;
     lp->tx_old = lp->tx_new;
-    
+
     return status;
 }
 
@@ -1359,12 +1476,7 @@
     u_long iobase = dev->base_addr;
     int status = 0;
 
-    if (skb == NULL) {
-	dev_tint(dev);
-	return 0;
-    }
-
-    set_bit(0, (void*)&dev->tbusy);              /* Stop send re-tries */
+    test_and_set_bit(0, (void*)&dev->tbusy);     /* Stop send re-tries */
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
 	return -1;                                
     }
@@ -1379,7 +1491,8 @@
     sti();
 
     /* Test if cache is already locked - requeue skb if so */
-    if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
+    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) 
+	return -1;
 
     /* Transmit descriptor ring full or stale skb */
     if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
@@ -1400,7 +1513,7 @@
 
 	while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
 	    cli();
-	    set_bit(0, (void*)&dev->tbusy);
+	    test_and_set_bit(0, (void*)&dev->tbusy);
 	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
 #if	LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
  	    lp->stats.tx_bytes += skb->len;
@@ -1488,7 +1601,7 @@
     }
 
     /* Load the TX ring with any locally stored packets */
-    if (!set_bit(0, (void *)&lp->cache.lock)) {
+    if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
 	while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
 	    de4x5_queue_pkt(de4x5_get_cache(dev), dev);
 	}
@@ -1660,7 +1773,7 @@
 de4x5_txur(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
+    u_long iobase = dev->base_addr;
     int omr;
 
     omr = inl(DE4X5_OMR);
@@ -1683,7 +1796,7 @@
 de4x5_rx_ovfc(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
+    u_long iobase = dev->base_addr;
     int omr;
 
     omr = inl(DE4X5_OMR);
@@ -1888,23 +2001,24 @@
     return;
 }
 
+#ifndef __sparc_v9__
 /*
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void
-eisa_probe(struct device *dev, u_long ioaddr)
+__initfunc(static void
+eisa_probe(struct device *dev, u_long ioaddr))
 {
     int i, maxSlots, status, device;
+    u_char irq;
     u_short vendor;
     u32 cfid;
     u_long iobase;
     struct bus_type *lp = &bus;
     char name[DE4X5_STRLEN];
-    struct device *tmp;
-    
-    if (autoprobed) return;                /* Been here before ! */
-    
+
+    if (lastEISA == MAX_EISA_SLOTS) return;/* No more EISA devices to search */
+
     lp->bus = EISA;
     
     if (ioaddr == 0) {                     /* Autoprobing */
@@ -1917,7 +2031,7 @@
 	maxSlots = i + 1;
     }
     
-    for (status= -ENODEV;(i<maxSlots)&&(dev!=NULL);i++,iobase+=EISA_SLOT_INC) {
+    for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
 	if (EISA_signature(name, EISA_ID)) {
 	    cfid = (u32) inl(PCI_CFID);
 	    cfrv = (u_short) inl(PCI_CFRV);
@@ -1925,34 +2039,37 @@
 	    vendor = (u_short) cfid;
 	    
 	    /* Read the EISA Configuration Registers */
-	    dev->irq = inb(EISA_REG0);
-	    dev->irq = de4x5_irq[(dev->irq >> 1) & 0x03];
+	    irq = inb(EISA_REG0);
+	    irq = de4x5_irq[(irq >> 1) & 0x03];
 
-	    if (is_DC2114x) device |= (cfrv & 0x00f0);
+	    if (is_DC2114x) device |= (cfrv & CFRV_RN);
 	    lp->chipset = device;
-	    DevicePresent(DE4X5_APROM);
+
 	    /* Write the PCI Configuration Registers */
 	    outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
 	    outl(0x00006000, PCI_CFLT);
 	    outl(iobase, PCI_CBIO);
 	    
+	    DevicePresent(EISA_APROM);
 	    if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
-		if ((tmp = alloc_device(dev, iobase)) != NULL) {
-		    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
-			num_de4x5s++;
-			if (loading_module) link_modules(dev, tmp);
-		    } else if (loading_module && (tmp != dev)) {
-			kfree(tmp);
-		    }
+		dev->irq = irq;
+		if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+		    num_de4x5s++;
+		    if (loading_module) link_modules(lastModule, dev);
+		    lastEISA = i;
+		    return;
 		}
-	    } else if (autoprobed) {
+	    } else if (ioaddr != 0) {
 		printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase);
 	    }
 	}
     }
-    
+
+    if (ioaddr == 0) lastEISA = i;
+
     return;
 }
+#endif                         /* !(__sparc_v9__) */
 
 /*
 ** PCI bus I/O device probe
@@ -1969,23 +2086,25 @@
 #define PCI_DEVICE    (dev_num << 3)
 #define PCI_LAST_DEV  32
 
-static void
-pci_probe(struct device *dev, u_long ioaddr)
+__initfunc(static void
+pci_probe(struct device *dev, u_long ioaddr))
 {
-    u_char irq;
-    u_char pb, pbus, dev_num, dnum, dev_fn;
+    u_char pb, pbus, dev_num, dnum, dev_fn, timer, tirq;
     u_short dev_id, vendor, index, status;
-    u_int class = DE4X5_CLASS_CODE;
-    u_int device, iobase;
+    u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE;
+    u_long iobase = 0;                     /* Clear upper 32 bits in Alphas */
     struct bus_type *lp = &bus;
-    struct device *tmp;
 
-    if (autoprobed) return;
-    
-    if (!pcibios_present()) return;          /* No PCI bus in this machine! */
+    if (lastPCI == NO_MORE_PCI) return;
+
+    if (!pcibios_present()) {
+	lastPCI = NO_MORE_PCI;
+	return;          /* No PCI bus in this machine! */
+    }
     
     lp->bus = PCI;
-    
+    lp->bus_num = 0;
+
     if ((ioaddr < 0x1000) && loading_module) {
 	pbus = (u_short)(ioaddr >> 8);
 	dnum = (u_short)(ioaddr & 0xff);
@@ -1994,12 +2113,17 @@
 	dnum = 0;
     }
 
-    for (index=0; 
+    for (index=lastPCI+1; 
 	 (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
 	 index++) {
 	dev_num = PCI_SLOT(dev_fn);
-
 	if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
+#ifdef __sparc_v9__
+	    struct pci_dev *pdev;
+	    for (pdev = pci_devices; pdev; pdev = pdev->next) {
+		if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
+	    }
+#endif
 	    device = 0;
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
@@ -2009,6 +2133,12 @@
 		continue;
 	    }
 
+	    /* Search for an SROM on this bus */
+	    if (lp->bus_num != pb) {
+		lp->bus_num = pb;
+		srom_search(index);
+	    }
+
 	    /* Get the chip configuration revision register */
 	    pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
 
@@ -2017,25 +2147,38 @@
 	    lp->bus_num = pb;
 	    
 	    /* Set the chipset information */
-	    if (is_DC2114x) device |= (cfrv & 0x00f0);
+	    if (is_DC2114x) device |= (cfrv & CFRV_RN);
 	    lp->chipset = device;
 
-	    if (is_DC21142 || is_DC21143) {
-		printk("de4x5: Detected a %s chip. Currently this is unsupported in this driver.\nPlease email the author to request its inclusion!\n", (is_DC21142?"DC21142":"DC21143"));
-		continue;
-	    }
-
-	    /* Get the board I/O address */
-	    pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
+	    /* Get the board I/O address (64 bits on sparc64) */
+#ifndef __sparc_v9__
+	    pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
+	    iobase = tmp;
+#else
+	    iobase = pdev->base_address[0];
+#endif
 	    iobase &= CBIO_MASK;
 
 	    /* Fetch the IRQ to be used */
-	    pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
-	    if ((irq == 0) || (irq == (u_char) 0xff)) continue;
+#ifndef __sparc_v9__
+	    pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
+	    irq = tirq;
+#else
+	    irq = pdev->irq;
+#endif
+	    if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
 	    
 	    /* Check if I/O accesses and Bus Mastering are enabled */
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+#ifdef __powerpc__
+	    if (!(status & PCI_COMMAND_IO)) {
+		status |= PCI_COMMAND_IO;
+		pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+		pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+	    }
+#endif /* __powerpc__ */
 	    if (!(status & PCI_COMMAND_IO)) continue;
+
 	    if (!(status & PCI_COMMAND_MASTER)) {
 		status |= PCI_COMMAND_MASTER;
 		pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
@@ -2043,131 +2186,126 @@
 	    }
 	    if (!(status & PCI_COMMAND_MASTER)) continue;
 
+	    /* Check the latency timer for values >= 0x60 */
+	    pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer);
+	    if (timer < 0x60) {
+		pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60);
+	    }
+
 	    DevicePresent(DE4X5_APROM);
 	    if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
-		if ((tmp = alloc_device(dev, iobase)) != NULL) {
-		    tmp->irq = irq;
-		    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
-			num_de4x5s++;
-			if (loading_module) link_modules(dev, tmp);
-		    } else if (loading_module && (tmp != dev)) {
-			kfree(tmp);
+		dev->irq = irq;
+		if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+		    num_de4x5s++;
+		    if (loading_module) {
+			link_modules(lastModule, dev);
+			lastPCI = index;
 		    }
+		    return;
 		}
-	    } else if (autoprobed) {
-		printk("%s: region already allocated at 0x%04x.\n", dev->name, 
-		       (u_short)iobase);
+	    } else if (ioaddr != 0) {
+		printk("%s: region already allocated at 0x%04lx.\n", dev->name,
+		       iobase);
 	    }
 	}
     }
-    
+
+    if (loading_module) lastPCI = NO_MORE_PCI;
+
     return;
 }
 
 /*
-** Search the entire 'eth' device list for a fixed probe. If a match isn't
-** found then check for an autoprobe or unused device location. If they
-** are not available then insert a new device structure at the end of
-** the current list.
+** This function searches the current bus (which is >0) for a DECchip with an
+** SROM, so that in multiport cards that have one SROM shared between multiple 
+** DECchips, we can find the base SROM irrespective of the BIOS scan direction.
+** For single port cards this is a time waster...
 */
-static struct device *
-alloc_device(struct device *dev, u_long iobase)
+__initfunc(static void
+srom_search(int index))
 {
-    struct device *adev = NULL;
-    int fixed = 0, new_dev = 0;
+    u_char pb, dev_fn, tirq;
+    u_short dev_id, dev_num, vendor, status;
+    u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE;
+    u_long iobase = 0;                     /* Clear upper 32 bits in Alphas */
+    int i, j;
+    struct bus_type *lp = &bus;
 
-    if (!dev) return dev;
-    num_eth = de4x5_dev_index(dev->name);
+    for (; 
+	 (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+	 index++) {
 
-    if (loading_module) {
-	if (dev->priv) {
-	    dev = insert_device(dev, iobase, de4x5_probe);
+	if (lp->bus_num != pb) return;
+	dev_num = PCI_SLOT(dev_fn);
+#ifdef __sparc_v9__
+	struct pci_dev *pdev;
+	for (pdev = pci_devices; pdev; pdev = pdev->next) {
+	    if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break;
 	}
-	num_eth++;
-	return dev;
-    }
-
-    while (1) {
-	if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) {
-	    adev=dev;
-	} else if ((dev->priv == NULL) && (dev->base_addr==iobase)) {
-	    fixed = 1;
-	} else {
-	    if (dev->next == NULL) {
-		new_dev = 1;
-	    } else if (strncmp(dev->next->name, "eth", 3) != 0) {
-		new_dev = 1;
-	    }
+#endif
+	device = 0;
+	pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
+	pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+	device = dev_id;
+	device <<= 8;
+	if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
+	    continue;
 	}
-	if ((dev->next == NULL) || new_dev || fixed) break;
-	dev = dev->next;
-	num_eth++;
-    }
-    if (adev && !fixed) {
-	dev = adev;
-	num_eth = de4x5_dev_index(dev->name);
-	new_dev = 0;
-    }
-
-    if (((dev->next == NULL) &&  
-	((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) ||
-	new_dev) {
-	num_eth++;                         /* New device */
-	dev = insert_device(dev, iobase, de4x5_probe);
-    }
-    
-    return dev;
-}
 
-/*
-** If at end of eth device list and can't use current entry, malloc
-** one up. If memory could not be allocated, print an error message.
-*/
-static struct device *
-insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))
-{
-    struct device *new;
+	/* Get the chip configuration revision register */
+	pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+
+	/* Set the device number information */
+	lp->device = dev_num;
+	lp->bus_num = pb;
+	    
+	/* Set the chipset information */
+	if (is_DC2114x) device |= (cfrv & CFRV_RN);
+	lp->chipset = device;
+
+	/* Get the board I/O address (64 bits on sparc64) */
+#ifndef __sparc_v9__
+	pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
+	iobase = tmp;
+#else
+	iobase = pdev->base_address[0];
+#endif
+	iobase &= CBIO_MASK;
 
-    new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
-    if (new == NULL) {
-	printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
-	return NULL;
-    } else {
-	memset((char *)new, 0, sizeof(struct device)+8);
-	new->name = (char *)(new + 1);
-	new->base_addr = iobase;       /* assign the io address */
-	new->init = init;              /* initialisation routine */
-	if (!loading_module) {
-	    new->next = dev->next;
-	    dev->next = new;
-	    if (num_eth > 9999) {
-		sprintf(new->name,"eth????");/* New device name */
-	    } else {
-		sprintf(new->name,"eth%d", num_eth);/* New device name */
+	/* Fetch the IRQ to be used */
+#ifndef __sparc_v9__
+	pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
+	irq = tirq;
+#else
+	irq = pdev->irq;
+#endif
+	if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+	    
+	/* Check if I/O accesses are enabled */
+	pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+	if (!(status & PCI_COMMAND_IO)) continue;
+
+	/* Search for a valid SROM attached to this DECchip */
+	DevicePresent(DE4X5_APROM);
+	for (j=0, i=0; i<ETH_ALEN; i++) {
+	    j += (u_char) *((u_char *)&lp->srom + SROM_HWADD + i);
+	}
+	if ((j != 0) && (j != 0x5fa)) {
+	    last.chipset = device;
+	    last.bus = pb;
+	    last.irq = irq;
+	    for (i=0; i<ETH_ALEN; i++) {
+		last.addr[i] = (u_char)*((u_char *)&lp->srom + SROM_HWADD + i);
 	    }
+	    return;
 	}
     }
 
-    return new;
-}
-
-static int
-de4x5_dev_index(char *s)
-{
-    int i=0, j=0;
-
-    for (;*s; s++) {
-	if (isdigit(*s)) {
-	    j=1;
-	    i = (i * 10) + (*s - '0');
-	} else if (j) break;
-    }
-
-    return i;
+    return;
 }
 
-static void
-link_modules(struct device *dev, struct device *tmp)
+__initfunc(static void
+link_modules(struct device *dev, struct device *tmp))
 {
     struct device *p=dev;
 
@@ -2198,13 +2336,15 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int next_tick = DE4X5_AUTOSENSE_MS;;
-    
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
     lp->linkOK = 0;
     lp->c_media = AUTO;                     /* Bogus last media */
     disable_ast(dev);
     inl(DE4X5_MFC);                         /* Zero the lost frames counter */
     lp->media = INIT;
+    lp->tcount = 0;
+
     if (lp->useSROM) {
 	next_tick = srom_autoconf(dev);
     } else if (lp->chipset == DC21040) {
@@ -2592,9 +2732,9 @@
 dc21140m_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int ana, anlpa, cap, cr, slnk, sr, iobase = dev->base_addr;
+    int ana, anlpa, cap, cr, slnk, sr;
     int next_tick = DE4X5_AUTOSENSE_MS;
-    u_long imr, omr;
+    u_long imr, omr, iobase = dev->base_addr;
 
     switch(lp->media) {
       case INIT: 
@@ -2608,7 +2748,10 @@
 	    next_tick &= ~TIMER_CB;
 	} else {
 	    if (lp->useSROM) {
-		srom_map_media(dev);
+		if (srom_map_media(dev) < 0) {
+		    lp->tcount++;
+		    return next_tick;
+		}
 		srom_exec(dev, lp->phy[lp->active].gep);
 		if (lp->infoblock_media == ANS) {
 		    ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
@@ -2690,11 +2833,11 @@
 	
       case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
         if (lp->timeout < 0) {
-	    lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
-		                                  (~inl(DE4X5_GEP) & GEP_LNP));
+	    lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : 
+		                                  (~gep_rd(dev) & GEP_LNP));
 	    SET_100Mb_PDET;
 	}
-        if ((slnk = test_sym_link(dev, 6200)) < 0) {
+        if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
 	    next_tick = slnk & ~TIMER_CB;
 	} else {
 	    if (is_spd_100(dev) && is_100_up(dev)) {
@@ -2715,7 +2858,7 @@
 	    de4x5_init_connection(dev);
 	} else {
 	    if (!lp->linkOK && (lp->autosense == AUTO)) {
-		if (!(is_spd_100(dev) && is_100_up(dev))) {
+		if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
 		    lp->media = INIT;
 		    lp->tcount++;
 		    next_tick = DE4X5_AUTOSENSE_MS;
@@ -2731,7 +2874,7 @@
 	    de4x5_init_connection(dev);
 	} else {
 	    if (!lp->linkOK && (lp->autosense == AUTO)) {
-		if (!(!is_spd_100(dev) && is_10_up(dev))) {
+		if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
 		    lp->media = INIT;
 		    lp->tcount++;
 		    next_tick = DE4X5_AUTOSENSE_MS;
@@ -2753,96 +2896,343 @@
     return next_tick;
 }
 
-static int
-srom_autoconf(struct device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
-    return lp->infoleaf_fn(dev);
-}
-
 /*
-** This mapping keeps the original media codes and FDX flag unchanged.
-** While it isn't strictly necessary, it helps me for the moment...
+** This routine may be merged into dc21140m_autoconf() sometime as I'm
+** changing how I figure out the media - but trying to keep it backwards
+** compatible with the de500-xa and de500-aa.
+** Whether it's BNC, AUI, SYM or MII is sorted out in the infoblock
+** functions and set during de4x5_mac_port() and/or de4x5_reset_phy().
+** This routine just has to figure out whether 10Mb/s or 100Mb/s is
+** active.
+** When autonegotiation is working, the ANS part searches the SROM for
+** the highest common speed (TP) link that both can run and if that can
+** be full duplex. That infoblock is executed and then the link speed set.
+**
+** Only _10Mb and _100Mb are tested here.
 */
-static void
-srom_map_media(struct device *dev)
+static int
+dc2114x_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts;
+    int next_tick = DE4X5_AUTOSENSE_MS;
 
-    lp->fdx = 0;
-    switch(lp->infoblock_media) {
-      case SROM_10BASETF:
-	lp->fdx = TRUE;
-      case SROM_10BASET:
-	if (lp->chipset == DC21140) {
-	    lp->media = _10Mb;
-	} else {
-	    lp->media = TP;
+    switch (lp->media) {
+      case INIT:
+        if (lp->timeout < 0) {
+	    DISABLE_IRQs;
+	    lp->tx_enable = FALSE;
+	    lp->linkOK = 0;
+            lp->timeout = -1;
+	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
 	}
+	if ((next_tick = de4x5_reset_phy(dev)) < 0) {
+	    next_tick &= ~TIMER_CB;
+	} else {
+            lp->media = SPD_DET;
+	    if ((lp->infoblock_media == ANS) && 
+		                    ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+		    ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+		    ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		    lp->media = ANS;
+	    }
+	    lp->local_state = 0;
+	    next_tick = dc2114x_autoconf(dev);
+        }
 	break;
-
-      case SROM_10BASE2:
-	lp->media = BNC;
-	break;
-
-      case SROM_10BASE5:
-	lp->media = AUI;
-	break;
-
-      case SROM_100BASETF:
-	lp->fdx = TRUE;
-      case SROM_100BASET:
-	lp->media = _100Mb;
-	break;
-
-      case SROM_100BASET4:
-	lp->media = _100Mb;
-	break;
-
-      case SROM_100BASEFF:
-	lp->fdx = TRUE;
-      case SROM_100BASEF: 
-	lp->media = _100Mb;
-	break;
-
+	
       case ANS:
-	lp->media = ANS;
-	break;
-
-      default: 
-	printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
-	                                                  lp->infoblock_media);
-	break;
-    }
-
-    return;
-}
-
-static void
-de4x5_init_connection(struct device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    if (lp->media != lp->c_media) {
-        de4x5_dbg_media(dev);
-	lp->c_media = lp->media;          /* Stop scrolling media messages */
-    }
-
-    cli();
-    de4x5_restore_skbs(dev);
-    de4x5_setup_intr(dev);
-    lp->tx_enable = YES;
-    dev->tbusy = 0;
-    sti();
-    outl(POLL_DEMAND, DE4X5_TPD);
-    mark_bh(NET_BH);
-
-    return;
-}
-
-/*
+	switch (lp->local_state) {
+	  case 0:
+	    if (lp->timeout < 0) {
+		mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+	    }
+	    cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+	    if (cr < 0) {
+		next_tick = cr & ~TIMER_CB;
+	    } else {
+		if (cr) {
+		    lp->local_state = 0;
+		    lp->media = SPD_DET;
+		} else {
+		    lp->local_state++;
+		}
+		next_tick = dc2114x_autoconf(dev);
+	    }
+	    break;
+	    
+	  case 1:
+	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+		next_tick = sr & ~TIMER_CB;
+	    } else {
+		lp->media = SPD_DET;
+		lp->local_state = 0;
+		if (sr) {                         /* Success! */
+		    lp->tmp = MII_SR_ASSC;
+		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
+		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		    if (!(anlpa & MII_ANLPA_RF) && 
+			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
+			if (cap & MII_ANA_100M) {
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+			    lp->media = _100Mb;
+			} else if (cap & MII_ANA_10M) {
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+			    lp->media = _10Mb;
+			}
+		    }
+		}                       /* Auto Negotiation failed to finish */
+		next_tick = dc2114x_autoconf(dev);
+	    }                           /* Auto Negotiation failed to start */
+	    break;
+	}
+	break;
+	
+      case AUI:
+	if (!lp->tx_enable) {
+	    if (lp->timeout < 0) {
+		omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
+	    }
+	    irqs = 0;
+	    irq_mask = 0;
+	    sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+		    lp->media = BNC;
+		    next_tick = dc2114x_autoconf(dev);
+		} else {
+		    lp->local_state = 1;
+		    de4x5_init_connection(dev);
+		}
+	    }
+	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
+	    lp->media = AUI_SUSPECT;
+	    next_tick = 3000;
+	}
+	break;
+	
+      case AUI_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
+	break;
+	
+      case BNC:
+	switch (lp->local_state) {
+	  case 0:
+	    if (lp->timeout < 0) {
+		omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
+	    }
+	    irqs = 0;
+	    irq_mask = 0;
+	    sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		lp->local_state++;             /* Ensure media connected */
+		next_tick = dc2114x_autoconf(dev);
+	    }
+	    break;
+	    
+	  case 1:
+	    if (!lp->tx_enable) {
+		if ((sts = ping_media(dev, 3000)) < 0) {
+		    next_tick = sts & ~TIMER_CB;
+		} else {
+		    if (sts) {
+			lp->local_state = 0;
+			lp->tcount++;
+			lp->media = INIT;
+		    } else {
+			de4x5_init_connection(dev);
+		    }
+		}
+	    } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+		lp->media = BNC_SUSPECT;
+		next_tick = 3000;
+	    }
+	    break;
+	}
+	break;
+	
+      case BNC_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
+	break;
+	
+      case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
+	  if (srom_map_media(dev) < 0) {
+	      lp->tcount++;
+	      lp->media = INIT;
+	      return next_tick;
+	  }
+	  if (lp->media == _100Mb) {
+	      if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
+		  lp->media = SPD_DET;
+		  return  (slnk & ~TIMER_CB);
+	      }
+	  } else {
+	      if (wait_for_link(dev) < 0) {
+		  lp->media = SPD_DET;
+		  return PDET_LINK_WAIT;
+	      }
+	  } 
+	  if (((lp->media == _100Mb) && is_100_up(dev)) ||
+	      ((lp->media == _10Mb)  && is_10_up(dev)) ||
+	       (lp->media == BNC) || (lp->media == AUI)) {
+	      next_tick = dc2114x_autoconf(dev);
+	  } else {
+	      lp->tcount++;
+	      lp->media = INIT;
+	  }
+	  break;
+	
+      case _10Mb:
+        next_tick = 3000;
+	if (!lp->tx_enable) {
+	    SET_10Mb;
+	    de4x5_init_connection(dev);
+	} else {
+	    if (!lp->linkOK && (lp->autosense == AUTO)) {
+		if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
+		    lp->media = INIT;
+		    lp->tcount++;
+		    next_tick = DE4X5_AUTOSENSE_MS;
+		}
+	    }
+	}
+	break;
+
+      case _100Mb:
+        next_tick = 3000;
+	if (!lp->tx_enable) {
+	    SET_100Mb;
+	    de4x5_init_connection(dev);
+	} else {
+	    if (!lp->linkOK && (lp->autosense == AUTO)) {
+		if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
+		    lp->media = INIT;
+		    lp->tcount++;
+		    next_tick = DE4X5_AUTOSENSE_MS;
+		}
+	    }
+	}
+	break;
+
+      default:
+	lp->tcount++;
+printk("Huh?: media:%02x\n", lp->media);
+	lp->media = INIT;
+	break;
+    }
+    
+    return next_tick;
+}
+
+static int
+srom_autoconf(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    return lp->infoleaf_fn(dev);
+}
+
+/*
+** This mapping keeps the original media codes and FDX flag unchanged.
+** While it isn't strictly necessary, it helps me for the moment...
+** The early return avoids a media state / SROM media space clash.
+*/
+static int
+srom_map_media(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    lp->fdx = 0;
+    if (lp->infoblock_media == lp->media) 
+      return 0;
+
+    switch(lp->infoblock_media) {
+      case SROM_10BASETF:
+	if (!lp->params.fdx) return -1;
+	lp->fdx = TRUE;
+      case SROM_10BASET:
+	if (lp->params.fdx && !lp->fdx) return -1;
+	if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
+	    lp->media = _10Mb;
+	} else {
+	    lp->media = TP;
+	}
+	break;
+
+      case SROM_10BASE2:
+	lp->media = BNC;
+	break;
+
+      case SROM_10BASE5:
+	lp->media = AUI;
+	break;
+
+      case SROM_100BASETF:
+        if (!lp->params.fdx) return -1;
+	lp->fdx = TRUE;
+      case SROM_100BASET:
+	if (lp->params.fdx && !lp->fdx) return -1;
+	lp->media = _100Mb;
+	break;
+
+      case SROM_100BASET4:
+	lp->media = _100Mb;
+	break;
+
+      case SROM_100BASEFF:
+	if (!lp->params.fdx) return -1;
+	lp->fdx = TRUE;
+      case SROM_100BASEF: 
+	if (lp->params.fdx && !lp->fdx) return -1;
+	lp->media = _100Mb;
+	break;
+
+      case ANS:
+	lp->media = ANS;
+	break;
+
+      default: 
+	printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
+	                                                  lp->infoblock_media);
+	return -1;
+	break;
+    }
+
+    return 0;
+}
+
+static void
+de4x5_init_connection(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    if (lp->media != lp->c_media) {
+        de4x5_dbg_media(dev);
+	lp->c_media = lp->media;          /* Stop scrolling media messages */
+    }
+
+    cli();
+    de4x5_rst_desc_ring(dev);
+    de4x5_setup_intr(dev);
+    lp->tx_enable = YES;
+    dev->tbusy = 0;
+    sti();
+    outl(POLL_DEMAND, DE4X5_TPD);
+    mark_bh(NET_BH);
+
+    return;
+}
+
+/*
 ** General PHY reset function. Some MII devices don't reset correctly
 ** since their MII address pins can float at voltages that are dependent
 ** on the signal pin use. Do a double reset to ensure a reset.
@@ -2857,7 +3247,7 @@
     if ((lp->useSROM) || (lp->phy[lp->active].id)) {
 	if (lp->timeout < 0) {
 	    if (lp->useSROM) {
-		if (lp->phy[lp->active].rst) { /* MII device specific reset */
+		if (lp->phy[lp->active].rst) {
 		    srom_exec(dev, lp->phy[lp->active].rst);
 		    srom_exec(dev, lp->phy[lp->active].rst);
 		} else if (lp->rst) {          /* Type 5 infoblock reset */
@@ -2890,7 +3280,9 @@
     
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
-	reset_init_sia(dev, csr13, csr14, csr15);
+	if (!lp->useSROM) {      /* Already done if by SROM, else dc2104[01] */
+	    reset_init_sia(dev, csr13, csr14, csr15);
+	}
 
 	/* set up the interrupt mask */
 	outl(irq_mask, DE4X5_IMR);
@@ -2900,7 +3292,7 @@
 	outl(sts, DE4X5_STS);
 	
 	/* clear csr12 NRA and SRA bits */
-	if (lp->chipset == DC21041) {
+	if ((lp->chipset == DC21041) || lp->useSROM) {
 	    csr12 = inl(DE4X5_SISR);
 	    outl(csr12, DE4X5_SISR);
 	}
@@ -2939,24 +3331,37 @@
     return sisr;
 }
 
+/*
+** Samples the 100Mb Link State Signal. The sample interval is important
+** because too fast a rate can give erroneous results and confuse the
+** speed sense algorithm.
+*/
+#define SAMPLE_INTERVAL 500  /* ms */
+#define SAMPLE_DELAY    2000 /* ms */
 static int
-test_sym_link(struct device *dev, int msec)
+test_for_100Mb(struct device *dev, int msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
-    int gep = 0;
-    
+    int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK);
+
     if (lp->timeout < 0) {
-	lp->timeout = msec/100;
+	if ((msec/SAMPLE_INTERVAL) <= 0) return 0;
+	if (msec > SAMPLE_DELAY) {
+	    lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL;
+	    gep = SAMPLE_DELAY | TIMER_CB;
+	    return gep;
+	} else {
+	    lp->timeout = msec/SAMPLE_INTERVAL;
+	}
     }
     
     if (lp->phy[lp->active].id || lp->useSROM) {
-	gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0);
+	gep = is_100_up(dev) | is_spd_100(dev);
     } else {
-	gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP));
+	gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP));
     }
-    if (!(gep & GEP_SLNK) && --lp->timeout) {
-	gep = 100 | TIMER_CB;
+    if (!(gep & ret) && --lp->timeout) {
+	gep = SAMPLE_INTERVAL | TIMER_CB;
     } else {
 	lp->timeout = -1;
     }
@@ -2964,6 +3369,24 @@
     return gep;
 }
 
+static int
+wait_for_link(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    if (lp->timeout < 0) {
+	lp->timeout = 1;
+    }
+    
+    if (lp->timeout--) {
+	return TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return 0;
+}
+
 /*
 **
 **
@@ -2972,7 +3395,8 @@
 test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int test, iobase = dev->base_addr;
+    int test;
+    u_long iobase = dev->base_addr;
     
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
@@ -2998,16 +3422,18 @@
     u_long iobase = dev->base_addr;
     int spd;
     
-    if (lp->useSROM && !lp->useMII) {
-	spd = (lp->asBitValid & 
-	       (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
- 		 (lp->linkOK & ~lp->asBitValid);
-    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+    if (lp->useMII) {
 	spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
 	spd = ~(spd ^ lp->phy[lp->active].spd.value);
 	spd &= lp->phy[lp->active].spd.mask;
+    } else if (!lp->useSROM) {                      /* de500-xa */
+	spd = ((~gep_rd(dev)) & GEP_SLNK);
     } else {
-	spd = ((~inl(DE4X5_GEP)) & GEP_SLNK);
+	if ((lp->ibn == 2) || !lp->asBitValid)
+	    return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+	spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
+	          (lp->linkOK & ~lp->asBitValid);
     }
     
     return spd;
@@ -3019,16 +3445,18 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     
-    if (lp->useSROM && !lp->useMII) {
-	return ((lp->asBitValid & 
-		 (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
-		(lp->linkOK & ~lp->asBitValid));
-    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+    if (lp->useMII) {
 	/* Double read for sticky bits & temporary drops */
 	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
 	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+    } else if (!lp->useSROM) {                       /* de500-xa */
+	return ((~gep_rd(dev)) & GEP_SLNK);
     } else {
-	return ((~inl(DE4X5_GEP)) & GEP_SLNK);
+	if ((lp->ibn == 2) || !lp->asBitValid)
+	    return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+        return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+		(lp->linkOK & ~lp->asBitValid));
     }
 }
 
@@ -3038,16 +3466,20 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     
-    if (lp->useSROM && !lp->useMII) {
-	return ((lp->asBitValid & 
-		 (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
-		(lp->linkOK & ~lp->asBitValid));
-    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+    if (lp->useMII) {
 	/* Double read for sticky bits & temporary drops */
 	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
 	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+    } else if (!lp->useSROM) {                       /* de500-xa */
+	return ((~gep_rd(dev)) & GEP_LNP);
     } else {
-	return ((~inl(DE4X5_GEP)) & GEP_LNP);
+	if ((lp->ibn == 2) || !lp->asBitValid)
+	    return (((lp->chipset & ~0x00ff) == DC2114x) ?
+		    (~inl(DE4X5_SISR)&SISR_LS10):
+		    0);
+
+	return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+		(lp->linkOK & ~lp->asBitValid));
     }
 }
 
@@ -3059,6 +3491,8 @@
     
     if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
 	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	return (inl(DE4X5_SISR) & SISR_LPN) >> 11;
     } else {
 	return 0;
     }
@@ -3115,7 +3549,7 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p;
 
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(DE4X5_DO_MEMCPY)
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
     struct sk_buff *ret;
     u_long i=0, tmp;
 
@@ -3228,7 +3662,7 @@
 }
 
 static void
-de4x5_restore_skbs(struct device *dev)
+de4x5_rst_desc_ring(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -3270,11 +3704,6 @@
 	lp->cache.csr0 = inl(DE4X5_BMR);
 	lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR));
 	lp->cache.csr7 = inl(DE4X5_IMR);
-	if (lp->chipset != DC21140) {
-	    lp->cache.csr13 = inl(DE4X5_SICR);
-	    lp->cache.csr14 = inl(DE4X5_STRR);
-	    lp->cache.csr15 = inl(DE4X5_SIGR);
-	}
 	break;
 
       case DE4X5_RESTORE_STATE:
@@ -3282,8 +3711,8 @@
 	outl(lp->cache.csr6, DE4X5_OMR);
 	outl(lp->cache.csr7, DE4X5_IMR);
 	if (lp->chipset == DC21140) {
-	    outl(lp->cache.gepc, DE4X5_GEP);
-	    outl(lp->cache.gep, DE4X5_GEP);
+	    gep_wr(lp->cache.gepc, dev);
+	    gep_wr(lp->cache.gep, dev);
 	} else {
 	    reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, 
 			                                      lp->cache.csr15);
@@ -3391,15 +3820,32 @@
 **
 */
 static void
-reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
+reset_init_sia(struct device *dev, s32 csr13, s32 csr14, s32 csr15)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    
+
     RESET_SIA;
-    outl(sigr, DE4X5_SIGR);
-    outl(strr, DE4X5_STRR);
-    outl(sicr, DE4X5_SICR);
+    if (lp->useSROM) {
+	if (lp->ibn == 3) {
+	    srom_exec(dev, lp->phy[lp->active].rst);
+	    srom_exec(dev, lp->phy[lp->active].gep);
+	    outl(1, DE4X5_SICR);
+	    return;
+	} else {
+	    csr15 = lp->cache.csr15;
+	    csr14 = lp->cache.csr14;
+	    csr13 = lp->cache.csr13;
+	    outl(csr15 | lp->cache.gepc, DE4X5_SIGR);
+	    outl(csr15 | lp->cache.gep, DE4X5_SIGR);
+	}
+    } else {
+	outl(csr15, DE4X5_SIGR);
+    }
+    outl(csr14, DE4X5_STRR);
+    outl(csr13, DE4X5_SICR);
+
+    de4x5_ms_delay(10);
 
     return;
 }
@@ -3522,6 +3968,8 @@
 	if (lp->chipset != DC21041) {
 	    useSROM = TRUE;             /* card is not recognisably DEC */
 	}
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	useSROM = TRUE;
     }
     
     return status;
@@ -3530,22 +3978,79 @@
 /*
 ** Set up the Ethernet PROM counter to the start of the Ethernet address on
 ** the DC21040, else  read the SROM for the other chips.
+** The SROM may not be present in a multi-MAC card, so first read the
+** MAC address and check for a bad address. If there is a bad one then exit
+** immediately with the prior srom contents intact (the h/w address will
+** be fixed up later).
 */
 static void
 DevicePresent(u_long aprom_addr)
 {
-    int i;
-    struct bus_type *lp = &bus;
+    int i, j=0;
+    struct bus_type *lp = &bus;
+    
+    if (lp->chipset == DC21040) {
+	if (lp->bus == EISA) {
+	    enet_addr_rst(aprom_addr); /* Reset Ethernet Address ROM Pointer */
+	} else {
+	    outl(0, aprom_addr);       /* Reset Ethernet Address ROM Pointer */
+	}
+    } else {                           /* Read new srom */
+	u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
+	for (i=0; i<(ETH_ALEN>>1); i++) {
+	    tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i);
+	    *p = le16_to_cpu(tmp);
+	    j += *p++;
+	}
+	if ((j == 0) || (j == 0x2fffd)) {
+	    return;
+	}
+
+	p=(short *)&lp->srom;
+	for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
+	    tmp = srom_rd(aprom_addr, i);
+	    *p++ = le16_to_cpu(tmp);
+	}
+	de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
+    }
+    
+    return;
+}
+
+/*
+** Since the write on the Enet PROM register doesn't seem to reset the PROM
+** pointer correctly (at least on my DE425 EISA card), this routine should do
+** it...from depca.c.
+*/
+static void
+enet_addr_rst(u_long aprom_addr)
+{
+    union {
+	struct {
+	    u32 a;
+	    u32 b;
+	} llsig;
+	char Sig[sizeof(u32) << 1];
+    } dev;
+    short sigLength=0;
+    s8 data;
+    int i, j;
     
-    if (lp->chipset == DC21040) {
-	outl(0, aprom_addr);           /* Reset Ethernet Address ROM Pointer */
-    } else {                           /* Read new srom */
-	u_short tmp, *p = (short *)&lp->srom;
-	for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
-	    tmp = srom_rd(aprom_addr, i);
-	    *p++ = le16_to_cpu(tmp);
+    dev.llsig.a = ETH_PROM_SIG;
+    dev.llsig.b = ETH_PROM_SIG;
+    sigLength = sizeof(u32) << 1;
+    
+    for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+	data = inb(aprom_addr);
+	if (dev.Sig[j] == data) {    /* track signature */
+	    j++;
+	} else {                     /* lost signature; begin search again */
+	    if (data == dev.Sig[0]) {  /* rare case.... */
+		j=1;
+	    } else {
+		j=0;
+	    }
 	}
-	de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
     }
     
     return;
@@ -3566,6 +4071,7 @@
     struct bus_type *lp = &bus;
 
     broken = de4x5_bad_srom(lp);
+
     for (i=0,k=0,j=0;j<3;j++) {
 	k <<= 1;
 	if (k > 0xffff) k-=0xffff;
@@ -3672,6 +4178,10 @@
     return;
 }
 
+/*
+** Assume that the irq's do not follow the PCI spec - this is seems
+** to be true so far (2 for 2).
+*/
 static int
 test_bad_enet(struct device *dev, int status)
 {
@@ -3688,10 +4198,8 @@
 		if (dev->dev_addr[i] != 0) break;
 	    }
 	    for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
-	    if (((*((int *)dev->dev_addr) & 0x00ffffff) == 0x95c000) &&
-		(lp->chipset == DC21040)) {
-		dev->irq = last.irq;
-	    }
+	    dev->irq = last.irq;
+
 	    status = 0;
 	}
     } else if (!status) {
@@ -3752,9 +4260,6 @@
     de4x5_us_delay(1);
     
     i = (getfrom_srom(addr) >> 3) & 0x01;
-    if (i != 0) {
-	printk("Bad SROM address phase.....\n");
-    }
     
     return;
 }
@@ -3867,14 +4372,13 @@
 srom_init(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
     u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
     u_char count;
 
     p+=2;
     if (lp->chipset == DC21140) {
 	lp->cache.gepc = (*p++ | GEP_CTRL);
-	outl(lp->cache.gepc, DE4X5_GEP);
+	gep_wr(lp->cache.gepc, dev);
     }
 
     /* Block count */
@@ -3887,9 +4391,13 @@
 	} else if (*(p+1) == 5) {
 	    type5_infoblock(dev, 1, p);
 	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 4) {
+	    p += ((*p & BLOCK_LEN) + 1);
 	} else if (*(p+1) == 3) {
 	    type3_infoblock(dev, 1, p);
 	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 2) {
+	    p += ((*p & BLOCK_LEN) + 1);
 	} else if (*(p+1) == 1) {
 	    type1_infoblock(dev, 1, p);
 	    p += ((*p & BLOCK_LEN) + 1);
@@ -3901,20 +4409,33 @@
     return;
 }
 
+/*
+** A generic routine that writes GEP control, data and reset information
+** to the GEP register (21140) or csr15 GEP portion (2114[23]).
+*/
 static void
 srom_exec(struct device *dev, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     u_char count = (p ? *p++ : 0);
+    u_short *w = (u_short *)p;
+
+    if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) return;
 
+    if (lp->chipset != DC21140) RESET_SIA;
+ 
     while (count--) {
-	if (lp->chipset == DC21140) {
-	    outl(*p++, DE4X5_GEP);
-	}
+	gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? 
+		                                   *p++ : TWIDDLE(w++)), dev);
 	udelay(2000);                       /* 2ms per action */
     }
 
+    if (lp->chipset != DC21140) {
+	outl(lp->cache.csr14, DE4X5_STRR);
+	outl(lp->cache.csr13, DE4X5_SICR);
+    }
+
     return;
 }
 
@@ -3970,15 +4491,70 @@
 static int 
 dc21142_infoleaf(struct device *dev)
 {
-printk("dc21142_infoleaf()\n");
-    return DE4X5_AUTOSENSE_MS;
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+	next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+	next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+
+    if (lp->tcount == count) {
+	lp->media = NC;
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tcount = 0;
+	lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
 }
 
 static int 
 dc21143_infoleaf(struct device *dev)
 {
-printk("dc21143_infoleaf()\n");
-    return DE4X5_AUTOSENSE_MS;
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+	next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+	next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+    if (lp->tcount == count) {
+	lp->media = NC;
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tcount = 0;
+	lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
 }
 
 /*
@@ -3989,7 +4565,6 @@
 compact_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
     u_char flags, csr6;
 
     /* Recursively figure out the info blocks */
@@ -4002,7 +4577,9 @@
     }
 
     if ((lp->media == INIT) && (lp->timeout < 0)) {
-        outl(lp->cache.gepc, DE4X5_GEP);
+        lp->ibn = COMPACT;
+        lp->active = 0;
+	gep_wr(lp->cache.gepc, dev);
 	lp->infoblock_media = (*p++) & COMPACT_MC;
 	lp->cache.gep = *p++;
 	csr6 = *p++;
@@ -4012,7 +4589,7 @@
 	lp->defMedium = (flags & 0x40) ? -1 : 0;
 	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
 	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-	lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
 	lp->useMII = FALSE;
 
 	de4x5_switch_mac_port(dev);
@@ -4023,12 +4600,11 @@
 
 /*
 ** This block describes non MII media for the DC21140[A] only.
- */
+*/
 static int 
 type0_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
     u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -4041,7 +4617,9 @@
     }
 
     if ((lp->media == INIT) && (lp->timeout < 0)) {
-        outl(lp->cache.gepc, DE4X5_GEP);
+        lp->ibn = 0;
+        lp->active = 0;
+        gep_wr(lp->cache.gepc, dev);
 	p+=2;
 	lp->infoblock_media = (*p++) & BLOCK0_MC;
 	lp->cache.gep = *p++;
@@ -4052,7 +4630,7 @@
 	lp->defMedium = (flags & 0x40) ? -1 : 0;
 	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
 	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-	lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
 	lp->useMII = FALSE;
 
 	de4x5_switch_mac_port(dev);
@@ -4080,7 +4658,6 @@
 
     p += 2;
     if (lp->state == INITIALISED) {
-	lp->ibn = 1;
 	lp->active = *p++;
 	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
 	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
@@ -4092,9 +4669,10 @@
     } else if ((lp->media == INIT) && (lp->timeout < 0)) {
         lp->ibn = 1;
         lp->active = *p;
-	lp->infoblock_csr6 = OMR_PS | OMR_HBD;
+	lp->infoblock_csr6 = OMR_MII_100;
 	lp->useMII = TRUE;
 	lp->infoblock_media = ANS;
+
 	de4x5_switch_mac_port(dev);
     }
 
@@ -4104,14 +4682,49 @@
 static int 
 type2_infoblock(struct device *dev, u_char count, u_char *p)
 {
-    return DE4X5_AUTOSENSE_MS;
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 2;
+        lp->active = 0;
+	p += 2;
+	lp->infoblock_media = (*p) & MEDIA_CODE;
+
+        if ((*p++) & EXT_FIELD) {
+	    lp->cache.csr13 = TWIDDLE(p); p += 2;
+	    lp->cache.csr14 = TWIDDLE(p); p += 2;
+	    lp->cache.csr15 = TWIDDLE(p); p += 2;
+	} else {
+	    lp->cache.csr13 = CSR13;
+	    lp->cache.csr14 = CSR14;
+	    lp->cache.csr15 = CSR15;
+	}
+        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16);
+	lp->infoblock_csr6 = OMR_SIA;
+	lp->useMII = FALSE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc2114x_autoconf(dev);
 }
 
 static int 
 type3_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+    u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
     if (--count > lp->tcount) {
@@ -4122,20 +4735,55 @@
 	}
     }
 
+    p += 2;
     if (lp->state == INITIALISED) {
-	lp->ibn = 3; p += 2;
         lp->active = *p++;
-	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
-	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+	lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
+	lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
 	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
 	lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
 	lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].ttm = TWIDDLE(p);
+	lp->phy[lp->active].ttm = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].mci = *p;
 	return 0;
-    } else if (lp->media == INIT) {
+    } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 3;
+	lp->active = *p;
+	lp->infoblock_csr6 = OMR_MII_100;
+	lp->useMII = TRUE;
+	lp->infoblock_media = ANS;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc2114x_autoconf(dev);
+}
+
+static int 
+type4_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 4;
+        lp->active = 0;
 	p+=2;
-	lp->infoblock_media = (*p++) & BLOCK0_MC;
-	lp->cache.gep = *p++;
+	lp->infoblock_media = (*p++) & MEDIA_CODE;
+        lp->cache.csr13 = CSR13;              /* Hard coded defaults */
+	lp->cache.csr14 = CSR14;
+	lp->cache.csr15 = CSR15;
+        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16); p += 2;
 	csr6 = *p++;
 	flags = *p++;
 
@@ -4143,19 +4791,13 @@
 	lp->defMedium = (flags & 0x40) ? -1 : 0;
 	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
 	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-	lp->infoblock_csr6 = (csr6 & 0x71) << 18;
-	lp->useMII = TRUE;
+	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+	lp->useMII = FALSE;
 
 	de4x5_switch_mac_port(dev);
     }
 
-    return dc21140m_autoconf(dev);
-}
-
-static int 
-type4_infoblock(struct device *dev, u_char count, u_char *p)
-{
-    return DE4X5_AUTOSENSE_MS;
+    return dc2114x_autoconf(dev);
 }
 
 /*
@@ -4166,8 +4808,7 @@
 type5_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    u_char i, j, len = (*p & BLOCK_LEN)+1;
+    u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
     if (--count > lp->tcount) {
@@ -4182,19 +4823,7 @@
     if ((lp->state == INITIALISED) || (lp->media == INIT)) {
 	p+=2;
         lp->rst = p;
-	i = *p++;
-	for (j=0;i;--i) {
-	    if (lp->chipset == DC21140) {
-		if (!j) {
-		    outl(*p++ | GEP_CTRL, DE4X5_GEP);
-		    j++;
-		}
-		outl(*p++, DE4X5_GEP);
-	    } else if (lp->chipset == DC21142) {
-	    } else if (lp->chipset == DC21143) {
-	    }
-	}
-	    
+        srom_exec(dev, lp->rst);
     }
 
     return DE4X5_AUTOSENSE_MS;
@@ -4326,8 +4955,7 @@
 }
 
 /*
-** Here's 3 ways to calculate the OUI from the ID registers. One's a brain
-** dead approach, 2 aren't (clue: mine isn't!).
+** Here's 3 ways to calculate the OUI from the ID registers.
 */
 static int
 mii_get_oui(u_char phyaddr, u_long ioaddr)
@@ -4380,7 +5008,7 @@
 mii_get_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
+    u_long iobase = dev->base_addr;
     int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
     int id;
     
@@ -4393,7 +5021,7 @@
 	if (i==0) n++;                             /* Count cycles */
 	while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
 	id = mii_get_oui(i, DE4X5_MII); 
-	if ((id == 0) || (id == -1)) continue;     /* Valid ID? */
+	if ((id == 0) || (id == 65535)) continue;  /* Valid ID? */
 	for (j=0; j<limit; j++) {                  /* Search PHY table */
 	    if (id != phy_info[j].id) continue;    /* ID match? */
 	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
@@ -4404,11 +5032,28 @@
 		lp->mii_cnt++;
 		lp->active++;
 	    } else {
-		i = DE4X5_MAX_MII;                 /* Stop the search */
-		j = limit;
+		goto purgatory;                    /* Stop the search */
 	    }
+	    break;
+	}
+	if ((j == limit) && (i < DE4X5_MAX_MII)) {
+	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+	    lp->phy[k].addr = i;
+	    lp->phy[k].id = id;
+	    lp->phy[k].spd.reg = GENERIC_REG;      /* ANLPA register         */
+	    lp->phy[k].spd.mask = GENERIC_MASK;    /* 100Mb/s technologies   */
+	    lp->phy[k].spd.value = GENERIC_VALUE;  /* TX & T4, H/F Duplex    */
+	    lp->mii_cnt++;
+	    lp->active++;
+	    printk("%s: Using generic MII device control. If the board doesn't operate, \nplease mail the following dump to the author:\n", dev->name);
+	    j = de4x5_debug;
+	    de4x5_debug |= DEBUG_MII;
+	    de4x5_dbg_mii(dev, k);
+	    de4x5_debug = j;
+	    printk("\n");
 	}
     }
+  purgatory:
     lp->active = 0;
     if (lp->phy[0].id) {                           /* Reset the PHY devices */
 	for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
@@ -4418,7 +5063,8 @@
 	    de4x5_dbg_mii(dev, k);
 	}
     }
-    
+    if (!lp->mii_cnt) lp->useMII = FALSE;
+
     return lp->mii_cnt;
 }
 
@@ -4476,9 +5122,11 @@
 de4x5_switch_mac_port(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
+    u_long iobase = dev->base_addr;
     s32 omr;
 
+    STOP_DE4X5;
+
     /* Assert the OMR_PS bit in CSR6 */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
 			                                             OMR_FDX));
@@ -4489,10 +5137,12 @@
     /* Soft Reset */
     RESET_DE4X5;
     
-    /* Restore the GEP */
+    /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */
     if (lp->chipset == DC21140) {
-	outl(lp->cache.gepc, DE4X5_GEP);
-	outl(lp->cache.gep, DE4X5_GEP);
+	gep_wr(lp->cache.gepc, dev);
+	gep_wr(lp->cache.gep, dev);
+    } else if ((lp->chipset & ~0x0ff) == DC2114x) {
+	reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15);
     }
 
     /* Restore CSR6 */
@@ -4505,6 +5155,36 @@
 }
 
 static void
+gep_wr(s32 data, struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    if (lp->chipset == DC21140) {
+	outl(data, DE4X5_GEP);
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	outl((data<<16) | lp->cache.csr15, DE4X5_SIGR);
+    }
+
+    return;
+}
+
+static int
+gep_rd(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    if (lp->chipset == DC21140) {
+	return inl(DE4X5_GEP);
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	return (inl(DE4X5_SIGR) & 0x000fffff);
+    }
+
+    return 0;
+}
+
+static void
 timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -4530,7 +5210,7 @@
 yawn(struct device *dev, int state)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
+    u_long iobase = dev->base_addr;
 
     if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return;
 
@@ -4575,6 +5255,49 @@
 }
 
 static void
+de4x5_parse_params(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    char *p, *q, t;
+
+    lp->params.fdx = 0;
+    lp->params.autosense = AUTO;
+
+    if (args == NULL) return;
+
+    if ((p = strstr(args, dev->name))) {
+	if (!(q = strstr(p+strlen(dev->name), "eth"))) q = p + strlen(p);
+	t = *q;
+	*q = '\0';
+
+	if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1;
+
+	if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
+	    if (strstr(p, "TP")) {
+		lp->params.autosense = TP;
+	    } else if (strstr(p, "TP_NW")) {
+		lp->params.autosense = TP_NW;
+	    } else if (strstr(p, "BNC")) {
+		lp->params.autosense = BNC;
+	    } else if (strstr(p, "AUI")) {
+		lp->params.autosense = AUI;
+	    } else if (strstr(p, "BNC_AUI")) {
+		lp->params.autosense = BNC;
+	    } else if (strstr(p, "10Mb")) {
+		lp->params.autosense = _10Mb;
+	    } else if (strstr(p, "100Mb")) {
+		lp->params.autosense = _100Mb;
+	    } else if (strstr(p, "AUTO")) {
+		lp->params.autosense = AUTO;
+	    }
+	}
+	*q = t;
+    }
+
+    return;
+}
+
+static void
 de4x5_dbg_open(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -4629,10 +5352,11 @@
 de4x5_dbg_mii(struct device *dev, int k)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
+    u_long iobase = dev->base_addr;
     
     if (de4x5_debug & DEBUG_MII) {
-	printk("\nMII CR:  %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
+	printk("\nMII device address: %d\n", lp->phy[k].addr);
+	printk("MII CR:  %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
 	printk("MII SR:  %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII));
 	printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII));
 	printk("MII ID1: %x\n",mii_rd(MII_ID1,lp->phy[k].addr,DE4X5_MII));
@@ -4659,25 +5383,18 @@
     
     if (lp->media != lp->c_media) {
 	if (de4x5_debug & DEBUG_MEDIA) {
-	    if (lp->chipset != DC21140) {
-		printk("%s: media is %s\n", dev->name,
-		       (lp->media == NC  ? "unconnected!" :
-			(lp->media == TP  ? "TP." :
-			 (lp->media == ANS ? "TP/Nway." :
-			  (lp->media == BNC ? "BNC." : 
-			   (lp->media == AUI ? "AUI." : 
-			    (lp->media == BNC_AUI ? "BNC/AUI." : 
-			     (lp->media == EXT_SIA ? "EXT SIA." : 
-			      "???."
-			      ))))))));
-	    } else {
-		printk("%s: mode is %s\n", dev->name,
-		    (lp->media == NC ? "link down or incompatible connection.":
-		     (lp->media == _100Mb  ? "100Mb/s." :
-		      (lp->media == _10Mb   ? "10Mb/s." :
-		       "\?\?\?"
-		       ))));
-	    }
+	    printk("%s: media is %s%s\n", dev->name,
+		   (lp->media == NC  ? "unconnected, link down or incompatible connection" :
+		    (lp->media == TP  ? "TP" :
+		     (lp->media == ANS ? "TP/Nway" :
+		      (lp->media == BNC ? "BNC" : 
+		       (lp->media == AUI ? "AUI" : 
+			(lp->media == BNC_AUI ? "BNC/AUI" : 
+			 (lp->media == EXT_SIA ? "EXT SIA" : 
+			  (lp->media == _100Mb  ? "100Mb/s" :
+			   (lp->media == _10Mb   ? "10Mb/s" :
+			    "???"
+			    ))))))))), (lp->fdx?" full duplex.":"."));
 	}
 	lp->c_media = lp->media;
     }
@@ -4749,7 +5466,8 @@
 
 /*
 ** Perform IOCTL call functions here. Some are privileged operations and the
-** effective uid is checked in those cases.
+** effective uid is checked in those cases. In the normal course of events
+** this function is only used for my testing.
 */
 static int
 de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
@@ -4791,7 +5509,7 @@
 	}
 	build_setup_frame(dev, PHYS_ADDR_ONLY);
 	/* Set up the descriptor and give ownership to the card */
-	while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+	while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);
 	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 		                                        SETUP_FRAME_LEN, NULL);
 	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -4804,6 +5522,7 @@
 	    omr = inl(DE4X5_OMR);
 	    omr |= OMR_PR;
 	    outl(omr, DE4X5_OMR);
+	    dev->flags |= IFF_PROMISC;
 	} else {
 	    status = -EPERM;
 	}
@@ -4814,6 +5533,7 @@
 	    omr = inl(DE4X5_OMR);
 	    omr &= ~OMR_PR;
 	    outb(omr, DE4X5_OMR);
+	    dev->flags &= ~IFF_PROMISC;
 	} else {
 	    status = -EPERM;
 	}
@@ -4823,13 +5543,7 @@
 	printk("%s: Boo!\n", dev->name);
 	
 	break;
-      case DE4X5_GET_MCA:              /* Get the multicast address table */
-	break;
-      case DE4X5_SET_MCA:              /* Set a multicast address */
-	break;
-      case DE4X5_CLR_MCA:              /* Clear all multicast addresses */
-	break;
-      case DE4X5_MCA_EN:               /* Enable pass all multicast addresses*/
+      case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
 	if (suser()) {
 	    omr = inl(DE4X5_OMR);
 	    omr |= OMR_PM;
@@ -4894,9 +5608,8 @@
 	}
 	break;
 	
-/*
-#define DE4X5_DUMP              0x0f / * Dump the DE4X5 Status * /
-	
+#define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
+/*	
       case DE4X5_DUMP:
 	j = 0;
 	tmp.addr[j++] = dev->irq;
@@ -4950,7 +5663,7 @@
 	tmp.lval[j>>2] = inl(DE4X5_IMR);  j+=4;
 	tmp.lval[j>>2] = lp->chipset; j+=4; 
 	if (lp->chipset == DC21140) {
-	    tmp.lval[j>>2] = inl(DE4X5_GEP);  j+=4;
+	    tmp.lval[j>>2] = gep_rd(dev);  j+=4;
 	} else {
 	    tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
 	    tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
@@ -5003,21 +5716,33 @@
 #define LP(a) ((struct de4x5_private *)(a))
 static struct device *mdev = NULL;
 static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+MODULE_PARM(io, "i");
+#endif /* LINUX_VERSION_CODE */
 
 int
 init_module(void)
 {
+    int i, num, status = -EIO;
     struct device *p;
 
-    if ((mdev = insert_device(NULL, io, de4x5_probe)) == NULL) 
-      return -ENOMEM;
+    num = count_adapters();
+
+    for (i=0; i<num; i++) {
+	if ((p = insert_device(NULL, io, de4x5_probe)) == NULL) 
+	    return -ENOMEM;
+
+	if (!mdev) mdev = p;
 
-    for (p = mdev; p != NULL; p = LP(p->priv)->next_module) {
-	if (register_netdev(p) != 0)
-	  return -EIO;
+	if (register_netdev(p) != 0) {
+	    kfree(p);
+	} else {
+	    status = 0;                 /* At least one adapter will work */
+	    lastModule = p;
+	}
     }
 
-    return 0;
+    return status;
 }
 
 void
@@ -5051,6 +5776,62 @@
     kfree(p);                               /* Free the device structure */
     
     return next;
+}
+
+static int
+count_adapters(void)
+{
+    int i, j;
+    char name[DE4X5_STRLEN];
+    u_char pb, dev_fn, dev_num;
+    u_short dev_id, vendor;
+    u_int class = DE4X5_CLASS_CODE;
+    u_int device;
+#ifndef __sparc_v9__
+    u_long iobase = 0x1000;
+
+    for (j=0, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+	if (EISA_signature(name, EISA_ID)) j++;
+    }
+#endif
+    if (!pcibios_present()) return j;
+
+    for (i=0; 
+	 (pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+	 i++) {
+	dev_num = PCI_SLOT(dev_fn);
+	device = 0;
+	pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
+	pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+	device = dev_id;
+	device <<= 8;
+	if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
+    }
+
+    return j;
+}
+
+/*
+** If at end of eth device list and can't use current entry, malloc
+** one up. If memory could not be allocated, print an error message.
+*/
+__initfunc(static struct device *
+insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
+{
+    struct device *new;
+
+    new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
+    if (new == NULL) {
+	printk("de4x5.c: Device not initialised, insufficient memory\n");
+	return NULL;
+    } else {
+	memset((char *)new, 0, sizeof(struct device)+8);
+	new->name = (char *)(new + 1);
+	new->base_addr = iobase;       /* assign the io address */
+	new->init = init;              /* initialisation routine */
+    }
+
+    return new;
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v2.0.33/linux/drivers/net/de4x5.h	Tue Aug 12 13:21:12 1997
+++ linux/drivers/net/de4x5.h	Wed Jun  3 15:17:47 1998
@@ -120,7 +120,7 @@
 #define DC21140     DC21140_DID
 #define DC2114x     DC2114x_DID
 #define DC21142     (DC2114x_DID | 0x0010)
-#define DC21143     (DC2114x_DID | 0x0020)
+#define DC21143     (DC2114x_DID | 0x0030)
 
 #define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
 #define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
@@ -166,7 +166,7 @@
 /*
 ** PCI Configuration Base I/O Address Register (PCI_CBIO)
 */
-#define CBIO_MASK   0xffffff80       /* Base I/O Address Mask */
+#define CBIO_MASK   -128             /* Base I/O Address Mask */
 #define CBIO_IOSI   0x00000001       /* I/O Space Indicator (RO, value is 1) */
 
 /*
@@ -360,6 +360,12 @@
 #define TR_128     0x00008000       /* Threshold set to 128 (512) bytes */
 #define TR_160     0x0000c000       /* Threshold set to 160 (1024) bytes */
 
+#define OMR_DEF     (OMR_SDP)
+#define OMR_SIA     (OMR_SDP | OMR_TTM)
+#define OMR_SYM     (OMR_SDP | OMR_SCR | OMR_PCS | OMR_HBD | OMR_PS)
+#define OMR_MII_10  (OMR_SDP | OMR_TTM | OMR_PS)
+#define OMR_MII_100 (OMR_SDP | OMR_HBD | OMR_PS)
+
 /*
 ** DC21040 Interrupt Mask Register (DE4X5_IMR)
 */
@@ -606,48 +612,60 @@
 ** DC21140 General Purpose Register (DE4X5_GEP) (hardware dependent bits)
 */
 /* Valid ONLY for DE500 hardware */
-#define GEP_LNP  0x00000080        /* Link Pass               (input) */
-#define GEP_SLNK 0x00000040        /* SYM LINK                (input) */
-#define GEP_SDET 0x00000020        /* Signal Detect           (input) */
-#define GEP_HRST 0x00000010        /* Hard RESET (to PHY)     (output) */
-#define GEP_FDXD 0x00000008        /* Full Duplex Disable     (output) */
-#define GEP_PHYL 0x00000004        /* PHY Loopback            (output) */
-#define GEP_FLED 0x00000002        /* Force Activity LED on   (output) */
-#define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s           */
-#define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1) */
-#define GEP_CTRL 0x00000100        /* GEP control bit                  */
+#define GEP_LNP  0x00000080        /* Link Pass               (input)        */
+#define GEP_SLNK 0x00000040        /* SYM LINK                (input)        */
+#define GEP_SDET 0x00000020        /* Signal Detect           (input)        */
+#define GEP_HRST 0x00000010        /* Hard RESET (to PHY)     (output)       */
+#define GEP_FDXD 0x00000008        /* Full Duplex Disable     (output)       */
+#define GEP_PHYL 0x00000004        /* PHY Loopback            (output)       */
+#define GEP_FLED 0x00000002        /* Force Activity LED on   (output)       */
+#define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s                 */
+#define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1)       */
+#define GEP_CTRL 0x00000100        /* GEP control bit                        */
+
+/*
+** SIA Register Defaults
+*/
+#define CSR13 0x00000001
+#define CSR14 0x0003ff7f           /* Autonegotiation disabled               */
+#define CSR15 0x00000008
 
 /*
 ** SIA Status Register (DE4X5_SISR)
 */
-#define SISR_LPC   0xffff0000      /* Link Partner's Code Word */
-#define SISR_LPN   0x00008000      /* Link Partner Negotiable */
-#define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State */
-#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected (DC21041) */
-#define SISR_TRF   0x00000800      /* Transmit Remote Fault */
-#define SISR_NSND  0x00000400      /* Non Stable NLPs Detected (DC21142) */
+#define SISR_LPC   0xffff0000      /* Link Partner's Code Word               */
+#define SISR_LPN   0x00008000      /* Link Partner Negotiable                */
+#define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State     */
+#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected (DC21041)     */
+#define SISR_TRF   0x00000800      /* Transmit Remote Fault                  */
+#define SISR_NSND  0x00000400      /* Non Stable NLPs Detected (DC21142)     */
 #define SISR_ANR_FDS 0x00000400    /* Auto Negotiate Restart/Full Duplex Sel.*/
-#define SISR_TRA   0x00000200      /* 10BASE-T Receive Port Activity */
-#define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity */
-#define SISR_ARA   0x00000100      /* AUI Receive Port Activity */
-#define SISR_SRA   0x00000100      /* Selected Port Receive Activity */
-#define SISR_DAO   0x00000080      /* PLL All One */
-#define SISR_DAZ   0x00000040      /* PLL All Zero */
-#define SISR_DSP   0x00000020      /* PLL Self-Test Pass */
-#define SISR_DSD   0x00000010      /* PLL Self-Test Done */
-#define SISR_APS   0x00000008      /* Auto Polarity State */
-#define SISR_LKF   0x00000004      /* Link Fail Status */
-#define SISR_NCR   0x00000002      /* Network Connection Error */
-#define SISR_PAUI  0x00000001      /* AUI_TP Indication */
-#define SISR_MRA   0x00000001      /* MII Receive Port Activity */
-
-#define ANS_NDIS   0x00000000      /* Nway disable */
-#define ANS_TDIS   0x00001000      /* Transmit Disable */
-#define ANS_ADET   0x00002000      /* Ability Detect */
-#define ANS_ACK    0x00003000      /* Acknowledge */
-#define ANS_CACK   0x00004000      /* Complete Acknowledge */
-#define ANS_NWOK   0x00005000      /* Nway OK - FLP Link Good */
-#define ANS_LCHK   0x00006000      /* Link Check */
+#define SISR_TRA   0x00000200      /* 10BASE-T Receive Port Activity         */
+#define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity     */
+#define SISR_ARA   0x00000100      /* AUI Receive Port Activity              */
+#define SISR_SRA   0x00000100      /* Selected Port Receive Activity         */
+#define SISR_DAO   0x00000080      /* PLL All One                            */
+#define SISR_DAZ   0x00000040      /* PLL All Zero                           */
+#define SISR_DSP   0x00000020      /* PLL Self-Test Pass                     */
+#define SISR_DSD   0x00000010      /* PLL Self-Test Done                     */
+#define SISR_APS   0x00000008      /* Auto Polarity State                    */
+#define SISR_LKF   0x00000004      /* Link Fail Status                       */
+#define SISR_LS10  0x00000004      /* 10Mb/s Link Fail Status                */
+#define SISR_NCR   0x00000002      /* Network Connection Error               */
+#define SISR_LS100 0x00000002      /* 100Mb/s Link Fail Status               */
+#define SISR_PAUI  0x00000001      /* AUI_TP Indication                      */
+#define SISR_MRA   0x00000001      /* MII Receive Port Activity              */
+
+#define ANS_NDIS   0x00000000      /* Nway disable                           */
+#define ANS_TDIS   0x00001000      /* Transmit Disable                       */
+#define ANS_ADET   0x00002000      /* Ability Detect                         */
+#define ANS_ACK    0x00003000      /* Acknowledge                            */
+#define ANS_CACK   0x00004000      /* Complete Acknowledge                   */
+#define ANS_NWOK   0x00005000      /* Nway OK - FLP Link Good                */
+#define ANS_LCHK   0x00006000      /* Link Check                             */
+
+#define SISR_RST   0x00000301      /* CSR12 reset                            */
+#define SISR_ANR   0x00001301      /* Autonegotiation restart                */
 
 /*
 ** SIA Connectivity Register (DE4X5_SICR)
@@ -791,16 +809,22 @@
 
 /*
 ** Media / mode state machine definitions
+** User selectable:
 */
-#define NC              0x0000     /* No Connection                        */
 #define TP              0x0001     /* 10Base-T                             */
 #define TP_NW           0x0002     /* 10Base-T with Nway                   */
 #define BNC             0x0004     /* Thinwire                             */
 #define AUI             0x0008     /* Thickwire                            */
 #define BNC_AUI         0x0010     /* BNC/AUI on DC21040 indistinguishable */
-#define ANS             0x0020     /* Intermediate AutoNegotiation State   */
 #define _10Mb           0x0040     /* 10Mb/s Ethernet                      */
 #define _100Mb          0x0080     /* 100Mb/s Ethernet                     */
+#define AUTO            0x4000     /* Auto sense the media or speed        */
+
+/*
+** Internal states
+*/
+#define NC              0x0000     /* No Connection                        */
+#define ANS             0x0020     /* Intermediate AutoNegotiation State   */
 #define SPD_DET         0x0100     /* Parallel speed detection             */
 #define INIT            0x0200     /* Initial state                        */
 #define EXT_SIA         0x0400     /* External SIA for motherboard chip    */
@@ -812,7 +836,6 @@
 #define AUI_SUSPECT     0x0807     /* Suspect the AUI port is down         */
 #define MII             0x1000     /* MII on the 21143                     */
 
-#define AUTO            0x4000     /* Auto sense the media or speed        */
 #define TIMER_CB        0x80000000 /* Timer callback detection             */
 
 /*
@@ -828,6 +851,7 @@
 #define DEBUG_OPEN      0x0040     /* Print de4x5_open() messages */
 #define DEBUG_CLOSE     0x0080     /* Print de4x5_close() messages */
 #define DEBUG_PCICFG    0x0100
+#define DEBUG_ALL       0x01ff
 
 /*
 ** Miscellaneous
@@ -884,6 +908,12 @@
 #define OPEN                 2     /* Running */
 
 /*
+** Various wait times
+*/
+#define PDET_LINK_WAIT    1200    /* msecs to wait for link detect bits     */
+#define ANS_FINISH_WAIT   1000    /* msecs to wait for link detect bits     */
+
+/*
 ** IEEE OUIs for various PHY vendor/chip combos - Reg 2 values only. Since
 ** the vendors seem split 50-50 on how to calculate the OUI register values
 ** anyway, just reading Reg2 seems reasonable for now [see de4x5_get_oui()].
@@ -908,12 +938,13 @@
   } else if (lp->useSROM && !lp->useMII) {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
+    outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\
   } else {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | OMR_TTM, DE4X5_OMR);\
+    outl(omr | OMR_SDP | OMR_TTM, DE4X5_OMR);\
     lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD);\
+    gep_wr(lp->cache.gep, dev);\
   }\
 }
 
@@ -936,12 +967,13 @@
   } else if (lp->useSROM && !lp->useMII) {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | lp->infoblock_csr6 | OMR_HBD, DE4X5_OMR);\
+    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
   } else {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
+    outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
     lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD) | GEP_MODE;\
+    gep_wr(lp->cache.gep, dev);\
   }\
 }
 
@@ -956,8 +988,9 @@
     outl(omr, DE4X5_OMR);\
   } else {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
+    outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS, DE4X5_OMR);\
     lp->cache.gep = (GEP_FDXD | GEP_MODE);\
+    gep_wr(lp->cache.gep, dev);\
   }\
 }
 
@@ -991,3 +1024,5 @@
 #define DE4X5_GET_OMR           0x0c /* Get the OMR Register contents */
 #define DE4X5_SET_OMR           0x0d /* Set the OMR Register contents */
 #define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
diff -u --recursive --new-file v2.0.33/linux/drivers/net/dlci.c linux/drivers/net/dlci.c
--- v2.0.33/linux/drivers/net/dlci.c	Sun Sep 15 00:34:18 1996
+++ linux/drivers/net/dlci.c	Wed Jun  3 15:17:47 1998
@@ -27,6 +27,7 @@
  *		2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.0.33/linux/drivers/net/eepro.c	Sat Aug 10 00:03:14 1996
+++ linux/drivers/net/eepro.c	Wed Jun  3 15:17:47 1998
@@ -1,6 +1,7 @@
 /* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
 /*
 	Written 1994, 1995,1996 by Bao C. Ha.
+	Last Update, 2/7/98, Phillip R. Jaenke
 
 	Copyright (C) 1994, 1995,1996 by Bao C. Ha.
 
@@ -11,6 +12,9 @@
 	The author may be reached at bao.ha@srs.gov 
 	or 418 Hastings Place, Martinez, GA 30907.
 
+	Phillip R. Jaenke may be reached at prj@nls.net
+	or P.O. Box 413, Twinsburg, OH 44087, ATTN: Linux
+
 	Things remaining to do:
 	Better record keeping of errors.
 	Eliminate transmit interrupt to reduce overhead.
@@ -23,6 +27,9 @@
 	This is a compatibility hardware problem.
 
 	Versions:
+	
+	0.10	Added several I/O addresses previously not included.
+		(PRJ, 2/7/98)
 
 	0.09	Fixed a race condition in the transmit algorithm,
 		which causes crashes under heavy load with fast
@@ -60,7 +67,7 @@
 */
 
 static const char *version =
-	"eepro.c: v0.09 7/31/96 Bao C. Ha (bao.ha@srs.gov)\n";
+	"eepro.c: v0.10 7/31/96 Bao C. Ha (bao.ha@srs.gov)\n";
 
 #include <linux/module.h>
 
@@ -110,7 +117,7 @@
 /* First, a few definitions that the brave might change. */
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int eepro_portlist[] =
-   { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0x360, 0};
+   { 0x200, 0x240, 0x260, 0x280, 0x2C0, 0x300, 0x310, 0x320, 0x340, 0x360, 0};
 
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
diff -u --recursive --new-file v2.0.33/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.0.33/linux/drivers/net/eepro100.c	Tue Dec  2 13:52:31 1997
+++ linux/drivers/net/eepro100.c	Wed Jun  3 15:17:47 1998
@@ -1,7 +1,7 @@
 /* drivers/net/eepro100.c: An Intel i82557 ethernet driver for linux. */
 /*
    NOTICE: this version tested with kernels 1.3.72 and later only!
-	Written 1996-1997 by Donald Becker.
+	Written 1996-1998 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -19,7 +19,7 @@
 */
 
 static const char *version =
-"eepro100.c:v0.36 10/20/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
+"eepro100.c:v0.99B 4/7/98 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values that apply to all boards.
    First set are undocumented and spelled per Intel recommendations. */
@@ -38,6 +38,9 @@
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
 
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
+
 #include <linux/config.h>
 #ifdef MODULE
 #ifdef MODVERSIONS
@@ -69,73 +72,36 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-
-/* A nominally proper method to handle version dependencies is to use
-   LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */
-#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
-#ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,0))
-#define KERNEL_1_2
-#else /* 1.3.0 */
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
-#define NEW_MULTICAST
-#define LINUX_1_4
-#else
-#warning "This driver is tested for 1.3.44 and later development kernels only."
-#endif /* 1.3.44 */
-#endif
-#else
-
-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST
 #include <linux/delay.h>
-#endif
 
-#ifdef HAVE_HEADER_CACHE
-#define LINUX_1_4
-#define NEW_MULTICAST
-#else
-#ifdef ETH_P_DDCMP				/* Warning: Bogus!  This means IS_LINUX_1_3. */
-#define KERNEL_1_3
-#else
-#define KERNEL_1_2
-#endif
+/* Unused in the 2.0.* version, but retained for documentation. */
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
 #endif
 
-#endif
-/* This should be in a header file. */
-#if (LINUX_VERSION_CODE < VERSION(1,3,44))
-struct device *init_etherdev(struct device *dev, int sizeof_priv,
-							 unsigned long *mem_startp);
-#endif
-#if LINUX_VERSION_CODE < 0x10300
-#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
-#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#define virt_to_bus(addr)  ((unsigned long)addr)
-#define bus_to_virt(addr) ((void*)addr)
-#else  /* 1.3.0 and later */
 #define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
-#endif
 
 #if (LINUX_VERSION_CODE < 0x20123)
 #define test_and_set_bit(val, addr) set_bit(val, addr)
 #endif
 
-/* The total I/O port extent of the board.  Nominally 0x18, but rounded up
-   for PCI allocation. */
+/* The total I/O port extent of the board.
+   The registers beyond 0x18 only exist on the i82558. */
 #define SPEEDO3_TOTAL_SIZE 0x20
 
-#ifdef HAVE_DEVLIST
-struct netdev_entry eepro100_drv =
-{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL};
-#endif
-
-#ifdef SPEEDO3_DEBUG
-int speedo_debug = SPEEDO3_DEBUG;
-#else
-int speedo_debug = 3;
-#endif
+int speedo_debug = 1;
 
 /*
 				Theory of Operation
@@ -274,7 +240,7 @@
 #define PKT_BUF_SZ		1536
 
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((400*HZ)/1000)
+#define TX_TIMEOUT  ((800*HZ)/1000)
 
 /* How to wait for the command unit to accept a command.
    Typically this takes 0 ticks. */
@@ -287,13 +253,6 @@
 
 /* Operational parameter that usually are not changed. */
 
-#ifndef PCI_VENDOR_ID_INTEL		/* Now defined in linux/pci.h */
-#define PCI_VENDOR_ID_INTEL		0x8086 /* Hmmmm, how did they pick that? */
-#endif
-#ifndef PCI_DEVICE_ID_INTEL_82557
-#define PCI_DEVICE_ID_INTEL_82557	0x1229
-#endif
-
 /* The rest of these values should never change. */
 
 /* Offsets to the various registers.
@@ -393,9 +352,6 @@
 	/* Rx descriptor ring & addresses of receive-in-place skbuffs. */
 	struct RxFD *rx_ringp[RX_RING_SIZE];
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-#if (LINUX_VERSION_CODE < 0x10300)	/* Kernel v1.2.*. */
-	struct RxFD saved_skhead[RX_RING_SIZE];	/* Saved skbuff header chunk. */
-#endif
 	struct RxFD *last_rxf;	/* Last command sent. */
 	struct enet_statistics stats;
 	struct speedo_stats lstats;
@@ -407,6 +363,7 @@
 	u8 config_cmd_data[22];			/* .. and setup parameters. */
 	int mc_setup_frm_len;			 	/* The length of an allocated.. */
 	struct descriptor *mc_setup_frm; 	/* ..multicast setup frame. */
+	int in_interrupt;					/* Word-aligned dev->interrupt */
 	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
@@ -437,7 +394,7 @@
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
 
 static void speedo_found1(struct device *dev, int ioaddr, int irq,
-						  int options, int card_idx);
+						  int card_idx);
 
 static int read_eeprom(int ioaddr, int location);
 static int mdio_read(int ioaddr, int phy_id, int location);
@@ -447,16 +404,10 @@
 static void speedo_init_rx_ring(struct device *dev);
 static int speedo_start_xmit(struct sk_buff *skb, struct device *dev);
 static int speedo_rx(struct device *dev);
-#ifdef SA_SHIRQ
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-#else
-static void speedo_interrupt(int irq, struct pt_regs *regs);
-#endif
 static int speedo_close(struct device *dev);
 static struct enet_statistics *speedo_get_stats(struct device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-#endif
 static void set_rx_mode(struct device *dev);
 
 
@@ -465,8 +416,8 @@
 /* 'options' is used to pass a transceiver override or full-duplex flag
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
 static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-#ifdef MODULE
 static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#ifdef MODULE
 static int debug = -1;			/* The debug level */
 #endif
 
@@ -481,12 +432,9 @@
 		static int pci_index = 0;
 		for (; pci_index < 8; pci_index++) {
 			unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency;
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
 			int pci_ioaddr;
-#else
-			long pci_ioaddr;
-#endif
-			unsigned short pci_command;
+
+			unsigned short pci_command, new_command;
 
 			if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
 									PCI_DEVICE_ID_INTEL_82557,
@@ -507,29 +455,25 @@
 			/* Get and check the bus-master and latency values. */
 			pcibios_read_config_word(pci_bus, pci_device_fn,
 									 PCI_COMMAND, &pci_command);
-			if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-				printk("  PCI Master Bit has not been set! Setting...\n");
-				pci_command |= PCI_COMMAND_MASTER;
+			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+			if (pci_command != new_command) {
+				printk(KERN_INFO "  The PCI BIOS has not enabled this"
+					   " device!  Updating PCI command %4.4x->%4.4x.\n",
+					   pci_command, new_command);
 				pcibios_write_config_word(pci_bus, pci_device_fn,
-										  PCI_COMMAND, pci_command);
+										  PCI_COMMAND, new_command);
 			}
 			pcibios_read_config_byte(pci_bus, pci_device_fn,
 										 PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency < 10) {
+			if (pci_latency < 32) {
 				printk("  PCI latency timer (CFLT) is unreasonably low at %d."
-					   "  Setting to 255 clocks.\n", pci_latency);
+					   "  Setting to 32 clocks.\n", pci_latency);
 				pcibios_write_config_byte(pci_bus, pci_device_fn,
-										  PCI_LATENCY_TIMER, 255);
+										  PCI_LATENCY_TIMER, 32);
 			} else if (speedo_debug > 1)
 				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
 
-#ifdef MODULE
-			speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found],
-						  cards_found);
-#else
-			speedo_found1(dev, pci_ioaddr, pci_irq_line,
-						  dev ? dev->mem_start : 0, -1);
-#endif
+			speedo_found1(dev, pci_ioaddr, pci_irq_line, cards_found);
 			dev = NULL;
 			cards_found++;
 		}
@@ -538,23 +482,26 @@
 	return cards_found;
 }
 
-static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
+static void speedo_found1(struct device *dev, int ioaddr, int irq,
 						  int card_idx)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct speedo_private *sp;
 	char *product;
-	int i;
+	int i, option;
 	u16 eeprom[0x40];
 
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
 	dev = init_etherdev(dev, sizeof(struct speedo_private));
-#else
-	dev = init_etherdev(dev, sizeof(struct speedo_private), 0);
-#endif
+
+	if (dev->mem_start > 0) 
+		option = dev->mem_start;
+	else if (card_idx >= 0  &&  options[card_idx] >= 0)
+		option = options[card_idx];
+	else
+		option = 0;
 
 	/* Read the station address EEPROM before doing the reset.
 	   Perhaps this should even be done before accepting the device,
@@ -618,17 +565,6 @@
 		if (eeprom[7] & 0x0700)
 			printk(KERN_INFO "    Secondary interface chip %s.\n",
 				   phys[(eeprom[7]>>8)&7]);
-#if defined(notdef)
-		/* ToDo: Read and set PHY registers through MDIO port. */
-		for (i = 0; i < 2; i++)
-			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
-		for (i = 5; i < 7; i++)
-			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
-		printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-			   25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25));
-#endif
 		if (((eeprom[6]>>8) & 0x3f) == DP83840
 			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
 			int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
@@ -638,13 +574,13 @@
 				   mdi_reg23);
 			mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
 		}
-		if ((options >= 0) && (options & 0x60)) {
+		if ((option >= 0) && (option & 0x70)) {
 			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
-				   (options & 0x20 ? 100 : 10),
-				   (options & 0x10 ? "full" : "half"));
+				   (option & 0x20 ? 100 : 10),
+				   (option & 0x10 ? "full" : "half"));
 			mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
-					   ((options & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
-					   ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+					   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
+					   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
 		}
 
 		/* Perform a system self-test. */
@@ -653,11 +589,7 @@
 		self_test_results[1] = -1;
 		outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort);
 		do {
-#ifdef _LINUX_DELAY_H
 			udelay(10);
-#else
-			SLOW_DOWN_IO;
-#endif
 		} while (self_test_results[1] == -1  &&  --boguscnt >= 0);
 
 		if (boguscnt < 0) {		/* Test optimized out. */
@@ -694,12 +626,12 @@
 	sp->next_module = root_speedo_dev;
 	root_speedo_dev = dev;
 
+	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
 			sp->full_duplex = full_duplex[card_idx];
-	} else
-		sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
-	sp->default_port = options >= 0 ? (options & 0x0f) : 0;
+	}
+	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
 	sp->phy[1] = eeprom[7];
@@ -713,12 +645,8 @@
 	dev->hard_start_xmit = &speedo_start_xmit;
 	dev->stop = &speedo_close;
 	dev->get_stats = &speedo_get_stats;
-#ifdef NEW_MULTICAST
 	dev->set_multicast_list = &set_rx_mode;
-#endif
-#ifdef HAVE_PRIVATE_IOCTL
 	dev->do_ioctl = &speedo_ioctl;
-#endif
 
 	return;
 }
@@ -735,13 +663,8 @@
 #define EE_ENB			(0x4800 | EE_CS)
 
 /* Delay between EEPROM clock transitions.
-   This is a "nasty" timing loop, but PC compatible machines are defined
-   to delay an ISA compatible period for the SLOW_DOWN_IO macro.  */
-#ifdef _LINUX_DELAY_H
+   This will actually work with no delay on 33Mhz PCI.  */
 #define eeprom_delay(nanosec)		udelay(1);
-#else
-#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-#endif
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5 << 6)
@@ -765,8 +688,6 @@
 		eeprom_delay(100);
 		outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
 		eeprom_delay(150);
-		outw(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
-		eeprom_delay(250);
 	}
 	outw(EE_ENB, ee_addr);
 
@@ -785,14 +706,9 @@
 
 static int mdio_read(int ioaddr, int phy_id, int location)
 {
-	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
+	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
 	do {
-#ifdef _LINUX_DELAY_H
-		udelay(16);
-#else
-		SLOW_DOWN_IO;
-#endif
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
@@ -803,15 +719,10 @@
 
 static int mdio_write(int ioaddr, int phy_id, int location, int value)
 {
-	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
+	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
 		 ioaddr + SCBCtrlMDI);
 	do {
-#ifdef _LINUX_DELAY_H
-		udelay(16);
-#else
-		SLOW_DOWN_IO;
-#endif
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
@@ -830,31 +741,13 @@
 #ifdef notdef
 	/* We could reset the chip, but should not need to. */
 	outl(0, ioaddr + SCBPort);
-	for (i = 40; i >= 0; i--)
-		SLOW_DOWN_IO;			/* At least 250ns */
+	udelay(10);
 #endif
 
-#ifdef SA_SHIRQ
 	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,
 					"Intel EtherExpress Pro 10/100 Ethernet", dev)) {
 		return -EAGAIN;
 	}
-#else
-#ifdef USE_SHARED_IRQ
-	if (request_shared_irq(dev->irq, &speedo_interrupt, dev,
-						   "Intel EtherExpress Pro 10/100 Ethernet"))
-		return -EAGAIN;
-#else
-	if (dev->irq < 2  ||  dev->irq > 15  ||  irq2dev_map[dev->irq] != NULL)
-		return -EAGAIN;
-	irq2dev_map[dev->irq] = dev;
-	if (request_irq(dev->irq, &speedo_interrupt, 0, "Intel EtherExpress Pro 10/100 Ethernet")) {
-		irq2dev_map[dev->irq] = NULL;
-		return -EAGAIN;
-	}
-#endif
-#endif
-
 	if (speedo_debug > 1)
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
@@ -899,6 +792,7 @@
 
 	dev->if_port = sp->default_port;
 
+	sp->in_interrupt = 0;
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
@@ -973,36 +867,23 @@
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
-#ifndef KERNEL_1_2
-		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#else
 		skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#endif
 		sp->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;			/* Bad news!  */
 		skb->dev = dev;			/* Mark as being used by this device. */
 
-#if LINUX_VERSION_CODE >= 0x10300
 		rxf = (struct RxFD *)skb->tail;
 		skb_reserve(skb, sizeof(struct RxFD));
-#else
-		/* Save the data in the header region -- it's restored later. */
-		rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD));
-		memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD));
-#endif
 		sp->rx_ringp[i] = rxf;
 		if (last_rxf)
 			last_rxf->link = virt_to_bus(rxf);
 		last_rxf = rxf;
 		rxf->status = 0x00000001; 			/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
-#if LINUX_VERSION_CODE < 0x10300
 		/* This field unused by i82557, we use it as a consistency check. */
-		rxf->rx_buf_addr = virt_to_bus(skb->data);
-#else
 		rxf->rx_buf_addr = virt_to_bus(skb->tail);
-#endif
+
 		rxf->count = 0;
 		rxf->size = PKT_BUF_SZ;
 	}
@@ -1015,27 +896,11 @@
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int ioaddr = dev->base_addr;
-	int i;
 
 	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
 		   "command %4.4x.\n",
 		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
-#ifndef final_version
-	printk(KERN_WARNING "%s:  Tx timeout  fill index %d  scavenge index %d.\n",
-		   dev->name, sp->cur_tx, sp->dirty_tx);
-	printk(KERN_WARNING "    Tx queue ");
-	for (i = 0; i < TX_RING_SIZE; i++)
-	  printk(" %8.8x", (int)sp->tx_ring[i].status);
-	printk(".\n" KERN_WARNING "    Rx ring ");
-	for (i = 0; i < RX_RING_SIZE; i++)
-	  printk(" %8.8x", (int)sp->rx_ringp[i]->status);
-	printk(".\n");
 
-#else
-	dev->if_port ^= 1;
-	printk(KERN_WARNING "  (Media type switching not yet implemented.)\n");
-	/* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */
-#endif
 	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
 	  printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
 			 dev->name);
@@ -1045,9 +910,14 @@
 	} else {
 	  outw(DRVR_INT, ioaddr + SCBCmd);
 	}
-	/* Reset the MII transceiver. */
-	if ((sp->phy[0] & 0x8000) == 0)
-		mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000);
+	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
+	if ((sp->phy[0] & 0x8000) == 0) {
+		int phy_addr = sp->phy[0] & 0x1f;
+		mdio_write(ioaddr, phy_addr, 0, 0x0400);
+		mdio_write(ioaddr, phy_addr, 1, 0x0000);
+		mdio_write(ioaddr, phy_addr, 4, 0x0000);
+		mdio_write(ioaddr, phy_addr, 0, 0x8000);
+	}
 	sp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	return;
@@ -1060,13 +930,6 @@
 	int ioaddr = dev->base_addr;
 	int entry;
 
-	if (skb == NULL || skb->len <= 0) {
-		printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n",
-			   dev->name);
-		dev_tint(dev);
-		return 0;
-	}
-
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 	   If this ever occurs the queue layer is doing something evil! */
@@ -1080,7 +943,7 @@
 			return 1;
 		}
 		speedo_tx_timeout(dev);
-		return 0;
+		return 1;
 	}
 
 	/* Caution: the write order is important here, set the base address
@@ -1123,7 +986,7 @@
 	if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)
 		sp->tx_full = 1;
 	else
-		dev->tbusy = 0;
+		clear_bit(0, (void*)&dev->tbusy);
 
 	dev->trans_start = jiffies;
 
@@ -1132,21 +995,9 @@
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-#ifdef SA_SHIRQ
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-#else
-static void speedo_interrupt(int irq, struct pt_regs *regs)
-#endif
 {
-#ifdef SA_SHIRQ
 	struct device *dev = (struct device *)dev_instance;
-#else
-#ifdef USE_SHARED_IRQ
-	struct device *dev = (struct device *)(irq == 0 ? regs : irq2dev_map[irq]);
-#else
-	struct device *dev = (struct device *)(irq2dev_map[irq]);
-#endif
-#endif
 	struct speedo_private *sp;
 	int ioaddr, boguscnt = max_interrupt_work;
 	unsigned short status;
@@ -1161,8 +1012,10 @@
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
 #ifndef final_version
-	if (dev->interrupt) {
-		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+	/* A lock to prevent simultaneous entry on SMP machines. */
+	if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
+		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+			   dev->name);
 		return;
 	}
 	dev->interrupt = 1;
@@ -1184,19 +1037,6 @@
 			speedo_rx(dev);
 
 		if (status & 0x1000) {
-#ifdef notdef
-		  int i;
-		  printk(KERN_WARNING"%s: The EEPro100 receiver left the ready"
-				 " state -- %4.4x!  Index %d (%d).\n", dev->name, status,
-				 sp->cur_rx, sp->cur_rx % RX_RING_SIZE);
-		  printk(KERN_WARNING "   Rx ring:\n ");
-		  for (i = 0; i < RX_RING_SIZE; i++)
-			printk("   %d %8.8x %8.8x %8.8x %d %d.\n",
-				   i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link,
-				   sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count,
-				   sp->rx_ringp[i]->size);
-#endif
-
 		  if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
 			outw(RX_RESUMENR, ioaddr + SCBCmd);
 		  else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
@@ -1243,7 +1083,7 @@
 				&& dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {
 				/* The ring is no longer full, clear tbusy. */
 				sp->tx_full = 0;
-				dev->tbusy = 0;
+				clear_bit(0, (void*)&dev->tbusy);
 				mark_bh(NET_BH);
 			}
 
@@ -1263,23 +1103,8 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
-#ifndef final_version
-	/* Special code for testing *only*. */
-	{
-		static int stopit = 100;
-		if (dev->start == 0  &&  --stopit < 0) {
-			printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n",
-				   dev->name);
-#ifdef SA_SHIRQ
-			free_irq(irq, dev);
-#else
-			free_irq(irq);
-#endif
-		}
-	}
-#endif
-
 	dev->interrupt = 0;
+	clear_bit(0, (void*)&sp->in_interrupt);
 	return;
 }
 
@@ -1320,16 +1145,6 @@
 
 				/* Pass up the skb already on the Rx ring. */
 				skb = sp->rx_skbuff[entry];
-#ifdef KERNEL_1_2
-				temp = skb->data;
-				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
-						   " in speedo_rx: %p vs. %p / %p.\n", dev->name,
-						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-						   temp, skb->data);
-				/* Get a fresh skbuff to replace the filled one. */
-				newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#else
 				temp = skb_put(skb, pkt_len);
 				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
 					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
@@ -1337,36 +1152,21 @@
 						   sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
 				/* Get a fresh skbuff to replace the filled one. */
 				newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#endif
+
 				if (newskb) {
 					struct RxFD *rxf;
 					rx_in_place = 1;
 					sp->rx_skbuff[entry] = newskb;
 					newskb->dev = dev;
-#ifdef KERNEL_1_2
-					/* Restore the data in the old header region. */
-					memcpy(skb->data - sizeof(struct RxFD),
-						   &sp->saved_skhead[entry], sizeof(struct RxFD));
-					/* Save the data in this header region. */
-					rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD));
-					sp->rx_ringp[entry] = rxf;
-					memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD));
-					rxf->rx_buf_addr = virt_to_bus(newskb->data);
-#else
 					rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail;
 					skb_reserve(newskb, sizeof(struct RxFD));
 					/* Unused by i82557, consistency check only. */
 					rxf->rx_buf_addr = virt_to_bus(newskb->tail);
-#endif
 					rxf->status = 0x00000001;
 				} else			/* No memory, drop the packet. */
 				  skb = 0;
 			} else
-#ifdef KERNEL_1_2
-				skb = alloc_skb(pkt_len, GFP_ATOMIC);
-#else
 				skb = dev_alloc_skb(pkt_len + 2);
-#endif
 			if (skb == NULL) {
 				int i;
 				printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
@@ -1388,7 +1188,6 @@
 				break;
 			}
 			skb->dev = dev;
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
 			if (! rx_in_place) {
 				skb_reserve(skb, 2);	/* 16 byte align the data fields */
 #if defined(__i386)   &&  notyet
@@ -1401,22 +1200,6 @@
 #endif
 			}
 			skb->protocol = eth_type_trans(skb, dev);
-#else
-#ifdef KERNEL_1_3
-#warning This code has only been tested with later 1.3.* kernels.
-			skb->len = pkt_len;
-			memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-				   pkt_len);
-			/* Needed for 1.3.*. */
-			skb->protocol = eth_type_trans(skb, dev);
-#else	/* KERNEL_1_2 */
-			skb->len = pkt_len;
-			if (! rx_in_place) {
-				memcpy(skb->data,
-					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
-			}
-#endif
-#endif
 			netif_rx(skb);
 			sp->stats.rx_packets++;
 		}
@@ -1460,12 +1243,7 @@
 	outw(INT_MASK, ioaddr + SCBCmd);
 	outw(INT_MASK | RX_ABORT, ioaddr + SCBCmd);
 
-#ifdef SA_SHIRQ
 	free_irq(dev->irq, dev);
-#else
-	free_irq(dev->irq);
-	irq2dev_map[dev->irq] = 0;
-#endif
 
 	/* Free all the skbuffs in the Rx and Tx queues. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -1549,7 +1327,6 @@
 	return &sp->stats;
 }
 
-#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
@@ -1572,7 +1349,6 @@
 		return -EOPNOTSUPP;
 	}
 }
-#endif  /* HAVE_PRIVATE_IOCTL */
 
 /* Set or clear the multicast filter for this adaptor.
    This is very ugly with Intel chips -- we usually have to execute an
@@ -1594,7 +1370,8 @@
 
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
 		new_rx_mode = 3;
-	} else if (dev->flags & IFF_ALLMULTI) {
+	} else if ((dev->flags & IFF_ALLMULTI)  ||
+			   dev->mc_count > multicast_filter_limit) {
 		new_rx_mode = 1;
 	} else
 		new_rx_mode = 0;
@@ -1681,7 +1458,7 @@
 		struct dev_mc_list *mclist;
 		u16 *eaddrs;
 		struct descriptor *mc_setup_frm = sp->mc_setup_frm;
-		u16 *setup_params = (u16 *)mc_setup_frm->params;
+		u16 *setup_params;
 		int i;
 
 		if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
@@ -1751,24 +1528,6 @@
 }
 
 #ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,38))	/* 1.3.38 and later */
-char kernel_version[] = UTS_RELEASE;
-#endif
-
-#if LINUX_VERSION_CODE > 0x20118
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-#endif
 
 int
 init_module(void)
@@ -1815,7 +1574,8 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.0.33/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.0.33/linux/drivers/net/epic100.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/epic100.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,1179 @@
+/* epic100.c: A SMC 83c170 EPIC/100 fast ethernet driver for Linux. */
+/*
+	Written 1997-1998 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+    All other rights reserved.
+
+	This driver is for the SMC83c170/175 "EPIC" series, as used on the
+	SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
+*/
+
+static const char *version =
+"epic100.c:v0.99B 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
+
+/* A few user-configurable values. */
+
+/* Keep the ring sizes a power of two for efficiency.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static int rx_copybreak = 200;
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 10;
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((2000*HZ)/1000)
+
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+/* Bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 128		/* Rounded down to 4 byte units. */
+#define RX_FIFO_THRESH 1		/* 0-3, 0==32, 64,96, or 3==128 bytes  */
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define RUN_AT(x) (jiffies + (x))
+
+#if LINUX_VERSION_CODE < 0x20138
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+#endif
+
+/* The I/O extent. */
+#define EPIC_TOTAL_SIZE 0x100
+
+static int epic_debug = 1;
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the SMC "EPCI/100", the SMC
+single-chip ethernet controllers for PCI.  This chip is used on
+the SMC EtherPower II boards.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+IVb. References
+
+http://www.smc.com/components/catalog/smc83c170.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.national.com/pf/DP/DP83840.html
+
+IVc. Errata
+
+*/
+
+#ifndef PCI_VENDOR_ID_SMC
+#define PCI_VENDOR_ID_SMC			0x10B8
+#endif
+#ifndef PCI_DEVICE_ID_SMC_EPIC100
+#define PCI_DEVICE_ID_SMC_EPIC100	0x0005
+#endif
+
+/* The rest of these values should never change. */
+/* Offsets to registers, using the (ugh) SMC names. */
+enum epic_registers {
+  COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14,
+  TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28,	/* Rx error counters. */
+  MIICtrl=0x30, MIIData=0x34, MIICfg=0x38,
+  LAN0=64,						/* MAC address. */
+  MC0=80,						/* Multicast filter table. */
+  RxCtrl=96, TxCtrl=112, TxSTAT=0x74,
+  PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatus {
+  TxIdle=0x40000, RxIdle=0x20000,
+  CntFull=0x0200, TxUnderrun=0x0100,
+  TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
+  RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
+};
+
+/* The EPIC100 Rx and Tx buffer descriptors. */
+
+struct epic_tx_desc {
+	s16 status;
+	u16 txlength;
+	u32 bufaddr;
+	u16 buflength;
+	u16 control;
+    u32 next;
+};
+
+struct epic_rx_desc {
+	s16 status;
+	u16 rxlength;
+	u32 bufaddr;
+	u32 buflength;
+    u32 next;
+};
+
+struct epic_private {
+	char devname[8];			/* Used only for kernel debugging. */
+	const char *product_name;
+	struct device *next_module;
+
+	/* Rx and Rx rings here so that they remain paragraph aligned. */
+	struct epic_rx_desc rx_ring[RX_RING_SIZE];
+	struct epic_tx_desc tx_ring[TX_RING_SIZE];
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+
+	/* Ring pointers. */
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+
+	u8 pci_bus, pci_dev_fn;				/* PCI bus location. */
+	u16 chip_id;
+
+	struct enet_statistics stats;
+	struct timer_list timer;			/* Media selection timer. */
+	unsigned char mc_filter[8];
+	signed char phys[4];				/* MII device addresses. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int media2:4;				/* Secondary monitored media port. */
+	unsigned int medialock:1;			/* Don't sense media type. */
+	unsigned int mediasense:1;			/* Media sensing in progress. */
+	int pad0, pad1;						/* Used for 8-byte alignment */
+};
+
+/* Used to pass the full-duplex flag, etc. */
+#define MAX_UNITS 8
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+static struct device *epic100_probe1(int pci_bus, int pci_devfn,
+									 struct device *dev, int card_idx);
+static int epic_open(struct device *dev);
+static int read_eeprom(int ioaddr, int location);
+static int mii_read(int ioaddr, int phy_id, int location);
+static void epic_timer(unsigned long data);
+static void epic_tx_timeout(struct device *dev);
+static void epic_init_ring(struct device *dev);
+static int epic_start_xmit(struct sk_buff *skb, struct device *dev);
+static int epic_rx(struct device *dev);
+static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int epic_close(struct device *dev);
+static struct enet_statistics *epic_get_stats(struct device *dev);
+static void set_rx_mode(struct device *dev);
+
+
+/* A list of all installed EPIC devices, for removing the driver module. */
+static struct device *root_epic_dev = NULL;
+
+int epic100_probe(struct device *dev)
+{
+	static int cards_found = 0;
+	static int pci_index = 0;	/* Static, for multiple probe calls. */
+
+	/* Ideally we would detect all network cards in slot order.  That would
+	   be best done a central PCI probe dispatch, which wouldn't work
+	   well with the current structure.  So instead we detect just the
+	   Epic cards in slot order. */
+
+	if (pcibios_present()) {
+		unsigned char pci_bus, pci_device_fn;
+
+		for (;pci_index < 0xff; pci_index++) {
+			u8  pci_latency;
+			u16 pci_command, new_command, vendor, device;
+			u32 pci_ioaddr;
+
+			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+#ifdef REVERSE_PROBE_ORDER
+									0xff - pci_index,
+#else
+									pci_index,
+#endif
+									&pci_bus, &pci_device_fn)
+				!= PCIBIOS_SUCCESSFUL)
+				break;
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_VENDOR_ID, &vendor);
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_DEVICE_ID, &device);
+			if (vendor != PCI_VENDOR_ID_SMC)
+				continue;
+			if (device != PCI_DEVICE_ID_SMC_EPIC100) {
+				printk("Unknown SMC PCI ethernet chip type %4.4x detected:"
+					   " not configured.\n", device);
+				continue;
+			}
+
+			/* Activate the card: fix for brain-damaged Win98 BIOSes. */
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+			if (pci_command != new_command) {
+				printk(KERN_INFO "  The PCI BIOS has not enabled Ethernet"
+					   " device %4.4x-%4.4x."
+					   "  Updating PCI command %4.4x->%4.4x.\n",
+					   vendor, device, pci_command, new_command);
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, new_command);
+			}
+
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			/* Remove I/O space marker in bit 0. */
+			pci_ioaddr &= ~3;
+
+			if (check_region(pci_ioaddr, EPIC_TOTAL_SIZE))
+				continue;
+
+			dev = epic100_probe1(pci_bus, pci_device_fn, dev, cards_found);
+
+			if (dev) {
+				pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_LATENCY_TIMER, &pci_latency);
+				if (pci_latency < 32) {
+					printk("  PCI latency timer (CFLT) value of %d is "
+						   "unreasonably low, setting to 32.\n", pci_latency);
+					pcibios_write_config_byte(pci_bus, pci_device_fn,
+											  PCI_LATENCY_TIMER, 32);
+				} else if (epic_debug > 1)
+					printk("  PCI latency timer (CFLT) is %#x.\n",
+						   pci_latency);
+				dev = 0;
+				cards_found++;
+			}
+		}
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+static struct device *epic100_probe1(int bus, int devfn, struct device *dev,
+									 int card_idx)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct epic_private *tp;
+	int i, option = 0, duplex = 0;
+	u8 irq;
+	u16 chip_id;
+	u32 ioaddr;
+
+	if (epic_debug > 0  &&  did_version++ == 0)
+		printk(version);
+
+	if (dev && dev->mem_start) {
+		option = dev->mem_start;
+		duplex = (dev->mem_start & 16) ? 1 : 0;
+	} else if (card_idx >= 0  &&  card_idx < MAX_UNITS) {
+		if (options[card_idx] >= 0)
+			option = options[card_idx];
+		if (full_duplex[card_idx] >= 0)
+			duplex = full_duplex[card_idx];
+	}
+
+	dev = init_etherdev(dev, 0);
+
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &ioaddr);
+	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &chip_id);
+	ioaddr &= ~3;
+
+	printk("%s: SMC EPIC/100 at %#3x, IRQ %d, ", dev->name, ioaddr, irq);
+
+	/* Bring the chip out of low-power mode. */
+	outl(0x0200, ioaddr + GENCTL);
+	/* Magic?!  If we don't set this bit the MII interface won't work. */
+	outl(0x0008, ioaddr + TEST1);
+
+	/* This could also be read from the EEPROM. */
+	for (i = 0; i < 3; i++)
+		((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4);
+
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x.\n", dev->dev_addr[i]);
+
+	if (epic_debug > 1) {
+	  printk("%s: EEPROM contents\n", dev->name);
+	  for (i = 0; i < 64; i++)
+		printk(" %4.4x%s", read_eeprom(ioaddr, i), i % 16 == 15 ? "\n" : "");
+	}
+
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, EPIC_TOTAL_SIZE, "SMC EPIC/100");
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* The data structures must be quadword aligned. */
+	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
+	memset(tp, 0, sizeof(*tp));
+	dev->priv = tp;
+
+	tp->next_module = root_epic_dev;
+	root_epic_dev = dev;
+
+	tp->chip_id = chip_id;
+
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	{
+		int phy, phy_idx;
+		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+			 phy++) {
+			int mii_status = mii_read(ioaddr, phy, 0);
+			if (mii_status != 0xffff  && mii_status != 0x0000) {
+				tp->phys[phy_idx++] = phy;
+				printk("%s: MII transceiver found at address %d.\n",
+					   dev->name, phy);
+			}
+		}
+		if (phy_idx == 0) {
+			printk("%s: ***WARNING***: No MII transceiver found!\n",
+				   dev->name);
+			/* Use the known PHY address of the EPII. */
+			tp->phys[0] = 3;
+		}
+	}
+
+	/* Leave the chip in low-power mode. */
+	outl(0x0008, ioaddr + GENCTL);
+
+	/* The lower four bits are the media type. */
+	tp->full_duplex = duplex;
+	tp->default_port = option;
+	if (tp->default_port)
+		tp->medialock = 1;
+
+	/* The Epic-specific entries in the device structure. */
+	dev->open = &epic_open;
+	dev->hard_start_xmit = &epic_start_xmit;
+	dev->stop = &epic_close;
+	dev->get_stats = &epic_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+
+	return dev;
+}
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS			0x02	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x08	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x01
+#define EE_WRITE_1		0x09
+#define EE_DATA_READ	0x10	/* EEPROM chip data out. */
+#define EE_ENB			(0x0001 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but 66Mhz is untested.
+ */
+
+#ifdef _LINUX_DELAY_H
+#define eeprom_delay(nanosec)	udelay(1)
+#else
+#define eeprom_delay(nanosec)	do { ; } while (0)
+#endif
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+static int read_eeprom(int ioaddr, int location)
+{
+	int i;
+	int retval = 0;
+	int ee_addr = ioaddr + EECTL;
+	int read_cmd = location | EE_READ_CMD;
+	
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	outl(EE_ENB, ee_addr);
+	
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outl(EE_ENB | dataval, ee_addr);
+		eeprom_delay(100);
+		outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(150);
+		outl(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay(250);
+	}
+	outl(EE_ENB, ee_addr);
+	
+	for (i = 16; i > 0; i--) {
+		outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(100);
+		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outl(EE_ENB, ee_addr);
+		eeprom_delay(100);
+	}
+
+	/* Terminate the EEPROM access. */
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	return retval;
+}
+
+#define MII_READOP		1
+#define MII_WRITEOP		2
+static int mii_read(int ioaddr, int phy_id, int location)
+{
+	int i;
+
+	outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl);
+	/* Typical operation takes < 50 ticks. */
+	for (i = 4000; i > 0; i--)
+		if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0)
+			break;
+	return inw(ioaddr + MIIData);
+}
+
+
+static int
+epic_open(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+	int mii_reg5;
+	int full_duplex = 0;
+
+	/* Soft reset the chip. */
+	outl(0x0001, ioaddr + GENCTL);
+
+	if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev))
+		return -EAGAIN;
+
+	MOD_INC_USE_COUNT;
+
+	epic_init_ring(dev);
+
+	/* This next line by Ken Yamaguchi.. ?? */
+	outl(0x8, ioaddr + 0x1c);
+
+	/* Pull the chip out of low-power mode, enable interrupts, and set for
+	   PCI read multiple. */
+	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+
+	for (i = 0; i < 3; i++)
+		outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4);
+
+	outl(TX_FIFO_THRESH, ioaddr + TxThresh);
+	full_duplex = tp->full_duplex;
+
+	mii_reg5 = mii_read(ioaddr, tp->phys[0], 5);
+	if (mii_reg5 != 0xffff && (mii_reg5 & 0x0100)) {
+		full_duplex = 1;
+		if (epic_debug > 1)
+			printk("%s: Setting %s-duplex based on MII xcvr %d"
+				   " register read of %4.4x.\n", dev->name,
+				   full_duplex ? "full" : "half", tp->phys[0],
+				   mii_read(ioaddr, tp->phys[0], 5));
+	}
+
+	outl(full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+	outl(virt_to_bus(tp->rx_ring), ioaddr + PRxCDAR);
+	outl(virt_to_bus(tp->tx_ring), ioaddr + PTxCDAR);
+
+	/* Start the chip's Rx process. */
+	set_rx_mode(dev);
+	outl(0x000A, ioaddr + COMMAND);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* Enable interrupts by setting the interrupt mask. */
+	outl(CntFull | TxUnderrun | TxDone
+		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
+		 ioaddr + INTMASK);
+
+	if (epic_debug > 1)
+		printk("%s: epic_open() ioaddr %4.4x IRQ %d status %4.4x %s-duplex.\n",
+			   dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL),
+			   full_duplex ? "full" : "half");
+
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer(&tp->timer);
+	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = &epic_timer;				/* timer handler */
+	add_timer(&tp->timer);
+
+	return 0;
+}
+
+static void epic_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int next_tick = 0;
+
+	if (epic_debug > 3) {
+		printk("%s: Media selection tick, Tx status %8.8x.\n",
+			   dev->name, inl(ioaddr + TxSTAT));
+		printk("%s: Other registers are IntMask %4.4x IntStatus %4.4x RxStatus"
+			   " %4.4x.\n",
+			   dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT),
+			   inl(ioaddr + RxSTAT));
+	}
+
+	if (next_tick) {
+		tp->timer.expires = RUN_AT(next_tick);
+		add_timer(&tp->timer);
+	}
+}
+
+static void epic_tx_timeout(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (epic_debug > 0) {
+		printk("%s: Transmit timeout using MII device, Tx status %4.4x.\n",
+			   dev->name, inw(ioaddr + TxSTAT));
+		if (epic_debug > 1) {
+			printk("%s: Tx indices: dirty_tx %d, cur_tx %d.\n",
+			 dev->name, tp->dirty_tx, tp->cur_tx);
+		}
+	}
+	/* Perhaps stop and restart the chip's Tx processes . */
+	/* Trigger a transmit demand. */
+	outl(0x0004, dev->base_addr + COMMAND);
+
+	dev->trans_start = jiffies;
+	tp->stats.tx_errors++;
+	return;
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+epic_init_ring(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int i;
+
+	tp->tx_full = 0;
+	tp->cur_rx = tp->cur_tx = 0;
+	tp->dirty_rx = tp->dirty_tx = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		tp->rx_ring[i].status = 0x8000;		/* Owned by Epic chip */
+		tp->rx_ring[i].buflength = PKT_BUF_SZ;
+		{
+			/* Note the receive buffer must be longword aligned.
+			   dev_alloc_skb() provides 16 byte alignment.  But do *not*
+			   use skb_reserve() to align the IP header! */
+			struct sk_buff *skb;
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			tp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
+			tp->rx_ring[i].bufaddr = virt_to_bus(skb->tail);
+		}
+		tp->rx_ring[i].next = virt_to_bus(&tp->rx_ring[i+1]);
+	}
+	/* Mark the last entry as wrapping the ring. */
+	tp->rx_ring[i-1].next = virt_to_bus(&tp->rx_ring[0]);
+
+	/* The Tx buffer descriptor is filled in as needed, but we
+	   do need to clear the ownership bit. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_ring[i].status = 0x0000;
+		tp->tx_ring[i].next = virt_to_bus(&tp->tx_ring[i+1]);
+	}
+	tp->tx_ring[i-1].next = virt_to_bus(&tp->tx_ring[0]);
+}
+
+static int
+epic_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int entry;
+	u32 flag;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start < TX_TIMEOUT)
+			return 1;
+		epic_tx_timeout(dev);
+		return 1;
+	}
+
+	/* Caution: the write order is important here, set the base address
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % TX_RING_SIZE;
+
+	tp->tx_skbuff[entry] = skb;
+	tp->tx_ring[entry].txlength = (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
+	tp->tx_ring[entry].bufaddr = virt_to_bus(skb->data);
+	tp->tx_ring[entry].buflength = skb->len;
+
+	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+	  flag = 0x10; /* No interrupt */
+	  clear_bit(0, (void*)&dev->tbusy);
+	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+	  flag = 0x14; /* Tx-done intr. */
+	  clear_bit(0, (void*)&dev->tbusy);
+	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+	  flag = 0x10; /* No Tx-done intr. */
+	  clear_bit(0, (void*)&dev->tbusy);
+	} else {
+	  /* Leave room for two additional entries. */
+	  flag = 0x14; /* Tx-done intr. */
+	  tp->tx_full = 1;
+	}
+
+	tp->tx_ring[entry].control = flag;
+	tp->tx_ring[entry].status = 0x8000;	/* Pass ownership to the chip. */
+	tp->cur_tx++;
+	/* Trigger an immediate transmit demand. */
+	outl(0x0004, dev->base_addr + COMMAND);
+
+	dev->trans_start = jiffies;
+	if (epic_debug > 4)
+		printk("%s: Queued Tx packet size %d to slot %d, "
+			   "flag %2.2x Tx status %8.8x.\n",
+			   dev->name, (int)skb->len, entry, flag,
+			   inl(dev->base_addr + TxSTAT));
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *)dev_instance;
+	struct epic_private *lp;
+	int status, ioaddr, boguscnt = max_interrupt_work;
+
+	ioaddr = dev->base_addr;
+	lp = (struct epic_private *)dev->priv;
+	if (dev->interrupt) {
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+		return;
+	}
+	dev->interrupt = 1;
+
+	do {
+		status = inl(ioaddr + INTSTAT);
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outl(status & 0x00007fff, ioaddr + INTSTAT);
+
+		if (epic_debug > 4)
+			printk("%s: interrupt  interrupt=%#8.8x new intstat=%#8.8x.\n",
+				   dev->name, status, inl(ioaddr + INTSTAT));
+
+		if ((status & (RxDone | TxEmpty | TxDone)) == 0)
+			break;
+
+		if (status & RxDone)			/* Rx interrupt */
+			epic_rx(dev);
+
+		if (status & (TxEmpty | TxDone)) {
+			int dirty_tx;
+
+			for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				int txstatus = lp->tx_ring[entry].status;
+
+				if (txstatus < 0)
+					break;			/* It still hasn't been Txed */
+
+				if ( ! (txstatus & 0x0001)) {
+					/* There was an major error, log it. */
+#ifndef final_version
+					if (epic_debug > 1)
+						printk("%s: Transmit error, Tx status %8.8x.\n",
+							   dev->name, txstatus);
+#endif
+					lp->stats.tx_errors++;
+					if (txstatus & 0x1050) lp->stats.tx_aborted_errors++;
+					if (txstatus & 0x0008) lp->stats.tx_carrier_errors++;
+					if (txstatus & 0x0040) lp->stats.tx_window_errors++;
+					if (txstatus & 0x0010) lp->stats.tx_fifo_errors++;
+#ifdef ETHER_STATS
+					if (txstatus & 0x1000) lp->stats.collisions16++;
+#endif
+				} else {
+#ifdef ETHER_STATS
+					if ((txstatus & 0x0002) != 0) lp->stats.tx_deferred++;
+#endif
+					lp->stats.collisions += (txstatus >> 8) & 15;
+					lp->stats.tx_packets++;
+				}
+
+				/* Free the original skb. */
+				dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+				lp->tx_skbuff[entry] = 0;
+			}
+
+#ifndef final_version
+			if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (lp->tx_full && dev->tbusy
+				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+				/* The ring is no longer full, clear tbusy. */
+				lp->tx_full = 0;
+				clear_bit(0, (void*)&dev->tbusy);
+				mark_bh(NET_BH);
+			}
+
+			lp->dirty_tx = dirty_tx;
+		}
+
+		/* Check uncommon events all at once. */
+		if (status & (CntFull | TxUnderrun | RxOverflow)) {
+			/* Always update the error counts to avoid overhead later. */
+			lp->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+			lp->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+			lp->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+
+			if (status & TxUnderrun) { /* Tx FIFO underflow. */
+			  lp->stats.tx_fifo_errors++;
+			  /* Restart the transmit process. */
+			  outl(0x0080, ioaddr + COMMAND);
+			}
+			if (status & RxOverflow) {		/* Missed a Rx frame. */
+				lp->stats.rx_errors++;
+			}
+			/* Clear all error sources. */
+			outl(status & 0x7f18, ioaddr + INTSTAT);
+		}
+		if (--boguscnt < 0) {
+			printk("%s: Too much work at interrupt, IntrStatus=0x%8.8x.\n",
+				   dev->name, status);
+			/* Clear all interrupt sources. */
+			outl(0x0001ffff, ioaddr + INTSTAT);
+			break;
+		}
+	} while (1);
+
+	if (epic_debug > 3)
+		printk("%s: exiting interrupt, intr_status=%#4.4x.\n",
+			   dev->name, inl(ioaddr + INTSTAT));
+
+	dev->interrupt = 0;
+	return;
+}
+
+static int
+epic_rx(struct device *dev)
+{
+	struct epic_private *lp = (struct epic_private *)dev->priv;
+	int entry = lp->cur_rx % RX_RING_SIZE;
+
+	if (epic_debug > 4)
+		printk(" In epic_rx(), entry %d %8.8x.\n", entry,
+			   lp->rx_ring[entry].status);
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while (lp->rx_ring[entry].status >= 0) {
+		int status = lp->rx_ring[entry].status;
+
+		if (epic_debug > 4)
+			printk("  epic_rx() status was %8.8x.\n", status);
+		if (status & 0x2000) {
+			printk("%s: Oversized Ethernet frame spanned multiple buffers,"
+				   " status %4.4x!\n", dev->name, status);
+			  lp->stats.rx_length_errors++;
+		} else if (status & 0x0006) {
+			/* Rx Frame errors are counted in hardware. */
+			lp->stats.rx_errors++;
+		} else {
+			/* Malloc up new buffer, compatible with net-2e. */
+			/* Omit the four octet CRC from the length. */
+			short pkt_len = lp->rx_ring[entry].rxlength - 4;
+			struct sk_buff *skb;
+			int rx_in_place = 0;
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len > rx_copybreak) {
+				struct sk_buff *newskb;
+				char *temp;
+
+				/* Pass up the skb already on the Rx ring. */
+				skb = lp->rx_skbuff[entry];
+				temp = skb_put(skb, pkt_len);
+				if (bus_to_virt(lp->rx_ring[entry].bufaddr) != temp)
+					printk("%s: Warning -- the skbuff addresses do not match"
+						   " in epic_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(lp->rx_ring[entry].bufaddr),
+						   skb->head, temp);
+				/* Get a fresh skbuff to replace the filled one. */
+				newskb = dev_alloc_skb(PKT_BUF_SZ);
+				if (newskb) {
+					rx_in_place = 1;
+					lp->rx_skbuff[entry] = newskb;
+					newskb->dev = dev;
+					/* Align IP on 16 byte boundaries */
+					skb_reserve(newskb, 2);
+					lp->rx_ring[entry].bufaddr = virt_to_bus(newskb->tail);
+				} else			/* No memory, drop the packet. */
+				  skb = 0;
+			} else
+				skb = dev_alloc_skb(pkt_len + 2);
+			if (skb == NULL) {
+				int i;
+				printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+				/* Check that at least two ring entries are free.
+				   If not, free one and mark stats->rx_dropped++. */
+				for (i = 0; i < RX_RING_SIZE; i++)
+					if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
+						break;
+
+				if (i > RX_RING_SIZE -2) {
+					lp->stats.rx_dropped++;
+					lp->rx_ring[entry].status = 0x8000;
+					lp->cur_rx++;
+				}
+				break;
+			}
+			skb->dev = dev;
+			if (! rx_in_place) {
+				skb_reserve(skb, 2);	/* 16 byte align the data fields */
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(lp->rx_ring[entry].bufaddr), pkt_len);
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		}
+
+		lp->rx_ring[entry].status = 0x8000;
+		entry = (++lp->cur_rx) % RX_RING_SIZE;
+	}
+
+	return 0;
+}
+
+static int
+epic_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (epic_debug > 1)
+		printk("%s: Shutting down ethercard, status was %2.2x.\n",
+			   dev->name, inl(ioaddr + INTSTAT));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outl(0x00000000, ioaddr + INTMASK);
+	/* Stop the chip's Tx and Rx DMA processes. */
+	outw(0x0061, ioaddr + COMMAND);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+	tp->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+	tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+
+	del_timer(&tp->timer);
+
+	free_irq(dev->irq, dev);
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = tp->rx_skbuff[i];
+		tp->rx_skbuff[i] = 0;
+		tp->rx_ring[i].status = 0;		/* Not owned by Epic chip. */
+		tp->rx_ring[i].buflength = 0;
+		tp->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
+		if (skb) {
+#if LINUX_VERSION_CODE < 0x20100
+			skb->free = 1;
+#endif
+			dev_kfree_skb(skb, FREE_WRITE);
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (tp->tx_skbuff[i])
+			dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+		tp->tx_skbuff[i] = 0;
+	}
+
+
+	/* Green! Leave the chip in low-power mode. */
+	outl(0x0008, ioaddr + GENCTL);
+	
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics *
+epic_get_stats(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (dev->start) {
+		/* Update the error counts. */
+		tp->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+		tp->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+		tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+	}
+
+	return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling tp->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+
+/* The little-endian AUTODIN II ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+
+static void set_rx_mode(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	unsigned char mc_filter[8];		 /* Multicast hash filter */
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		outl(0x002C, ioaddr + RxCtrl);
+		/* Unconditionally log net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+	} else if ((dev->mc_count > 0)  ||  (dev->flags & IFF_ALLMULTI)) {
+		/* There is apparently a chip bug, so the multicast filter
+		   is never enabled. */
+		/* Too many to filter perfectly -- accept all multicasts. */
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		outl(0x000C, ioaddr + RxCtrl);
+	} else if (dev->mc_count == 0) {
+		outl(0x0004, ioaddr + RxCtrl);
+		return;
+	} else {					/* Never executed, for now. */
+		struct dev_mc_list *mclist;
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next)
+			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
+					mc_filter);
+	}
+	/* ToDo: perhaps we need to stop the Tx and Rx process here? */
+	if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) {
+		for (i = 0; i < 4; i++)
+			outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4);
+		memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter));
+	}
+	return;
+}
+
+
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *epic_attach(dev_locator_t *loc)
+{
+	struct device *dev;
+	u16 dev_id;
+	u32 io;
+	u8 bus, devfn, irq;
+
+	if (loc->bus != LOC_PCI) return NULL;
+	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+	printk(KERN_INFO "epic_attach(bus %d, function %d)\n", bus, devfn);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+	io &= ~3;
+	dev = epic100_probe1(bus, devfn, NULL, -1);
+	if (dev) {
+		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+		strcpy(node->dev_name, dev->name);
+		node->major = node->minor = 0;
+		node->next = NULL;
+		MOD_INC_USE_COUNT;
+		return node;
+	}
+	return NULL;
+}
+
+static void epic_detach(dev_node_t *node)
+{
+	struct device **devp, **next;
+	printk(KERN_INFO "epic_detach(%s)\n", node->dev_name);
+	for (devp = &root_epic_dev; *devp; devp = next) {
+		next = &((struct epic_private *)(*devp)->priv)->next_module;
+		if (strcmp((*devp)->name, node->dev_name) == 0) break;
+	}
+	if (*devp) {
+		unregister_netdev(*devp);
+		kfree(*devp);
+		*devp = *next;
+		kfree(node);
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+struct driver_operations epic_ops = {
+	"epic_cb", epic_attach, NULL, NULL, epic_detach
+};
+
+#endif  /* Cardbus support */
+
+
+#ifdef MODULE
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+	if (debug >= 0)
+		epic_debug = debug;
+
+#ifdef CARDBUS
+	register_driver(&epic_ops);
+	return 0;
+#else
+	return epic100_probe(0);
+#endif
+}
+
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+#ifdef CARDBUS
+	unregister_driver(&epic_ops);
+#endif
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_epic_dev) {
+		next_dev = ((struct epic_private *)root_epic_dev->priv)->next_module;
+		unregister_netdev(root_epic_dev);
+		release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);
+		kfree(root_epic_dev);
+		root_epic_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c"
+ *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c"
+ *  alt-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic.c -o epic_cb.c -I/usr/src/pcmcia-cs-3.0.0/include/"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.0.33/linux/drivers/net/eql.c	Tue Aug 12 14:15:56 1997
+++ linux/drivers/net/eql.c	Wed Jun  3 15:17:47 1998
@@ -375,7 +375,6 @@
 	equalizer_t *eql = (equalizer_t *) dev->priv;
 	struct device *slave_dev = 0;
 	slave_t *slave;
-	struct sk_buff *skb2;
 
 	if (skb == NULL)
 		return 0;
diff -u --recursive --new-file v2.0.33/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.0.33/linux/drivers/net/eth16i.c	Fri Aug 15 15:35:39 1997
+++ linux/drivers/net/eth16i.c	Wed Jun  3 15:17:47 1998
@@ -332,7 +332,7 @@
 static int eth16i_tx(struct sk_buff *skb, struct device *dev);
 static void eth16i_rx(struct device *dev);
 static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void eth16i_multicast(struct device *dev, int num_addrs, void *addrs); 
+static void eth16i_multicast(struct device *dev); 
 static void eth16i_select_regbank(unsigned char regbank, short ioaddr);
 static void eth16i_initialize(struct device *dev);
 static struct enet_statistics *eth16i_get_stats(struct device *dev);
@@ -1152,7 +1152,7 @@
   return;
 }
 
-static void eth16i_multicast(struct device *dev, int num_addrs, void *addrs)
+static void eth16i_multicast(struct device *dev)
 {
   short ioaddr = dev->base_addr;
   
diff -u --recursive --new-file v2.0.33/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.0.33/linux/drivers/net/hp100.c	Tue Aug  5 09:11:35 1997
+++ linux/drivers/net/hp100.c	Wed Jun  3 15:17:47 1998
@@ -2,7 +2,7 @@
 ** hp100.c 
 ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
 **
-** $Id: hp100.c,v 1.54 1997/06/12 10:37:07 perex Exp perex $
+** $Id: hp100.c,v 1.56 1998/03/04 15:23:59 perex Exp perex $
 **
 ** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
 ** Extended for new busmaster capable chipsets by 
@@ -17,6 +17,7 @@
 ** -- HP J2973  10 Mbit/s PCI 10base-T
 ** -- HP J2573  10/100 ISA
 ** -- Compex ReadyLink ENET100-VG4  10/100 Mbit/s PCI / EISA
+** -- Compex FreedomLine 100/VG  10/100 Mbit/s ISA / EISA / PCI
 ** 
 ** but it should also work with the other CASCADE based adapters.
 **
@@ -27,6 +28,7 @@
 **       -  To reduce interrupt load in busmaster, one could switch off
 **          the interrupts that are used to refill the queues whenever the
 **          queues are filled up to more than a certain threshold.
+**       -  some updates for EISA version of card
 **
 **
 ** This source/code is public free; you can distribute it and/or modify 
@@ -34,6 +36,18 @@
 ** Free Software Foundation) either version two of this License, or any 
 ** later version.
 **
+** 1.55 -> 1.56
+**   - removed printk in misc. interrupt and update statistics to allow
+**     monitoring of card status
+**   - timing changes in xmit routines, relogin to 100VG hub added when
+**     driver does reset
+**   - included fix for Compex FreedomLine PCI adapter
+** 
+** 1.54 -> 1.55
+**   - fixed bad initialization in init_module
+**   - added Compex FreedomLine adapter
+**   - some fixes in card initialization
+**
 ** 1.53 -> 1.54
 **   - added hardware multicast filter support (doesn't work)
 **   - little changes in hp100_sense_lan routine 
@@ -115,6 +129,12 @@
 #ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4
 #define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
 #endif
+#ifndef PCI_VENDOR_ID_COMPEX2
+#define PCI_VENDOR_ID_COMPEX2 0x101a
+#endif
+#ifndef PCI_DEVICE_ID_COMPEX2_100VG
+#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005
+#endif
 
 #define HP100_REGION_SIZE  0x20 /* for ioports */
 
@@ -141,11 +161,17 @@
   u_char bus;
 };
 
+struct hp100_pci_id {
+  u_short vendor;
+  u_short device;
+};
+
 struct hp100_private {
   struct hp100_eisa_id *id;
   u_short chip;
   u_short soft_model;
   u_int memory_size; 
+  u_int virt_memory_size;
   u_short rx_ratio;       /* 1 - 99 */
   u_short priority_tx;    /* != 0 - priority tx */
   u_short mode;           /* PIO, Shared Mem or Busmaster */
@@ -213,10 +239,35 @@
   /* 10/100 EISA card from Compex */
   { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA },
 
+  /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */
+  /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */
+  /*       version of adapter, too... */
+  { 0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA },
+
+  /* 10/100 PCI card from Compex - FreedomLine
+   *
+   * I think this card doesn't like aic7178 scsi controller, but
+   * I haven't tested this much. It works fine on diskless machines.
+   *                            Jacek Lipkowski <sq5bpf@acid.ch.pw.edu.pl>
+   */
+  { 0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI },
+  
   /* 10/100 PCI card from Compex (J2585A compatible) */
   { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI }
+
 };
 
+#define HP100_EISA_IDS_SIZE	(sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id))
+
+static struct hp100_pci_id hp100_pci_ids[] = {
+  { PCI_VENDOR_ID_HP, 		PCI_DEVICE_ID_HP_J2585A },
+  { PCI_VENDOR_ID_HP,		PCI_DEVICE_ID_HP_J2585B },
+  { PCI_VENDOR_ID_COMPEX,	PCI_DEVICE_ID_COMPEX_ENET100VG4 },
+  { PCI_VENDOR_ID_COMPEX2,	PCI_DEVICE_ID_COMPEX2_100VG }
+};
+
+#define HP100_PCI_IDS_SIZE	(sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id))
+
 static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
 static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
 static int hp100_mode = 1;
@@ -238,13 +289,14 @@
 static int  hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev );
 static void hp100_rx( struct device *dev );
 static hp100_stats_t *hp100_get_stats( struct device *dev );
+static void hp100_misc_interrupt( struct device *dev );
 static void hp100_update_stats( struct device *dev );
 static void hp100_clear_stats( int ioaddr );
 static void hp100_set_multicast_list( struct device *dev);
 static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs );
 static void hp100_start_interface( struct device *dev );
 static void hp100_stop_interface( struct device *dev );
-static void hp100_load_eeprom( struct device *dev );
+static void hp100_load_eeprom( struct device *dev, u_short ioaddr );
 static int  hp100_sense_lan( struct device *dev );
 static int  hp100_login_to_vg_hub( struct device *dev, u_short force_relogin );
 static int  hp100_down_vg_link( struct device *dev );
@@ -272,7 +324,7 @@
  *  These functions should - if possible - avoid doing write operations
  *  since this could cause problems when the card is not installed.
  */
-
+ 
 __initfunc(int hp100_probe( struct device *dev ))
 {
   int base_addr = dev ? dev -> base_addr : 0;
@@ -322,17 +374,16 @@
         {
           u_char pci_bus, pci_device_fn;
           u_short pci_command;
+          int pci_id_index;
 
-          if ((pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
-                                    pci_index, &pci_bus,
-                                    &pci_device_fn ) != 0 ) && 
-              (pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B,
-                                    pci_index, &pci_bus,
-                                    &pci_device_fn ) != 0 ) &&
-              (pcibios_find_device( PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4,
-                                    pci_index, &pci_bus,
-                                    &pci_device_fn ) != 0 ) ) break; 
+	  for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ )
+            if ( pcibios_find_device( hp100_pci_ids[ pci_id_index ].vendor,
+            			      hp100_pci_ids[ pci_id_index ].device,
+                                      pci_index, &pci_bus,
+                                      &pci_device_fn ) == 0 ) goto __pci_found;
+          break;
 
+	  __pci_found:
           pcibios_read_config_dword( pci_bus, pci_device_fn,
                                      PCI_BASE_ADDRESS_0, &ioaddr );
 
@@ -342,6 +393,15 @@
 
           pcibios_read_config_word( pci_bus, pci_device_fn,
                                     PCI_COMMAND, &pci_command );
+          if ( !( pci_command & PCI_COMMAND_IO ) )
+            {
+#ifdef HP100_DEBUG
+              printk( "hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name );
+#endif
+              pci_command |= PCI_COMMAND_IO;
+              pcibios_write_config_word( pci_bus, pci_device_fn,
+                                         PCI_COMMAND, pci_command );
+            }
           if ( !( pci_command & PCI_COMMAND_MASTER ) )
             {
 #ifdef HP100_DEBUG
@@ -386,7 +446,7 @@
   u_char uc, uc_1;
   u_int eisa_id;
   u_int chip;
-  u_int memory_size = 0;
+  u_int memory_size = 0, virt_memory_size = 0;
   u_short local_mode, lsw;
   short mem_mapped;
   u_int *mem_ptr_phys, *mem_ptr_virt;
@@ -443,14 +503,18 @@
       return -ENODEV;
     }
 
-  for ( i=0; i<sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id); i++)
-    if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
+  for ( i=0; i < HP100_EISA_IDS_SIZE; i++)
+    if ( hp100_eisa_ids[ i ].id == eisa_id )
       break;
-  if ( i >= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) )
-    {
+  if ( i >= HP100_EISA_IDS_SIZE ) {
+    for ( i = 0; i < HP100_EISA_IDS_SIZE; i++)
+      if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
+        break;
+    if ( i >= HP100_EISA_IDS_SIZE ) {
       printk( "hp100_probe: %s: card at port 0x%x isn't known (id = 0x%x)\n", dev -> name, ioaddr, eisa_id );
-      return -ENODEV;
+        return -ENODEV;
     }
+  }
   eid = &hp100_eisa_ids[ i ];
   if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
     {
@@ -468,7 +532,13 @@
       return -EIO;
     }
 
-  /* Determine driver operation mode
+  /* Make sure, that all registers are correctly updated... */
+
+  hp100_load_eeprom( dev, ioaddr );
+  wait();
+
+  /*
+   * Determine driver operation mode
    *
    * Use the variable "hp100_mode" upon insmod or as kernel parameter to
    * force driver modes:
@@ -478,6 +548,22 @@
    * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
    */
 
+  /*
+   * LSW values:
+   *   0x2278 -> J2585B, PnP shared memory mode
+   *   0x2270 -> J2585B, shared memory mode, 0xdc000
+   *   0xa23c -> J2585B, I/O mapped mode
+   *   0x2240 -> EISA COMPEX, BusMaster (Shasta Chip)
+   *   0x2220 -> EISA HP, I/O (Shasta Chip)
+   *   0x2260 -> EISA HP, BusMaster (Shasta Chip)
+   */
+
+#if 0
+  local_mode = 0x2270;
+  hp100_outw(0xfefe,OPTION_LSW);
+  hp100_outw(local_mode|HP100_SET_LB|HP100_SET_HB,OPTION_LSW);
+#endif
+
   /* hp100_mode value maybe used in future by another card */
   local_mode=hp100_mode;
   if ( local_mode < 1 || local_mode > 4 )
@@ -536,7 +622,8 @@
       else
 	{
 #ifdef HP100_DEBUG
-	  printk("hp100: %s: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n", dev->name);
+	  printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name );
+	  printk("hp100: %s: Trying shared memory mode.\n", dev->name);
 #endif
 	  /* In this case, try shared memory mode */
 	  local_mode=2;
@@ -554,6 +641,7 @@
   mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0);
   mem_ptr_phys = mem_ptr_virt = NULL;
   memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07));
+  virt_memory_size = 0;
 
   /* For memory mapped or busmaster mode, we want the memory address */
   if ( mem_mapped || (local_mode==1))
@@ -574,21 +662,21 @@
       /* However in slave mode we need to remap high (>1GB) card memory  */
       if(local_mode!=1) /* = not busmaster */
 	{
-	  if ( bus == HP100_BUS_PCI )
+	  if ( bus == HP100_BUS_PCI && mem_ptr_phys >= (u_int *)0x100000 )
 	    {
 	      /* We try with smaller memory sizes, if ioremap fails */
-	      for(; memory_size>16383; memory_size=memory_size/2)
+	      for(virt_memory_size = memory_size; virt_memory_size>16383; virt_memory_size>>=1)
 		{
-		  if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,memory_size))==NULL)
+		  if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,virt_memory_size))==NULL)
 		    {
 #ifdef HP100_DEBUG
-		      printk( "hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, memory_size, (u_long)mem_ptr_phys );
+		      printk( "hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys );
 #endif
 		    }	
 		  else
 		    {
 #ifdef HP100_DEBUG
-		      printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt);
+		      printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt);
 #endif
 		      break;
 		    }
@@ -598,7 +686,7 @@
 		{
 		  printk("hp100: %s: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n", dev->name);
 		  local_mode=3;
-		  memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07) );
+		  virt_memory_size = 0;
 		}
 	    }
 	}
@@ -637,6 +725,7 @@
   dev->base_addr = ioaddr;
 
   lp->memory_size = memory_size;
+  lp->virt_memory_size = virt_memory_size;
   lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */
 
   /* memory region for programmed i/o */
@@ -724,7 +813,8 @@
   if ( lp->mode==2 ) /* memory mapped */ 
     {
       printk( "hp100: %s: Memory area at 0x%lx-0x%lx",
-              dev->name,(u_long)mem_ptr_phys,(u_long)mem_ptr_phys+(u_long)lp->memory_size );
+              dev->name,(u_long)mem_ptr_phys,
+              ((u_long)mem_ptr_phys+(mem_ptr_phys>(u_int *)0x100000?(u_long)lp->memory_size:16*1024))-1 );
       if ( mem_ptr_virt )
 	printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
       printk( ".\n" );
@@ -786,7 +876,7 @@
     }
 		
   /* Initiate EEPROM reload */
-  hp100_load_eeprom( dev );
+  hp100_load_eeprom( dev, 0 );
 		
   wait();
 		
@@ -1447,6 +1537,7 @@
 /* tx function for busmaster mode */
 static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev )
 {
+  unsigned long flags;
   int i, ok_flag;
   int ioaddr = dev->base_addr;
   struct hp100_private *lp = (struct hp100_private *)dev->priv;
@@ -1459,7 +1550,9 @@
 
   if ( skb==NULL )
     {
+#ifndef LINUX_2_1
       dev_tint( dev );
+#endif
       return 0;
     }
 	
@@ -1473,7 +1566,7 @@
       printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name);
 #endif
       /* not waited long enough since last tx? */
-      if ( jiffies - dev->trans_start < HZ/10 ) return -EAGAIN;
+      if ( jiffies - dev->trans_start < HZ ) return -EAGAIN;
 
       if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
 	{
@@ -1519,6 +1612,8 @@
 	      {
 		printk( "hp100: %s: interface reset\n", dev->name );
 		hp100_stop_interface( dev );
+		if ( lp->lan_type == HP100_LAN_100 )
+		  lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
 		hp100_start_interface( dev );
 	      }
 	}
@@ -1531,6 +1626,7 @@
    * we have to turn int's off before modifying this, otherwise
    * a tx_pdl_cleanup could occur at the same time
    */
+  save_flags( flags );
   cli();
   ringptr=lp->txrtail;
   lp->txrtail=ringptr->next;
@@ -1557,7 +1653,7 @@
   hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */
 	
   lp->txrcommit++;
-  sti();
+  restore_flags( flags );
 	
   /* Update statistics */	
   lp->stats.tx_packets++;
@@ -1606,7 +1702,11 @@
 	     hp100_inb(TX_PDL),
 	     donecount);
 #endif
+#ifdef LINUX_2_1
+      dev_kfree_skb( lp->txrhead->skb );
+#else
       dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );
+#endif
       lp->txrhead->skb=(void *)NULL;
       lp->txrhead=lp->txrhead->next;
       lp->txrcommit--;
@@ -1627,6 +1727,16 @@
   printk("hp100: %s: start_xmit\n", dev->name);
 #endif
 
+  if ( skb==NULL )
+    {
+#ifndef LINUX_2_1
+      dev_tint( dev );
+#endif
+      return 0;
+    }
+	
+  if ( skb->len <= 0 ) return 0;
+	
   if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
     {
       hp100_stop_interface( dev );
@@ -1649,7 +1759,7 @@
       printk( "hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i );
 #endif
       /* not waited long enough since last failed tx try? */
-      if ( jiffies - dev->trans_start < HZ/2 ) 
+      if ( jiffies - dev->trans_start < HZ ) 
 	{
 #ifdef HP100_DEBUG
 	  printk("hp100: %s: trans_start timing problem\n", dev->name);
@@ -1686,6 +1796,8 @@
 	      {
 		printk( "hp100: %s: interface reset\n", dev->name );
 		hp100_stop_interface( dev );
+		if ( lp->lan_type == HP100_LAN_100 )
+		  lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
 		hp100_start_interface( dev );
 		udelay(1000);
 	      }
@@ -1721,13 +1833,14 @@
       if ( lp->mem_ptr_virt ) /* high pci memory was remapped */
 	{
 	  /* Note: The J2585B needs alignment to 32bits here!  */
-	  memcpy( lp->mem_ptr_virt, skb->data, ( skb->len +3 ) & ~3 );
+	  memcpy( lp->mem_ptr_virt, skb->data, ( skb->len + 3 ) & ~3 );
 	  if ( !ok_flag )
 	    memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len );
 	}
       else
 	{
-	  memcpy_toio( lp->mem_ptr_phys, skb->data, skb->len );
+	  /* Note: The J2585B needs alignment to 32bits here!  */
+	  memcpy_toio( lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3 );
 	  if ( !ok_flag )
 	    memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len );
 	}
@@ -1749,7 +1862,11 @@
   dev->trans_start=jiffies;
   hp100_ints_on();
 	
+#ifdef LINUX_2_1
+  dev_kfree_skb( skb );
+#else
   dev_kfree_skb( skb, FREE_WRITE );
+#endif
 	
 #ifdef HP100_DEBUG_TX
   printk( "hp100: %s: start_xmit: end\n", dev->name );
@@ -1814,7 +1931,7 @@
       else /* programmed i/o */
         header = hp100_inl( DATA32 );
       
-      pkt_len = header & HP100_PKT_LEN_MASK;
+      pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3;
 
 #ifdef HP100_DEBUG_RX
       printk( "hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n",
@@ -1824,10 +1941,6 @@
 #endif
     
       /* Now we allocate the skb and transfer the data into it. */  
-      /* NOTE! This (and the skb_put() below) depends on the skb-functions
-       * allocating more than asked (notably, aligning the request up to
-       * the next 16-byte length).
-       */
       skb = dev_alloc_skb( pkt_len );
       if ( skb == NULL ) /* Not enough memory->drop packet */
 	{
@@ -1849,13 +1962,13 @@
 	  if ( lp->mode==2 )
             {
               if ( lp->mem_ptr_virt )
-                memcpy( ptr, lp->mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
+                memcpy( ptr, lp->mem_ptr_virt, pkt_len );
               /* Note alignment to 32bit transfers */
               else
-                memcpy_fromio( ptr, lp->mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
+                memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len );
             }
 	  else /* io mapped */
-	    insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
+	    insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 );
       
 	  skb->protocol = eth_type_trans( skb, dev );
 
@@ -1987,7 +2100,11 @@
           printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n",dev->name,pkt_len);
 #endif
 	  if(ptr->skb!=NULL)
+#ifdef LINUX_2_1
+	    dev_kfree_skb( ptr->skb );
+#else
 	    dev_kfree_skb( ptr->skb, FREE_READ );					
+#endif
           lp->stats.rx_errors++;
         }
 						
@@ -2055,20 +2172,37 @@
   hp100_page( PERFORMANCE );
 }
 
+static void hp100_misc_interrupt( struct device *dev )
+{
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4216, TRACE );
+  printk("hp100: %s: misc_interrupt\n", dev->name);
+#endif
+
+  /* Note: Statistics counters clear when read. */
+  lp->stats.rx_errors++;
+  lp->stats.tx_errors++;
+}
+
 static void hp100_clear_stats( int ioaddr )
 {
+  unsigned long flags;
+
 #ifdef HP100_DEBUG_B
   hp100_outw( 0x4217, TRACE );
   printk("hp100: %s: clear_stats\n", dev->name);
 #endif
 
+  save_flags( flags );
   cli();
   hp100_page( MAC_CTRL );    /* get all statistics bytes */
   hp100_inw( DROPPED );
   hp100_inb( CRC );
   hp100_inb( ABORT );
   hp100_page( PERFORMANCE );
-  sti();
+  restore_flags( flags );
 }
 
 
@@ -2080,8 +2214,9 @@
  *  Set or clear the multicast filter for this adapter.
  */
                                                           
-static void hp100_set_multicast_list( struct device *dev)
+static void hp100_set_multicast_list( struct device *dev )
 {
+  unsigned long flags;
   int ioaddr = dev->base_addr;
   struct hp100_private *lp = (struct hp100_private *)dev->priv;
 
@@ -2090,6 +2225,7 @@
   printk("hp100: %s: set_mc_list\n", dev->name);
 #endif
 
+  save_flags( flags );
   cli();
   hp100_ints_off();
   hp100_page( MAC_CTRL );
@@ -2223,7 +2359,7 @@
 
   hp100_page( PERFORMANCE );
   hp100_ints_on();
-  sti();
+  restore_flags( flags );
 }
 
 
@@ -2354,12 +2490,15 @@
    */
   if ( val & HP100_MISC_ERROR ) /* New for J2585B */
     {
+#ifdef HP100_DEBUG_IRQ
       printk("hp100: %s: Misc. Error Interrupt - Check cabling.\n", dev->name);
+#endif
       if(lp->mode==1)
 	{
 	  hp100_clean_txring( dev );
 	  hp100_rxfill( dev );
 	}
+      hp100_misc_interrupt( dev );
     }
 	
   dev->interrupt = 0;
@@ -2373,6 +2512,7 @@
 
 static void hp100_start_interface( struct device *dev )
 {
+  unsigned long flags;
   int ioaddr = dev->base_addr;
   struct hp100_private *lp = (struct hp100_private *)dev->priv;
 
@@ -2381,6 +2521,7 @@
   printk("hp100: %s: hp100_start_interface\n",dev->name);
 #endif
 
+  save_flags( flags );
   cli();
 
   /* Ensure the adapter does not want to request an interrupt when */
@@ -2430,8 +2571,9 @@
     }
 	
   /* Enable MAC Tx and RX, set MAC modes, ... */
-  /* Note: This function also turns on the interrupts. */
   hp100_set_multicast_list( dev );
+
+  restore_flags( flags );
 }
 
 
@@ -2473,10 +2615,10 @@
 }
 
 
-static void hp100_load_eeprom( struct device *dev )
+static void hp100_load_eeprom( struct device *dev, u_short probe_ioaddr )
 {
   int i;
-  int ioaddr = dev->base_addr;
+  int ioaddr = probe_ioaddr > 0 ? probe_ioaddr : dev->base_addr;
 
 #ifdef HP100_DEBUG_B
   hp100_outw( 0x4222, TRACE );
@@ -2915,14 +3057,13 @@
 
 int init_module( void )
 {
-  int	i;
-  int	ret = 0;
+  int	i, cards;
 
   if (hp100_port == 0 && !EISA_bus && !pcibios_present())
     printk("hp100: You should not use auto-probing with insmod!\n");
 
   /* Loop on all possible base addresses */
-  i = -1;
+  i = -1; cards = 0;
   while((hp100_port[++i] != -1) && (i < 5))
     {
       /* Create device and set basics args */
@@ -2939,11 +3080,12 @@
 	  /* Note: if dev->priv is mallocated, there is no way to fail */
 	  kfree_s(hp100_devlist[i], sizeof(struct device));
 	  hp100_devlist[i] = (struct device *) NULL;
-	  ret = -EIO;
 	}
+       else
+        cards++;
     }			/* Loop over all devices */
 
-  return ret;
+  return cards > 0 ? 0 : -ENODEV;
 }
 
 void cleanup_module( void )
diff -u --recursive --new-file v2.0.33/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.0.33/linux/drivers/net/lance.c	Tue Apr  8 08:47:46 1997
+++ linux/drivers/net/lance.c	Wed Jun  3 15:17:47 1998
@@ -1,6 +1,6 @@
-/* lance.c: An AMD LANCE ethernet driver for linux. */
+/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */
 /*
-	Written 1993,1994,1995 by Donald Becker.
+	Written/copyright 1993-1998 by Donald Becker.
 
 	Copyright 1993 United States Government as represented by the
 	Director, National Security Agency.
@@ -8,13 +8,12 @@
 	of the GNU Public License, incorporated herein by reference.
 
 	This driver is for the Allied Telesis AT1500 and HP J2405A, and should work
-	with most other LANCE-based bus-master (NE2100 clone) ethercards.
+	with most other LANCE-based bus-master (NE2100/NE2500) ethercards.
 
 	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
-
 	Fixing alignment problem with 1.3.* kernel and some minor changes
 	by Andrey V. Savochkin, 1996.
 
@@ -28,12 +27,33 @@
 	But I should to inform you that I'm not an expert in the LANCE card
 	and it may occurs that you will receive no answer on your mail
 	to Donald Becker. I didn't receive any answer on all my letters
-	to him. Who knows why... But may be you are more lucky?  ;-)
+	to him. Who knows why... But may be you are more lucky?  ;->
                                                           SAW
-    Fixed 7990 autoIRQ failure and reversed unneeded alignment. 8/20/96 djb
+
+	Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
+	- added support for Linux/Alpha, but removed most of it, because
+        it worked only for the PCI chip. 
+      - added hook for the 32bit lance driver
+      - added PCnetPCI II (79C970A) to chip table
+	Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
+	- hopefully fix above so Linux/Alpha can use ISA cards too.
+    8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
+    v1.12 10/27/97 Module support -djb
+    v1.14  2/3/98 Module support modified, made PCI support optional -djb
 */
 
-static const char *version = "lance.c:v1.09 Aug 20 1996 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "lance.c:v1.14 2/3/1998 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -54,8 +74,9 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
-void lance_probe1(int ioaddr);
+static unsigned int lance_portlist[] = { 0x300, 0x320, 0x340, 0x360, 0};
+int lance_probe(struct device *dev);
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options);
 
 #ifdef HAVE_DEVLIST
 struct netdev_entry lance_drv =
@@ -96,7 +117,7 @@
 probed for by enabling each free DMA channel in turn and checking if
 initialization succeeds.
 
-The HP-J2405A board is an exception: with this board it's easy to read the
+The HP-J2405A board is an exception: with this board it is easy to read the
 EEPROM-set values for the base, IRQ, and DMA.  (Of course you must already
 _know_ the base address -- that field is for writing the EEPROM.)
 
@@ -155,26 +176,11 @@
 
 */
 
-/* Memory accessed from LANCE card must be aligned on 8-byte boundaries.
-   But we can't believe that kmalloc()'ed memory satisfies it. -- SAW */
-#define LANCE_KMALLOC(x) \
-	((void *) (((unsigned long)kmalloc((x)+7, GFP_DMA | GFP_KERNEL)+7) & ~7))
-
-/*
- * Changes:
- *	Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
- *	- added support for Linux/Alpha, but removed most of it, because
- *        it worked only for the PCI chip. 
- *      - added hook for the 32bit lance driver
- *      - added PCnetPCI II (79C970A) to chip table
- *
- *	Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
- *	- hopefully fix above so Linux/Alpha can use ISA cards too.
- */
-
 /* Set the number of Tx and Rx buffers, using Log_2(# buffers).
    Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
-   That translates to 4 and 4 (16 == 2^^4). */
+   That translates to 4 and 4 (16 == 2^^4).
+   This is a compile-time option for efficiency.
+   */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 4
 #define LANCE_LOG_RX_BUFFERS 4
@@ -228,6 +234,8 @@
 	const char *name;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	unsigned long rx_buffs;		/* Address of Rx and Tx buffers. */
 	/* Tx low-memory "bounce buffer" address. */
 	char (*tx_bounce_buffs)[PKT_BUF_SZ];
@@ -299,15 +307,74 @@
 
 
 
-/* This lance probe is unlike the other board probes in 1.0.*.  The LANCE may
-   have to allocate a contiguous low-memory region for bounce buffers.
-   This requirement is satisfied by having the lance initialization occur
-   before the memory management system is started, and thus well before the
-   other probes. */
+#ifdef MODULE
+#define MAX_CARDS		8	/* Max number of interfaces (cards) per module */
+#define IF_NAMELEN		8	/* # of chars for storing dev->name */
+
+static int io[MAX_CARDS] = { 0, };
+static int dma[MAX_CARDS] = { 0, };
+static int irq[MAX_CARDS]  = { 0, };
+
+static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, };
+static struct device dev_lance[MAX_CARDS] =
+{{
+    0, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, NULL}};
+
+int init_module(void)
+{
+	int this_dev, found = 0;
+
+	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_lance[this_dev];
+		dev->name = ifnames[this_dev];
+		dev->irq = irq[this_dev];
+		dev->base_addr = io[this_dev];
+		dev->dma = dma[this_dev];
+		dev->init = lance_probe;
+		if (io[this_dev] == 0)  {
+			if (this_dev != 0) break; /* only complain once */
+			printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
+			return -EPERM;
+		}
+		if (register_netdev(dev) != 0) {
+			printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]);
+			if (found != 0) return 0;	/* Got at least one. */
+			return -ENXIO;
+		}
+		found++;
+	}
+
+	return 0;
+}
 
-int lance_init(void)
+void
+cleanup_module(void)
 {
-	int *port;
+	int this_dev;
+
+	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_lance[this_dev];
+		if (dev->priv != NULL) {
+			kfree(dev->priv);
+			dev->priv = NULL;
+			free_irq(dev->irq, NULL);
+			release_region(dev->base_addr, LANCE_TOTAL_SIZE);
+			unregister_netdev(dev);
+		}
+	}
+}
+#endif /* MODULE */
+
+/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other
+   board probes now that kmalloc() can allocate ISA DMA-able regions.
+   This also allows the LANCE driver to be used as a module.
+   */
+int lance_probe(struct device *dev)
+{
+	int *port, result;
 
 	if (high_memory <= 16*1024*1024)
 		lance_need_isa_bounce_buffers = 0;
@@ -346,8 +413,9 @@
 			}
 			printk("Found PCnet/PCI at %#x, irq %d.\n",
 				   pci_ioaddr, pci_irq_line);
-			lance_probe1(pci_ioaddr);
+			result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0);
 			pci_irq_line = 0;
+			if (!result) return 0;
 		}
 	}
 #endif  /* defined(CONFIG_PCI) */
@@ -361,16 +429,17 @@
 			char offset15, offset14 = inb(ioaddr + 14);
 			
 			if ((offset14 == 0x52 || offset14 == 0x57) &&
-				((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
-				lance_probe1(ioaddr);
+				((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) {
+				result = lance_probe1(dev, ioaddr, 0, 0);
+				if ( !result ) return 0;
+			}
 		}
 	}
-	return 0;
+	return -ENODEV;
 }
 
-void lance_probe1(int ioaddr)
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options)
 {
-	struct device *dev;
 	struct lance_private *lp;
 	short dma_channels;					/* Mark spuriously-busy DMA channels */
 	int i, reset_val, lance_version;
@@ -407,7 +476,7 @@
 
 	outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
 	if (inw(ioaddr+LANCE_DATA) != 0x0004)
-		return;
+		return -ENODEV;
 
 	/* Get the version of the chip. */
 	outw(88, ioaddr+LANCE_ADDR);
@@ -420,7 +489,7 @@
 		if (lance_debug > 2)
 			printk("  LANCE chip version is %#x.\n", chip_version);
 		if ((chip_version & 0xfff) != 0x003)
-			return;
+			return -ENODEV;
 		chip_version = (chip_version >> 12) & 0xffff;
 		for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
 			if (chip_table[lance_version].id_number == chip_version)
@@ -428,7 +497,9 @@
 		}
 	}
 
-	dev = init_etherdev(0, 0);
+	/* We can't use init_etherdev() to allocate dev->priv because it must
+	   a ISA DMA-able region. */
+	dev = init_etherdev(dev, 0);
 	dev->open = lance_open_fail;
 	chipname = chip_table[lance_version].name;
 	printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
@@ -442,15 +513,15 @@
 	request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
 #ifdef CONFIG_LANCE32
-        /* look if it's a PCI or VLB chip */
-        if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) {
-	    extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
+	/* look if it's a PCI or VLB chip */
+	if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) {
+	    extern int lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
 	    
-	    lance32_probe1 (dev, chipname, pci_irq_line);
-	    return;
+	    return lance32_probe1 (dev, chipname, pci_irq_line);
 	}
 #endif    
 	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
+		
 	lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7,
 										   GFP_DMA | GFP_KERNEL)+7) & ~7);
 	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
@@ -484,9 +555,9 @@
 	outw(0x0000, ioaddr+LANCE_ADDR);
 	inw(ioaddr+LANCE_ADDR);
 
-	if (pci_irq_line) {
+	if (irq) {					/* Set iff PCI card. */
 		dev->dma = 4;			/* Native bus-master, no DMA channel needed. */
-		dev->irq = pci_irq_line;
+		dev->irq = irq;
 	} else if (hp_builtin) {
 		static const char dma_tbl[4] = {3, 5, 6, 0};
 		static const char irq_tbl[4] = {3, 4, 5, 9};
@@ -535,7 +606,7 @@
 			printk(", probed IRQ %d", dev->irq);
 		else {
 			printk(", failed to detect IRQ line.\n");
-			return;
+			return -ENODEV;
 		}
 
 		/* Check for the initialization done bit, 0x0100, which means
@@ -549,7 +620,7 @@
 	} else if (dev->dma) {
 		if (request_dma(dev->dma, chipname)) {
 			printk("DMA %d allocation failed.\n", dev->dma);
-			return;
+			return -ENODEV;
 		} else
 			printk(", assigned DMA %d.\n", dev->dma);
 	} else {			/* OK, we have to auto-DMA. */
@@ -584,7 +655,7 @@
 		}
 		if (i == 4) {			/* Failure: bail. */
 			printk("DMA detection failed.\n");
-			return;
+			return -ENODEV;
 		}
 	}
 
@@ -597,7 +668,7 @@
 		dev->irq = autoirq_report(4);
 		if (dev->irq == 0) {
 			printk("  Failed to detect the 7990 IRQ line.\n");
-			return;
+			return -ENODEV;
 		}
 		printk("  Auto-IRQ detected IRQ%d.\n", dev->irq);
 	}
@@ -606,7 +677,8 @@
 		/* Turn on auto-select of media (10baseT or BNC) so that the user
 		   can watch the LEDs even if the board isn't opened. */
 		outw(0x0002, ioaddr+LANCE_ADDR);
-		outw(0x0002, ioaddr+LANCE_BUS_IF);
+		/* Don't touch 10base2 power bit. */
+		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
 	}
 
 	if (lance_debug > 0  &&  did_version++ == 0)
@@ -619,7 +691,7 @@
 	dev->get_stats = lance_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 
-	return;
+	return 0;
 }
 
 static int
@@ -638,15 +710,15 @@
 	int i;
 
 	if (dev->irq == 0 ||
-		request_irq(dev->irq, &lance_interrupt, 0, lp->name, NULL)) {
+		request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) {
 		return -EAGAIN;
 	}
 
+	MOD_INC_USE_COUNT;
+
 	/* We used to allocate DMA here, but that was silly.
 	   DMA lines can't be shared!  We now permanently allocate them. */
 
-	irq2dev_map[dev->irq] = dev;
-
 	/* Reset the LANCE */
 	inw(ioaddr+LANCE_RESET);
 
@@ -663,8 +735,9 @@
 	if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
 		/* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
 		outw(0x0002, ioaddr+LANCE_ADDR);
-		outw(0x0002, ioaddr+LANCE_BUS_IF);
-	}
+		/* Only touch autoselect bit. */
+		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
+ 	}
 
 	if (lance_debug > 1)
 		printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
@@ -745,12 +818,26 @@
 	lp->dirty_rx = lp->dirty_tx = 0;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;
+		struct sk_buff *skb;
+		void *rx_buff;
+
+		skb = alloc_skb(PKT_BUF_SZ, GFP_DMA | GFP_KERNEL);
+		lp->rx_skbuff[i] = skb;
+		if (skb) {
+			skb->dev = dev;
+			rx_buff = skb->tail;
+		} else
+			rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | GFP_KERNEL);
+		if (rx_buff == NULL)
+			lp->rx_ring[i].base = 0;
+		else
+			lp->rx_ring[i].base = (u32)virt_to_bus(rx_buff) | 0x80000000;
 		lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
 	}
 	/* The Tx buffer address is filled in as needed, but we do need to clear
 	   the upper ownership bit. */
 	for (i = 0; i < TX_RING_SIZE; i++) {
+		lp->tx_skbuff[i] = 0;
 		lp->tx_ring[i].base = 0;
 	}
 
@@ -816,18 +903,10 @@
 
 		dev->tbusy=0;
 		dev->trans_start = jiffies;
-		dev_kfree_skb(skb, FREE_WRITE);
-		return 0;
-	}
 
-	if (skb == NULL) {
-		dev_tint(dev);
 		return 0;
 	}
 
-	if (skb->len <= 0)
-		return 0;
-
 	if (lance_debug > 3) {
 		outw(0x0000, ioaddr+LANCE_ADDR);
 		printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
@@ -904,7 +983,7 @@
 static void
 lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct device *dev = (struct device *)dev_id;
 	struct lance_private *lp;
 	int csr0, ioaddr, boguscnt=10;
 	int must_restart;
@@ -1111,6 +1190,7 @@
 {
 	int ioaddr = dev->base_addr;
 	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int i;
 
 	dev->start = 0;
 	dev->tbusy = 1;
@@ -1132,10 +1212,25 @@
 	if (dev->dma != 4)
 		disable_dma(dev->dma);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
-	irq2dev_map[dev->irq] = 0;
+	/* Free all the skbuffs in the Rx and Tx queues. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = lp->rx_skbuff[i];
+		lp->rx_skbuff[i] = 0;
+		lp->rx_ring[i].base = 0;		/* Not owned by LANCE chip. */
+		if (skb) {
+			skb->free = 1;
+			dev_kfree_skb(skb, FREE_WRITE);
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (lp->tx_skbuff[i])
+			dev_kfree_skb(lp->tx_skbuff[i], FREE_WRITE);
+		lp->tx_skbuff[i] = 0;
+	}
 
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1198,8 +1293,9 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c"
  *  c-indent-level: 4
+ *  c-basic-offset: 4
  *  tab-width: 4
  * End:
  */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/lance32.c linux/drivers/net/lance32.c
--- v2.0.33/linux/drivers/net/lance32.c	Mon Aug  4 12:11:05 1997
+++ linux/drivers/net/lance32.c	Wed Dec 31 16:00:00 1969
@@ -1,849 +0,0 @@
-/* lance32.c: An AMD PCnet32 ethernet driver for linux. */
-/*
- *      Copyright 1996 Thomas Bogendoerfer
- * 
- * 	Derived from the lance driver written 1993,1994,1995 by Donald Becker.
- * 
- * 	Copyright 1993 United States Government as represented by the
- * 	Director, National Security Agency.
- * 
- * 	This software may be used and distributed according to the terms
- * 	of the GNU Public License, incorporated herein by reference.
- *
- * 	This driver is for PCnet32 and PCnetPCI based ethercards
- */
-
-static const char *version = "lance32.c:v0.10 28.4.96 tsbogend@bigbug.franken.de\n";
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/bios32.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#ifdef LANCE32_DEBUG
-int lance32_debug = LANCE32_DEBUG;
-#else
-int lance32_debug = 1;
-#endif
-
-/*
- * 				Theory of Operation
- * 
- * This driver uses the same software structure as the normal lance
- * driver. So look for a verbose description in lance.c. The differences
- * to the normal lance driver is the use of the 32bit mode of PCnet32
- * and PCnetPCI chips. Because these chips are 32bit chips, there is no
- * 16MB limitation and we don't need bounce buffers.
- */
- 
-/*
- * History:
- * v0.01:  Initial version
- *         only tested on Alpha Noname Board
- * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
- *         tested on a ASUS SP3G
- * v0.10:  fixed a odd problem with the 79C794 in a Compaq Deskpro XL
- *         looks like the 974 doesn't like stopping and restarting in a
- *         short period of time; now we do a reinit of the lance; the
- *         bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
- *         and hangs the machine (thanks to Klaus Liedl for debugging)
- */
-
-
-/*
- * Set the number of Tx and Rx buffers, using Log_2(# buffers).
- * Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
- * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
- */
-#ifndef LANCE_LOG_TX_BUFFERS
-#define LANCE_LOG_TX_BUFFERS 4
-#define LANCE_LOG_RX_BUFFERS 4
-#endif
-
-#define TX_RING_SIZE			(1 << (LANCE_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS		((LANCE_LOG_TX_BUFFERS) << 12)
-
-#define RX_RING_SIZE			(1 << (LANCE_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS		((LANCE_LOG_RX_BUFFERS) << 4)
-
-#define PKT_BUF_SZ		1544
-
-/* Offsets from base I/O address. */
-#define LANCE_DATA 0x10
-#define LANCE_ADDR 0x12
-#define LANCE_RESET 0x14
-#define LANCE_BUS_IF 0x16
-#define LANCE_TOTAL_SIZE 0x18
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance32_rx_head {
-	u32 base;
-	s16 buf_length;
-        s16 status;    
-	u32 msg_length;
-	u32 reserved;
-};
-	
-struct lance32_tx_head {
-	u32 base;
-	s16 length;
-        s16 status;
-	u32 misc;
-	u32 reserved;
-};
-
-
-/* The LANCE 32-Bit initialization block, described in databook. */
-struct lance32_init_block {
-	u16 mode;
-	u16 tlen_rlen;
-	u8  phys_addr[6];
-	u16 reserved;
-	u32 filter[2];
-	/* Receive and transmit ring base, along with extra bits. */    
-	u32 rx_ring;
-	u32 tx_ring;
-};
-
-struct lance32_private {
-	/* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
-	struct lance32_rx_head   rx_ring[RX_RING_SIZE];
-	struct lance32_tx_head   tx_ring[TX_RING_SIZE];
-	struct lance32_init_block	init_block;
-	const char *name;
-	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	unsigned long rx_buffs;			/* Address of Rx and Tx buffers. */
-	int cur_rx, cur_tx;			/* The next free ring entry */
-	int dirty_rx, dirty_tx;		        /* The ring entries to be free()ed. */
-	int dma;
-	struct enet_statistics stats;
-	char tx_full;
-	unsigned long lock;
-};
-
-static int lance32_open(struct device *dev);
-static void lance32_init_ring(struct device *dev);
-static int lance32_start_xmit(struct sk_buff *skb, struct device *dev);
-static int lance32_rx(struct device *dev);
-static void lance32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int lance32_close(struct device *dev);
-static struct enet_statistics *lance32_get_stats(struct device *dev);
-static void lance32_set_multicast_list(struct device *dev);
-
-
-
-/* lance32_probe1 */
-void lance32_probe1(struct device *dev, char *chipname, int pci_irq_line)
-{
-	struct lance32_private *lp;
-        int ioaddr = dev->base_addr;
-	short dma_channels;					/* Mark spuriously-busy DMA channels */    
-        int i;
-    
-	/* Make certain the data structures used by the LANCE are 16byte aligned and DMAble. */
-	lp = (struct lance32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15);
-      
-	memset(lp, 0, sizeof(*lp));
-	dev->priv = lp;
-	lp->name = chipname;
-	lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
-
-	lp->init_block.mode = 0x0003;		/* Disable Rx and Tx. */
-        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;    
-	for (i = 0; i < 6; i++)
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	lp->init_block.filter[0] = 0x00000000;
-	lp->init_block.filter[1] = 0x00000000;
-	lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
-	lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
-    
-	/* switch lance to 32bit mode */
-	outw(0x0014, ioaddr+LANCE_ADDR);
-	outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-	outw(0x0001, ioaddr+LANCE_ADDR);
-	inw(ioaddr+LANCE_ADDR);
-	outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
-	outw(0x0002, ioaddr+LANCE_ADDR);
-	inw(ioaddr+LANCE_ADDR);
-	outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
-	outw(0x0000, ioaddr+LANCE_ADDR);
-	inw(ioaddr+LANCE_ADDR);
-    
-	if (pci_irq_line) {
-		dev->dma = 4;			/* Native bus-master, no DMA channel needed. */
-		dev->irq = pci_irq_line;
-	} else {
-		/* The DMA channel may be passed in PARAM1. */
-		if (dev->mem_start & 0x07)
-			dev->dma = dev->mem_start & 0x07;
-	}
-
-	if (dev->dma == 0) {
-		/* Read the DMA channel status register, so that we can avoid
-		   stuck DMA channels in the DMA detection below. */
-		dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
-			(inb(DMA2_STAT_REG) & 0xf0);
-	}
-	if (dev->irq >= 2)
-		printk(" assigned IRQ %d", dev->irq);
-	else {
-		/* To auto-IRQ we enable the initialization-done and DMA error
-		   interrupts. For ISA boards we get a DMA error, but VLB and PCI
-		   boards will work. */
-		autoirq_setup(0);
-
-		/* Trigger an initialization just for the interrupt. */
-		outw(0x0041, ioaddr+LANCE_DATA);
-
-		dev->irq = autoirq_report(1);
-		if (dev->irq)
-			printk(", probed IRQ %d", dev->irq);
-		else {
-			printk(", failed to detect IRQ line.\n");
-			return;
-		}
-
-		/* Check for the initialization done bit, 0x0100, which means
-		   that we don't need a DMA channel. */
-		if (inw(ioaddr+LANCE_DATA) & 0x0100)
-			dev->dma = 4;
-	}
-
-	if (dev->dma == 4) {
-		printk(", no DMA needed.\n");
-	} else if (dev->dma) {
-		if (request_dma(dev->dma, chipname)) {
-			printk("DMA %d allocation failed.\n", dev->dma);
-			return;
-		} else
-			printk(", assigned DMA %d.\n", dev->dma);
-	} else {			/* OK, we have to auto-DMA. */
-		for (i = 0; i < 4; i++) {
-			static const char dmas[] = { 5, 6, 7, 3 };
-			int dma = dmas[i];
-			int boguscnt;
-
-			/* Don't enable a permanently busy DMA channel, or the machine
-			   will hang. */
-			if (test_bit(dma, &dma_channels))
-				continue;
-			outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
-			if (request_dma(dma, chipname))
-				continue;
-			set_dma_mode(dma, DMA_MODE_CASCADE);
-			enable_dma(dma);
-
-			/* Trigger an initialization. */
-			outw(0x0001, ioaddr+LANCE_DATA);
-			for (boguscnt = 100; boguscnt > 0; --boguscnt)
-				if (inw(ioaddr+LANCE_DATA) & 0x0900)
-					break;
-			if (inw(ioaddr+LANCE_DATA) & 0x0100) {
-				dev->dma = dma;
-				printk(", DMA %d.\n", dev->dma);
-				break;
-			} else {
-				disable_dma(dma);
-				free_dma(dma);
-			}
-		}
-		if (i == 4) {			/* Failure: bail. */
-			printk("DMA detection failed.\n");
-			return;
-		}
-	}
-    
-        outw(0x0002, ioaddr+LANCE_ADDR);
-	outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-	/* Reset the LANCE - this should prevent any more interrupts from arriving */
-	inw(ioaddr+LANCE_RESET);
-
-	if (lance32_debug > 0)
-		printk(version);
-
-	/* The LANCE-specific entries in the device structure. */
-	dev->open = &lance32_open;
-	dev->hard_start_xmit = &lance32_start_xmit;
-	dev->stop = &lance32_close;
-	dev->get_stats = &lance32_get_stats;
-	dev->set_multicast_list = &lance32_set_multicast_list;
-
-	return;
-}
-
-
-static int
-lance32_open(struct device *dev)
-{
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-	int ioaddr = dev->base_addr;
-	int i;
-
-	if (dev->irq == 0 ||
-		request_irq(dev->irq, &lance32_interrupt, 0, lp->name, (void *)dev)) {
-		return -EAGAIN;
-	}
-
-	irq2dev_map[dev->irq] = dev;
-
-	/* Reset the LANCE */
-	inw(ioaddr+LANCE_RESET);
-
-	/* switch lance to 32bit mode */
-	outw(0x0014, ioaddr+LANCE_ADDR);
-	outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-	/* The DMA controller is used as a no-operation slave, "cascade mode". */
-	if (dev->dma != 4) {
-		enable_dma(dev->dma);
-		set_dma_mode(dev->dma, DMA_MODE_CASCADE);
-	}
-
-	/* Turn on auto-select of media (AUI, BNC). */
-	outw(0x0002, ioaddr+LANCE_ADDR);
-	outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-	if (lance32_debug > 1)
-		printk("%s: lance32_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
-			   dev->name, dev->irq, dev->dma,
-		           (u32) virt_to_bus(lp->tx_ring),
-		           (u32) virt_to_bus(lp->rx_ring),
-			   (u32) virt_to_bus(&lp->init_block));
-
-	lp->init_block.mode = 0x0000;
-	lp->init_block.filter[0] = 0x00000000;
-	lp->init_block.filter[1] = 0x00000000;
-	lance32_init_ring(dev);
-    
-	/* Re-initialize the LANCE, and start it when done. */
-	outw(0x0001, ioaddr+LANCE_ADDR);
-	outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
-	outw(0x0002, ioaddr+LANCE_ADDR);
-	outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
-
-	outw(0x0004, ioaddr+LANCE_ADDR);
-	outw(0x0915, ioaddr+LANCE_DATA);
-
-	outw(0x0000, ioaddr+LANCE_ADDR);
-	outw(0x0001, ioaddr+LANCE_DATA);
-
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-	i = 0;
-	while (i++ < 100)
-		if (inw(ioaddr+LANCE_DATA) & 0x0100)
-			break;
-	/* 
-	 * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
-	 * reports that doing so triggers a bug in the '974.
-	 */
- 	outw(0x0042, ioaddr+LANCE_DATA);
-
-	if (lance32_debug > 2)
-		printk("%s: LANCE32 open after %d ticks, init block %#x csr0 %4.4x.\n",
-			   dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+LANCE_DATA));
-
-	return 0;					/* Always succeed */
-}
-
-/*
- * The LANCE has been halted for one reason or another (busmaster memory
- * arbitration error, Tx FIFO underflow, driver stopped it to reconfigure,
- * etc.).  Modern LANCE variants always reload their ring-buffer
- * configuration when restarted, so we must reinitialize our ring
- * context before restarting.  As part of this reinitialization,
- * find all packets still on the Tx ring and pretend that they had been
- * sent (in effect, drop the packets on the floor) - the higher-level
- * protocols will time out and retransmit.  It'd be better to shuffle
- * these skbs to a temp list and then actually re-Tx them after
- * restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
- */
-
-static void 
-lance32_purge_tx_ring(struct device *dev)
-{
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-	int i;
-
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (lp->tx_skbuff[i]) {
-			dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE);
-			lp->tx_skbuff[i] = NULL;
-		}
-	}
-}
-
-
-/* Initialize the LANCE Rx and Tx rings. */
-static void
-lance32_init_ring(struct device *dev)
-{
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-	int i;
-
-	lp->lock = 0, lp->tx_full = 0;
-	lp->cur_rx = lp->cur_tx = 0;
-	lp->dirty_rx = lp->dirty_tx = 0;
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ);
-		lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
-	        lp->rx_ring[i].status = 0x8000;	    
-	}
-	/* The Tx buffer address is filled in as needed, but we do need to clear
-	   the upper ownership bit. */
-	for (i = 0; i < TX_RING_SIZE; i++) {
-	        lp->tx_ring[i].base = 0;
-	        lp->tx_ring[i].status = 0;
-	}
-
-        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
-	for (i = 0; i < 6; i++)
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
-	lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
-}
-
-static void
-lance32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
-{
-        int i;
-	int ioaddr = dev->base_addr;
-    
-	lance32_purge_tx_ring(dev);
-	lance32_init_ring(dev);
-    
-	outw(0x0000, ioaddr + LANCE_ADDR);
-        /* ReInit Ring */
-        outw(0x0001, ioaddr + LANCE_DATA);
-	i = 0;
-	while (i++ < 100)
-		if (inw(ioaddr+LANCE_DATA) & 0x0100)
-			break;
-
-	outw(csr0_bits, ioaddr + LANCE_DATA);
-}
-
-static int
-lance32_start_xmit(struct sk_buff *skb, struct device *dev)
-{
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-	int ioaddr = dev->base_addr;
-	int entry;
-	unsigned long flags;
-
-	/* Transmitter timeout, serious problems. */
-	if (dev->tbusy) {
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 60)		/* It can take this long to run through the 16 retries */
-			return 1;
-		outw(0, ioaddr+LANCE_ADDR);
-		printk("%s: transmit timed out, status %4.4x, resetting.\n",
-			   dev->name, inw(ioaddr+LANCE_DATA));
-		outw(0x0004, ioaddr+LANCE_DATA);
-		lp->stats.tx_errors++;
-#ifndef final_version
-		{
-			int i;
-			printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-				   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
-				   lp->cur_rx);
-			for (i = 0 ; i < RX_RING_SIZE; i++)
-				printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
-					   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-					   lp->rx_ring[i].msg_length);
-			for (i = 0 ; i < TX_RING_SIZE; i++)
-				printk("%s %08x %04x %04x %08x  ", i & 0x1 ? "" : "\n ",
-					   lp->tx_ring[i].base, -lp->tx_ring[i].length,
-					   lp->tx_ring[i].status,
-					   lp->tx_ring[i].misc);
-			printk("\n");
-		}
-#endif
-		lance32_restart(dev, 0x0042, 1);
-
-		dev->tbusy=0;
-		dev->trans_start = jiffies;
-		dev_kfree_skb(skb, FREE_WRITE);
-		return 0;
-	}
-
-	if (skb == NULL) {
-		dev_tint(dev);
-		return 0;
-	}
-
-	if (skb->len <= 0)
-		return 0;
-
-	if (lance32_debug > 3) {
-		outw(0x0000, ioaddr+LANCE_ADDR);
-		printk("%s: lance32_start_xmit() called, csr0 %4.4x.\n", dev->name,
-			   inw(ioaddr+LANCE_DATA));
-		outw(0x0000, ioaddr+LANCE_DATA);
-	}
-
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
-		return 1;
-	}
-
-	if (set_bit(0, (void*)&lp->lock) != 0) {
-		if (lance32_debug > 0)
-			printk("%s: tx queue lock!.\n", dev->name);
-		/* don't clear dev->tbusy flag. */
-		return 1;
-	}
-
-	/* Fill in a Tx ring entry */
-
-	/* Mask to ring buffer boundary. */
-	entry = lp->cur_tx & TX_RING_MOD_MASK;
-
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
-
-	lp->tx_ring[entry].length = -skb->len;
-
-	lp->tx_ring[entry].misc = 0x00000000;
-
-	lp->tx_skbuff[entry] = skb;
-	lp->tx_ring[entry].base = (u32)virt_to_bus(skb->data);
-        lp->tx_ring[entry].status = 0x8300;
-
-	lp->cur_tx++;
-
-	/* Trigger an immediate send poll. */
-	outw(0x0000, ioaddr+LANCE_ADDR);
-	outw(0x0048, ioaddr+LANCE_DATA);
-
-	dev->trans_start = jiffies;
-
-	save_flags(flags);
-	cli();
-	lp->lock = 0;
-	if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
-		dev->tbusy=0;
-	else
-		lp->tx_full = 1;
-	restore_flags(flags);
-
-	return 0;
-}
-
-/* The LANCE32 interrupt handler. */
-static void
-lance32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct device *dev = (struct device *)dev_id;
-	struct lance32_private *lp;
-	int csr0, ioaddr, boguscnt=10;
-	int must_restart;
-
-	if (dev == NULL) {
-		printk ("lance32_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
-
-	ioaddr = dev->base_addr;
-	lp = (struct lance32_private *)dev->priv;
-	if (dev->interrupt)
-		printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
-	dev->interrupt = 1;
-
-	outw(0x00, dev->base_addr + LANCE_ADDR);
-	while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600
-		   && --boguscnt >= 0) {
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA);
-
-		must_restart = 0;
-
-		if (lance32_debug > 5)
-			printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
-				   dev->name, csr0, inw(dev->base_addr + LANCE_DATA));
-
-		if (csr0 & 0x0400)			/* Rx interrupt */
-			lance32_rx(dev);
-
-		if (csr0 & 0x0200) {		/* Tx-done interrupt */
-			int dirty_tx = lp->dirty_tx;
-
-			while (dirty_tx < lp->cur_tx) {
-				int entry = dirty_tx & TX_RING_MOD_MASK;
-				int status = lp->tx_ring[entry].status;
-			
-				if (status < 0)
-					break;			/* It still hasn't been Txed */
-
-				lp->tx_ring[entry].base = 0;
-
-				if (status & 0x4000) {
-					/* There was an major error, log it. */
-					int err_status = lp->tx_ring[entry].misc;
-					lp->stats.tx_errors++;
-					if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
-					if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
-					if (err_status & 0x10000000) lp->stats.tx_window_errors++;
-					if (err_status & 0x40000000) {
-						/* Ackk!  On FIFO errors the Tx unit is turned off! */
-						lp->stats.tx_fifo_errors++;
-						/* Remove this verbosity later! */
-						printk("%s: Tx FIFO error! Status %4.4x.\n",
-							   dev->name, csr0);
-						/* Restart the chip. */
-						must_restart = 1;
-					}
-				} else {
-					if (status & 0x1800)
-						lp->stats.collisions++;
-					lp->stats.tx_packets++;
-				}
-
-				/* We must free the original skb */
-				if (lp->tx_skbuff[entry]) {
-					dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE);
-					lp->tx_skbuff[entry] = 0;
-				}
-				dirty_tx++;
-			}
-
-#ifndef final_version
-			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dirty_tx, lp->cur_tx, lp->tx_full);
-				dirty_tx += TX_RING_SIZE;
-			}
-#endif
-
-			if (dev->tbusy)
-				dev->trans_start = jiffies; /* We are just starting the next transmit */
-
-			if (lp->tx_full && dev->tbusy
-				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
-				/* The ring is no longer full, clear tbusy. */
-				lp->tx_full = 0;
-				dev->tbusy = 0;
-				mark_bh(NET_BH);
-			}
-
-			lp->dirty_tx = dirty_tx;
-		}
-
-		/* Log misc errors. */
-		if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
-		if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
-		if (csr0 & 0x0800) {
-			printk("%s: Bus master arbitration failure, status %4.4x.\n",
-				   dev->name, csr0);
-			/* Restart the chip. */
-			must_restart = 1;
-		}
-
-		if (must_restart) {
-			/* stop the chip to clear the error condition, then restart */
-			outw(0x0000, dev->base_addr + LANCE_ADDR);
-			outw(0x0004, dev->base_addr + LANCE_DATA);
-			lance32_restart(dev, 0x0002, 0);
-		}
-	}
-
-    /* Clear any other interrupt, and set interrupt enable. */
-    outw(0x0000, dev->base_addr + LANCE_ADDR);
-    outw(0x7940, dev->base_addr + LANCE_DATA);
-
-	if (lance32_debug > 4)
-		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
-			   dev->name, inw(ioaddr + LANCE_ADDR),
-			   inw(dev->base_addr + LANCE_DATA));
-
-	dev->interrupt = 0;
-	return;
-}
-
-static int
-lance32_rx(struct device *dev)
-{
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-	int entry = lp->cur_rx & RX_RING_MOD_MASK;
-	int i;
-		
-	/* If we own the next entry, it's a new packet. Send it up. */
-	while (lp->rx_ring[entry].status >= 0) {
-		int status = lp->rx_ring[entry].status >> 8;
-
-		if (status != 0x03) {			/* There was an error. */
-			/* There is a tricky error noted by John Murphy,
-			   <murf@perftech.com> to Russ Nelson: Even with full-sized
-			   buffers it's possible for a jabber packet to use two
-			   buffers, with only the last correctly noting the error. */
-			if (status & 0x01)	/* Only count a general error at the */
-				lp->stats.rx_errors++; /* end of a packet.*/
-			if (status & 0x20) lp->stats.rx_frame_errors++;
-			if (status & 0x10) lp->stats.rx_over_errors++;
-			if (status & 0x08) lp->stats.rx_crc_errors++;
-			if (status & 0x04) lp->stats.rx_fifo_errors++;
-			lp->rx_ring[entry].status &= 0x03ff;
-		}
-		else 
-		{
-			/* Malloc up new buffer, compatible with net-2e. */
-			short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
-			struct sk_buff *skb;
-			
-			if(pkt_len<60)
-			{
-				printk("%s: Runt packet!\n",dev->name);
-				lp->stats.rx_errors++;
-			}
-			else
-			{
-				skb = dev_alloc_skb(pkt_len+2);
-				if (skb == NULL) 
-				{
-					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-					for (i=0; i < RX_RING_SIZE; i++)
-						if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status < 0)
-							break;
-
-					if (i > RX_RING_SIZE -2) 
-					{
-						lp->stats.rx_dropped++;
-						lp->rx_ring[entry].status |= 0x8000;
-						lp->cur_rx++;
-					}
-					break;
-				}
-				skb->dev = dev;
-				skb_reserve(skb,2);	/* 16 byte align */
-				skb_put(skb,pkt_len);	/* Make room */
-				eth_copy_and_sum(skb,
-					(unsigned char *)bus_to_virt(lp->rx_ring[entry].base),
-					pkt_len,0);
-				skb->protocol=eth_type_trans(skb,dev);
-				netif_rx(skb);
-				lp->stats.rx_packets++;
-			}
-		}
-		/* The docs say that the buffer length isn't touched, but Andrew Boyd
-		   of QNX reports that some revs of the 79C965 clear it. */
-		lp->rx_ring[entry].buf_length = -PKT_BUF_SZ;
-		lp->rx_ring[entry].status |= 0x8000;
-		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
-	}
-
-	/* We should check that at least two ring entries are free.	 If not,
-	   we should free one and mark stats->rx_dropped++. */
-
-	return 0;
-}
-
-static int
-lance32_close(struct device *dev)
-{
-	int ioaddr = dev->base_addr;
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-
-	dev->start = 0;
-	dev->tbusy = 1;
-
-	outw(112, ioaddr+LANCE_ADDR);
-	lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
-
-	outw(0, ioaddr+LANCE_ADDR);
-
-	if (lance32_debug > 1)
-		printk("%s: Shutting down ethercard, status was %2.2x.\n",
-			   dev->name, inw(ioaddr+LANCE_DATA));
-
-	/* We stop the LANCE here -- it occasionally polls
-	   memory if we don't. */
-	outw(0x0004, ioaddr+LANCE_DATA);
-
-	if (dev->dma != 4)
-		disable_dma(dev->dma);
-
-	free_irq(dev->irq, dev);
-
-	irq2dev_map[dev->irq] = 0;
-
-	return 0;
-}
-
-static struct enet_statistics *
-lance32_get_stats(struct device *dev)
-{
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-	int ioaddr = dev->base_addr;
-	unsigned short saved_addr;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	saved_addr = inw(ioaddr+LANCE_ADDR);
-	outw(112, ioaddr+LANCE_ADDR);
-	lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
-	outw(saved_addr, ioaddr+LANCE_ADDR);
-	restore_flags(flags);
-
-	return &lp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-
-static void lance32_set_multicast_list(struct device *dev)
-{
-	int ioaddr = dev->base_addr;
-	struct lance32_private *lp = (struct lance32_private *)dev->priv;    
-
-	if (dev->flags&IFF_PROMISC) {
-		/* Log any net taps. */
-		printk("%s: Promiscuous mode enabled.\n", dev->name);
-	        lp->init_block.mode = 0x8000;
-	} else {
-		int num_addrs=dev->mc_count;
-		if(dev->flags&IFF_ALLMULTI)
-			num_addrs=1;
-		/* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
-		memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter));
-	        lp->init_block.mode = 0x0000;	        
-	}
-    
-	outw(0, ioaddr+LANCE_ADDR);
-	outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.	 */
-
-	lance32_restart(dev, 0x0042, 0); /*  Resume normal operation */
-
-}
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance32.c"
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.0.33/linux/drivers/net/ne.c	Tue Dec  2 13:52:31 1997
+++ linux/drivers/net/ne.c	Wed Jun  3 15:17:47 1998
@@ -118,7 +118,9 @@
 static unsigned char pci_irq_line = 0;
 
 int ne_probe(struct device *dev);
+#ifdef CONFIG_PCI
 static int ne_probe_pci(struct device *dev);
+#endif
 static int ne_probe1(struct device *dev, int ioaddr);
 
 static int ne_open(struct device *dev);
@@ -205,6 +207,7 @@
 	for (i = 0; pci_clone_list[i].vendor != 0; i++) {
 		unsigned char pci_bus, pci_device_fn;
 		unsigned int pci_ioaddr;
+		u16 pci_command, new_command;
 		int pci_index;
 		
 		for (pci_index = 0; pci_index < 8; pci_index++) {
@@ -226,6 +229,20 @@
 		if (pci_irq_line == 0) continue;	/* Try next PCI ID */
 		printk("ne.c: PCI BIOS reports NE 2000 clone at i/o %#x, irq %d.\n",
 				pci_ioaddr, pci_irq_line);
+
+		pcibios_read_config_word(pci_bus, pci_device_fn, 
+					PCI_COMMAND, &pci_command);
+
+		/* Activate the card: fix for brain-damaged Win98 BIOSes. */
+		new_command = pci_command | PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled this"
+				" NE2k clone!  Updating PCI command %4.4x->%4.4x.\n",
+					pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+					PCI_COMMAND, new_command);
+		}
+
 		if (ne_probe1(dev, pci_ioaddr) != 0) {	/* Shouldn't happen. */
 			printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
 			pci_irq_line = 0;
@@ -420,9 +437,10 @@
     }
     
     /* Snarf the interrupt now.  There's no point in waiting since we cannot
-       share and the board will usually be enabled. */
+       share (with ISA cards) and the board will usually be enabled. */
     {
-	int irqval = request_irq(dev->irq, ei_interrupt, 0, name, NULL);
+	int irqval = request_irq(dev->irq, ei_interrupt,
+			pci_irq_line ? SA_SHIRQ : 0, name, dev);
 	if (irqval) {
 	    printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
 	    return EAGAIN;
@@ -730,6 +748,7 @@
 
 static int io[MAX_NE_CARDS] = { 0, };
 static int irq[MAX_NE_CARDS]  = { 0, };
+static int bad[MAX_NE_CARDS]  = { 0, };
 
 /* This is set up so that no autoprobe takes place. We can't guarantee
 that the ne2k probe is the last 8390 based probe to take place (as it
@@ -747,6 +766,7 @@
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->init = ne_probe;
+		dev->mem_end = bad[this_dev];
 		if (register_netdev(dev) == 0) {
 			found++;
 			continue;
@@ -773,7 +793,7 @@
 		if (dev->priv != NULL) {
 			kfree(dev->priv);
 			dev->priv = NULL;
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			irq2dev_map[dev->irq] = NULL;
 			release_region(dev->base_addr, NE_IO_EXTENT);
 			unregister_netdev(dev);
diff -u --recursive --new-file v2.0.33/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.0.33/linux/drivers/net/ne2k-pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/ne2k-pci.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,641 @@
+/* ne2k-pci.c: A NE2000 clone on PCI bus driver for Linux. */
+/*
+	A Linux device driver for PCI NE2000 clones.
+
+	Authorship and other copyrights:
+	1992-1998 by Donald Becker, NE2000 core and various modifications.
+	1995-1998 by Paul Gortmaker, core modifications and PCI support.
+
+	Copyright 1993 assigned to the United States Government as represented
+	by the Director, National Security Agency.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	People are making PCI ne2000 clones! Oh the horror, the horror...
+
+	Issues remaining:
+	No full-duplex support.
+*/
+
+/* Our copyright info must remain in the binary. */
+static const char *version =
+"ne2k-pci.c:v0.99L 2/7/98 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
+
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+/* Set statically or when loading the driver module. */
+static debug = 1;
+
+/* Some defines that people can play with if so inclined. */
+
+/* Do #define LOAD_8390_BY_KERNELD to automatically load 8390 support. */
+#ifdef LOAD_8390_BY_KERNELD
+#include <linux/kerneld.h>
+#endif
+/* Use 32 bit data-movement operations instead of 16 bit. */
+#define USE_LONGIO
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
+/* #define PACKETBUF_MEMSIZE	0x40 */
+
+static struct {
+	unsigned short vendor, dev_id;
+	char *name;
+}
+pci_clone_list[] = {
+	{0x10ec, 0x8029, "RealTek RTL-8029"},
+	{0x1050, 0x0940, "Winbond 89C940"},
+	{0x11f6, 0x1401, "Compex RL2000"},
+	{0x8e2e, 0x3000, "KTI ET32P2"},
+	{0x4a14, 0x5000, "NetVin NV5000SC"},
+	{0x1106, 0x0926, "Via 82C926"},
+	{0,}
+};
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE	 (dev->base_addr)
+#define NE_CMD	 	0x00
+#define NE_DATAPORT	0x10	/* NatSemi-defined port window offset. */
+#define NE_RESET	0x1f	/* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT	0x20
+
+#define NESM_START_PG	0x40	/* First page of TX buffer */
+#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+int ne2k_pci_probe(struct device *dev);
+static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq);
+
+static int ne_open(struct device *dev);
+static int ne_close(struct device *dev);
+
+static void ne_reset_8390(struct device *dev);
+static void ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+			  int ring_page);
+static void ne_block_input(struct device *dev, int count,
+			  struct sk_buff *skb, int ring_offset);
+static void ne_block_output(struct device *dev, const int count,
+		const unsigned char *buf, const int start_page);
+
+
+
+/* No room in the standard 8390 structure for extra info we need. */
+struct ne2k_pci_card {
+	struct ne2k_pci_card *next;
+	struct device *dev;
+	unsigned char pci_bus, pci_device_fn;
+};
+/* A list of all installed devices, for removing the driver module. */
+static struct ne2k_pci_card *ne2k_card_list = NULL;
+
+#ifdef LOAD_8390_BY_KERNELD
+static int (*Lethdev_init)(struct device *dev);
+static void (*LNS8390_init)(struct device *dev, int startp);
+static int (*Lei_open)(struct device *dev);
+static int (*Lei_close)(struct device *dev);
+static void (*Lei_interrupt)(int irq, void *dev_id, struct pt_regs *regs);
+#else
+#define Lethdev_init ethdev_init
+#define LNS8390_init NS8390_init
+#define Lei_open ei_open
+#define Lei_close ei_close
+#define Lei_interrupt ei_interrupt
+#endif
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+	/* We must emit version information. */
+	if (debug)
+		printk(KERN_INFO "%s", version);
+
+	return ne2k_pci_probe(0);
+}
+
+void
+cleanup_module(void)
+{
+	struct device *dev;
+	struct ne2k_pci_card *this_card;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (ne2k_card_list) {
+		dev = ne2k_card_list->dev;
+		unregister_netdev(dev);
+		release_region(dev->base_addr, NE_IO_EXTENT);
+		kfree(dev);
+		this_card = ne2k_card_list;
+		ne2k_card_list = ne2k_card_list->next;
+		kfree(this_card);
+	}
+
+#ifdef LOAD_8390_BY_KERNELD
+	release_module("8390", 0);
+#endif
+}
+
+#endif  /* MODULE */
+
+/*
+  NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet
+  buffer memory space.  By-the-spec NE2000 clones have 0x57,0x57 in bytes
+  0x0e,0x0f of the SAPROM, while other supposed NE2000 clones must be
+  detected by their SA prefix.
+
+  Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+  mode results in doubled values, which can be detected and compensated for.
+
+  The probe is also responsible for initializing the card and filling
+  in the 'dev' and 'ei_status' structures.
+*/
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry netcard_drv =
+{"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0};
+#endif
+
+int ne2k_pci_probe(struct device *dev)
+{
+	static int pci_index = 0;	/* Static, for multiple calls. */
+	int cards_found = 0;
+	int i;
+
+	if ( ! pcibios_present())
+		return -ENODEV;
+
+#ifndef MODULE
+	{
+		static unsigned version_printed = 0;
+		if (version_printed++ == 0)
+			printk(KERN_INFO "%s", version);
+	}
+#endif
+
+	for (;pci_index < 0xff; pci_index++) {
+		unsigned char pci_bus, pci_device_fn;
+		u8 pci_irq_line;
+		u16 pci_command, new_command, vendor, device;
+		u32 pci_ioaddr;
+
+		if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
+								&pci_bus, &pci_device_fn)
+			!= PCIBIOS_SUCCESSFUL)
+			break;
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_VENDOR_ID, &vendor);
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_DEVICE_ID, &device);
+
+		/* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */
+		for (i = 0; pci_clone_list[i].vendor != 0; i++)
+			if (pci_clone_list[i].vendor == vendor
+				&& pci_clone_list[i].dev_id == device)
+				break;
+		if (pci_clone_list[i].vendor == 0)
+			continue;
+
+		pcibios_read_config_dword(pci_bus, pci_device_fn,
+								  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+								 PCI_INTERRUPT_LINE, &pci_irq_line);
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_COMMAND, &pci_command);
+
+		/* Remove I/O space marker in bit 0. */
+		pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+
+		/* Avoid already found cards from previous calls */
+		if (check_region(pci_ioaddr, NE_IO_EXTENT))
+			continue;
+
+		/* Activate the card: fix for brain-damaged Win98 BIOSes. */
+		new_command = pci_command | PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled this"
+				   " NE2k clone!  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+									  PCI_COMMAND, new_command);
+		}
+
+		if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS)
+			printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k"
+				   " card to IRQ %d, which is unlikely to work!.\n"
+				   KERN_WARNING " You should use the PCI BIOS setup to assign"
+				   " a valid IRQ line.\n", pci_irq_line);
+
+		printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n",
+			   pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
+		dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line);
+		if (dev == 0) {
+			/* Should not happen. */
+			printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n",
+				   pci_ioaddr);
+			continue;
+		} else {
+			struct ne2k_pci_card *ne2k_card =
+				kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL);
+			ne2k_card->next = ne2k_card_list;
+			ne2k_card_list = ne2k_card;
+			ne2k_card->dev = dev;
+			ne2k_card->pci_bus = pci_bus;
+			ne2k_card->pci_device_fn = pci_device_fn;
+		}
+		dev = 0;
+
+		cards_found++;
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq)
+{
+	int i;
+	unsigned char SA_prom[32];
+	const char *name = NULL;
+	int start_page, stop_page;
+	int reg0 = inb(ioaddr);
+
+	if (reg0 == 0xFF)
+		return 0;
+
+	/* Do a preliminary verification that we have a 8390. */
+	{
+		int regd;
+		outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+		regd = inb(ioaddr + 0x0d);
+		outb(0xff, ioaddr + 0x0d);
+		outb(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+		inb(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+		if (inb(ioaddr + EN0_COUNTER0) != 0) {
+			outb(reg0, ioaddr);
+			outb(regd, ioaddr + 0x0d);	/* Restore the old values. */
+			return 0;
+		}
+	}
+
+	dev = init_etherdev(dev, 0);
+
+	/* Reset card. Who knows what dain-bramaged state it was left in. */
+	{
+		unsigned long reset_start_time = jiffies;
+
+		outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+		/* This looks like a horrible timing loop, but it should never take
+		   more than a few cycles.
+		*/
+		while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+			/* Limit wait: '2' avoids jiffy roll-over. */
+			if (jiffies - reset_start_time > 2) {
+				printk("ne2k-pci: Card failure (no reset ack).\n");
+				return 0;
+			}
+		
+		outb(0xff, ioaddr + EN0_ISR);		/* Ack all intr. */
+	}
+
+#if defined(LOAD_8390_BY_KERNELD)
+	/* We are now certain the 8390 module is required. */
+	if (request_module("8390")) {
+		printk("ne2k-pci: Failed to load the 8390 core module.\n");
+		return 0;
+	}
+	if ((Lethdev_init = (void*)get_module_symbol(0, "ethdev_init")) == 0 ||
+		(LNS8390_init = (void*)get_module_symbol(0, "NS8390_init")) == 0 ||
+		(Lei_open = (void*)get_module_symbol(0, "ei_open")) == 0 ||
+		(Lei_close = (void*)get_module_symbol(0, "ei_close")) == 0 ||
+		(Lei_interrupt = (void*)get_module_symbol(0, "ei_interrupt")) == 0 ) {
+		printk("ne2k-pci: Failed to resolve an 8390 symbol.\n");
+		release_module("8390", 0);
+		return 0;
+	}
+#endif
+
+	/* Read the 16 bytes of station address PROM.
+	   We must first initialize registers, similar to NS8390_init(eifdev, 0).
+	   We can't reliably read the SAPROM address without this.
+	   (I learned the hard way!). */
+	{
+		struct {unsigned char value, offset; } program_seq[] = {
+			{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+			{0x49,	EN0_DCFG},	/* Set word-wide access. */
+			{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
+			{0x00,	EN0_RCNTHI},
+			{0x00,	EN0_IMR},	/* Mask completion irq. */
+			{0xFF,	EN0_ISR},
+			{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+			{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
+			{32,	EN0_RCNTLO},
+			{0x00,	EN0_RCNTHI},
+			{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
+			{0x00,	EN0_RSARHI},
+			{E8390_RREAD+E8390_START, E8390_CMD},
+		};
+		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+			outb(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+	}
+
+#ifdef notdef
+	/* Some broken PCI cards don't respect the byte-wide
+	   request in program_seq above, and hence don't have doubled up values.
+	*/
+	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
+		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+		SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
+		if (SA_prom[i] != SA_prom[i+1])
+			sa_prom_doubled = 0;
+	}
+
+	if (sa_prom_doubled)
+		for (i = 0; i < 16; i++)
+			SA_prom[i] = SA_prom[i+i];
+#else
+	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
+		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+
+#endif
+
+	/* We always set the 8390 registers for word mode. */
+	outb(0x49, ioaddr + EN0_DCFG);
+	start_page = NESM_START_PG;
+	stop_page = NESM_STOP_PG;
+
+	/* Set up the rest of the parameters. */
+	name = "PCI NE2000";
+
+	dev->irq = irq;
+	dev->base_addr = ioaddr;
+
+	/* Allocate dev->priv and fill in 8390 specific dev fields. */
+	if (Lethdev_init(dev)) {
+		printk ("%s: unable to get memory for dev->priv.\n", dev->name);
+		return 0;
+	}
+
+	request_region(ioaddr, NE_IO_EXTENT, dev->name);
+
+	printk("%s: %s found at %#x, IRQ %d, ",
+		   dev->name, name, ioaddr, dev->irq);
+	for(i = 0; i < 6; i++) {
+		printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
+		dev->dev_addr[i] = SA_prom[i];
+	}
+
+	ei_status.name = name;
+	ei_status.tx_start_page = start_page;
+	ei_status.stop_page = stop_page;
+	ei_status.word16 = 1;
+
+	ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+	/* Allow the packet buffer size to be overridden by know-it-alls. */
+	ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+	ei_status.reset_8390 = &ne_reset_8390;
+	ei_status.block_input = &ne_block_input;
+	ei_status.block_output = &ne_block_output;
+	ei_status.get_8390_hdr = &ne_get_8390_hdr;
+	dev->open = &ne_open;
+	dev->stop = &ne_close;
+	LNS8390_init(dev, 0);
+	return dev;
+}
+
+static int
+ne_open(struct device *dev)
+{
+	if (request_irq(dev->irq, Lei_interrupt, SA_SHIRQ, dev->name, dev))
+		return -EAGAIN;
+	Lei_open(dev);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int
+ne_close(struct device *dev)
+{
+	Lei_close(dev);
+	free_irq(dev->irq, dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+static void
+ne_reset_8390(struct device *dev)
+{
+	unsigned long reset_start_time = jiffies;
+
+	if (debug > 1) printk("%s: Resetting the 8390 t=%ld...",
+						  dev->name, jiffies);
+
+	outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+	ei_status.txing = 0;
+	ei_status.dmaing = 0;
+
+	/* This check _should_not_ be necessary, omit eventually. */
+	while ((inb(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+		if (jiffies - reset_start_time > 2) {
+			printk("%s: ne_reset_8390() did not complete.\n", dev->name);
+			break;
+		}
+	outb(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void
+ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+
+	int nic_base = dev->base_addr;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing) {
+		printk("%s: DMAing conflict in ne_get_8390_hdr "
+			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+			   dev->name, ei_status.dmaing, ei_status.irqlock,
+			   dev->interrupt);
+		return;
+	}
+
+	ei_status.dmaing |= 0x01;
+	outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+	outb(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+	outb(0, nic_base + EN0_RCNTHI);
+	outb(0, nic_base + EN0_RSARLO);		/* On page boundary */
+	outb(ring_page, nic_base + EN0_RSARHI);
+	outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+#if defined(USE_LONGIO)
+	*(u32*)hdr = inl(NE_BASE + NE_DATAPORT);
+#else
+	insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+#endif
+
+	outb(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using outb. */
+
+static void
+ne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+	int nic_base = dev->base_addr;
+	char *buf = skb->data;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing) {
+		printk("%s: DMAing conflict in ne_block_input "
+			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+			   dev->name, ei_status.dmaing, ei_status.irqlock,
+			   dev->interrupt);
+		return;
+	}
+	ei_status.dmaing |= 0x01;
+	outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+	outb(count & 0xff, nic_base + EN0_RCNTLO);
+	outb(count >> 8, nic_base + EN0_RCNTHI);
+	outb(ring_offset & 0xff, nic_base + EN0_RSARLO);
+	outb(ring_offset >> 8, nic_base + EN0_RSARHI);
+	outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+#if defined(USE_LONGIO)
+	insl(NE_BASE + NE_DATAPORT, buf, count>>2);
+	if (count & 3) {
+		buf += count & ~3;
+		if (count & 2)
+			*((u16*)buf)++ = inw(NE_BASE + NE_DATAPORT);
+		if (count & 1)
+			*buf = inb(NE_BASE + NE_DATAPORT);
+	}
+#else
+	insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+	if (count & 0x01) {
+		buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+	}
+#endif
+
+	outb(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+}
+
+static void
+ne_block_output(struct device *dev, int count,
+		const unsigned char *buf, const int start_page)
+{
+	int nic_base = NE_BASE;
+	unsigned long dma_start;
+
+	/* On little-endian it's always safe to round the count up for
+	   word writes. */
+	if (count & 0x01)
+		count++;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing) {
+		printk("%s: DMAing conflict in ne_block_output."
+			   "[DMAstat:%d][irqlock:%d][intr:%d]\n",
+			   dev->name, ei_status.dmaing, ei_status.irqlock,
+			   dev->interrupt);
+		return;
+	}
+	ei_status.dmaing |= 0x01;
+	/* We should already be in page 0, but to be safe... */
+	outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE8390_RW_BUGFIX
+	/* Handle the read-before-write bug the same way as the
+	   Crynwr packet driver -- the NatSemi method doesn't work.
+	   Actually this doesn't always work either, but if you have
+	   problems with your NEx000 this is better than nothing! */
+	outb(0x42, nic_base + EN0_RCNTLO);
+	outb(0x00, nic_base + EN0_RCNTHI);
+	outb(0x42, nic_base + EN0_RSARLO);
+	outb(0x00, nic_base + EN0_RSARHI);
+	outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+#endif
+	outb(ENISR_RDC, nic_base + EN0_ISR);
+
+   /* Now the normal output. */
+	outb(count & 0xff, nic_base + EN0_RCNTLO);
+	outb(count >> 8,   nic_base + EN0_RCNTHI);
+	outb(0x00, nic_base + EN0_RSARLO);
+	outb(start_page, nic_base + EN0_RSARHI);
+	outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+#if defined(USE_LONGIO)
+	outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
+	if (count & 3) {
+		buf += count & ~3;
+		if (count & 2)
+			outw(*((u16*)buf)++, NE_BASE + NE_DATAPORT);
+	}
+#else
+	outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+#endif
+
+	dma_start = jiffies;
+
+	while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+		if (jiffies - dma_start > 2) { 			/* Avoid clock roll-over. */
+			printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+			ne_reset_8390(dev);
+			LNS8390_init(dev,1);
+			break;
+		}
+
+	outb(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+	return;
+}
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
+ *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ *  version-control: t
+ *  kept-new-versions: 5
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/new_tunnel.c linux/drivers/net/new_tunnel.c
--- v2.0.33/linux/drivers/net/new_tunnel.c	Tue Aug 12 13:21:12 1997
+++ linux/drivers/net/new_tunnel.c	Wed Jun  3 15:17:47 1998
@@ -267,7 +267,7 @@
 
 		/* Tack on our header */
 		new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
-		new_skb->mac.raw = new_skb->ip_hdr;
+		new_skb->mac.raw = (void *)new_skb->ip_hdr;
 
 		/* Free the old packet, we no longer need it */
 		dev_kfree_skb(skb, FREE_WRITE);
diff -u --recursive --new-file v2.0.33/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.0.33/linux/drivers/net/pcnet32.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcnet32.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,956 @@
+/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
+/*
+ *  Copyright 1996,97 Thomas Bogendoerfer, 1993-1995,1998 Donald Becker
+ * 	Copyright 1993 United States Government as represented by the
+ * 	Director, National Security Agency.
+ *
+ * 	Derived from the lance driver written 1993-1995 by Donald Becker.
+ *
+ * 	This software may be used and distributed according to the terms
+ * 	of the GNU Public License, incorporated herein by reference.
+ *
+ * 	This driver is for AMD PCnet-PCI based ethercards
+ */
+
+static const char *version = "pcnet32.c:v0.99B 4/4/98 DJBecker/TSBogend.\n";
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/*
+ * Set the number of Tx and Rx buffers, using Log_2(# buffers).
+ * Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
+ * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
+ */
+#define PCNET_LOG_TX_BUFFERS 4
+#define PCNET_LOG_RX_BUFFERS 4
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Driver verbosity level.  0 = no messages, 7 = wordy death.
+   Modify here, or when loading as a module. */
+static int pcnet32_debug = 1;
+
+/*
+ * 				Theory of Operation
+ *
+ * This driver uses the same software structure as the normal lance
+ * driver. So look for a verbose description in lance.c. The differences
+ * to the normal lance driver is the use of the 32bit mode of PCnet32
+ * and PCnetPCI chips. Because these chips are 32bit chips, there is no
+ * 16MB limitation and we don't need bounce buffers.
+ */
+
+/*
+ * History:
+ * v0.01:  Initial version
+ *         only tested on Alpha Noname Board
+ * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
+ *         tested on a ASUS SP3G
+ * v0.10:  fixed an odd problem with the 79C794 in a Compaq Deskpro XL
+ *         looks like the 974 doesn't like stopping and restarting in a
+ *         short period of time; now we do a reinit of the lance; the
+ *         bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
+ *         and hangs the machine (thanks to Klaus Liedl for debugging)
+ * v0.12:  by suggestion from Donald Becker: Renamed driver to pcnet32,
+ *         made it standalone (no need for lance.c)
+ * v0.13:  added additional PCI detecting for special PCI devices (Compaq)
+ * v0.14:  stripped down additional PCI probe (thanks to David C Niemi
+ *         and sveneric@xs4all.nl for testing this on their Compaq boxes)
+ * v0.15:  added 79C965 (VLB) probe
+ *         added interrupt sharing for PCI chips
+ * v0.16:  fixed set_multicast_list on Alpha machines
+ * v0.17:  removed hack from dev.c; now pcnet32 uses ethif_probe in Space.c
+ * v0.19:  changed setting of autoselect bit
+ * v0.20:  removed additional Compaq PCI probe; there is now a working one
+ *	   in arch/i386/bios32.c
+ * v0.21:  added endian conversion for ppc, from work by cort@cs.nmt.edu
+ * v0.22:  added printing of status to ring dump
+ * v0.23:  changed enet_statistics to net_devive_stats
+ * v0.99: Changes for 2.0.34 final release. -djb
+ */
+
+
+#ifndef __powerpc__
+#define le16_to_cpu(val)  (val)
+#define le32_to_cpu(val)  (val)
+#endif
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
+#define TX_RING_SIZE			(1 << (PCNET_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS		((PCNET_LOG_TX_BUFFERS) << 12)
+
+#define RX_RING_SIZE			(1 << (PCNET_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
+#define RX_RING_LEN_BITS		((PCNET_LOG_RX_BUFFERS) << 4)
+
+#define PKT_BUF_SZ		1544
+
+/* Offsets from base I/O address. */
+enum pcnet_offsets { PCNET32_DATA=0x10, PCNET32_ADDR=0x12, PCNET32_RESET=0x14,
+					 PCNET32_BUS_IF=0x16,};
+#define PCNET32_TOTAL_SIZE 0x20
+
+/* The PCNET32 Rx and Tx ring descriptors. */
+struct pcnet32_rx_head {
+	u32 base;
+	s16 buf_length;
+	s16 status;
+	u32 msg_length;
+	u32 reserved;
+};
+
+struct pcnet32_tx_head {
+	u32 base;
+	s16 length;
+	s16 status;
+	u32 misc;
+	u32 reserved;
+};
+
+/* The PCNET32 32-Bit initialization block, described in databook. */
+struct pcnet32_init_block {
+	u16 mode;
+	u16 tlen_rlen;
+	u8  phys_addr[6];
+	u16 reserved;
+	u32 filter[2];
+	/* Receive and transmit ring base, along with extra bits. */
+	u32 rx_ring;
+	u32 tx_ring;
+};
+
+struct pcnet32_private {
+	/* The Tx and Rx ring entries must be aligned on 16-byte boundaries
+	   in 32bit mode. */
+	struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
+	struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
+	struct pcnet32_init_block	init_block;
+	const char *name;
+	struct device *next_module;
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	unsigned long rx_buffs;		/* Address of Rx and Tx buffers. */
+	int cur_rx, cur_tx;			/* The next free ring entry */
+	int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
+	struct enet_statistics stats;
+	char tx_full;
+	unsigned long lock;
+};
+
+static struct pcnet_chip_type {
+	int id_number;
+	const char *name;
+	int flags;
+} chip_table[] = {
+	{0x2420, "PCnet/PCI 79C970", 0},
+	{0x2430, "PCnet32", 0},
+	{0x2621, "PCnet/PCI II 79C970A", 0},
+	{0x2623, "PCnet/PCI II 79C971A", 0},
+	{0x0, 	 "PCnet32 (unknown)", 0},
+};
+
+/* Index of functions. */
+int  pcnet32_probe(struct device *dev);
+static int  pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line);
+static int  pcnet32_open(struct device *dev);
+static void pcnet32_init_ring(struct device *dev);
+static int  pcnet32_start_xmit(struct sk_buff *skb, struct device *dev);
+static int  pcnet32_rx(struct device *dev);
+static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int  pcnet32_close(struct device *dev);
+static struct enet_statistics *pcnet32_get_stats(struct device *dev);
+static void pcnet32_set_multicast_list(struct device *dev);
+
+
+/* A list of all installed PCnet32 devices, for removing the driver module. */
+static struct device *root_pcnet32_dev = NULL;
+
+int pcnet32_probe (struct device *dev)
+{
+	static int pci_index = 0;	/* Static, for multiple probe calls. */
+	int cards_found = 0;
+
+	if ( ! pcibios_present())
+		return ENODEV;
+
+	for (;pci_index < 0xff; pci_index++) {
+		u8 irq_line;
+		u16 pci_command, new_command;
+		unsigned char pci_bus, pci_device_fn;
+		u32 pci_ioaddr;
+
+		if (pcibios_find_device (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
+								 pci_index, &pci_bus, &pci_device_fn)
+			!= PCIBIOS_SUCCESSFUL)
+			break;
+
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+								 PCI_INTERRUPT_LINE, &irq_line);
+		pcibios_read_config_dword(pci_bus, pci_device_fn,
+								  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+		/* Remove I/O space marker in bit 0. */
+		pci_ioaddr &= ~3;
+
+		/* Avoid already found cards from previous pcnet32_probe() calls */
+		if (check_region(pci_ioaddr, PCNET32_TOTAL_SIZE))
+			continue;
+
+		/* Activate the card: fix for brain-damaged Win98 BIOSes. */
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_COMMAND, &pci_command);
+		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled the AMD Ethernet"
+				   " device at %2x-%2x."
+				   "  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_bus, pci_device_fn, pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+									  PCI_COMMAND, new_command);
+		}
+
+#ifdef __powerpc__
+		/* This is bogus! -djb */
+		irq_line = 15;
+#endif
+
+		if (pcnet32_probe1(dev, pci_ioaddr, irq_line) != 0) {
+			/* Should never happen. */
+			printk(KERN_ERR "pcnet32.c: Probe of PCI card at %#x failed.\n",
+				   pci_ioaddr);
+		} else
+			dev = 0;
+		cards_found++;
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+
+/* pcnet32_probe1 */
+static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line)
+{
+	struct pcnet32_private *lp;
+	int i;
+	const char *chipname;
+
+	/* check if there is really a pcnet chip on that ioaddr */
+	if ((inb(ioaddr + 14) != 0x57) || (inb(ioaddr + 15) != 0x57))
+		return ENODEV;
+
+	inw(ioaddr+PCNET32_RESET); /* Reset the PCNET32 */
+
+	outw(0x0000, ioaddr+PCNET32_ADDR); /* Switch to window 0 */
+	if (inw(ioaddr+PCNET32_DATA) != 0x0004)
+		return ENODEV;
+
+	/* Get the version of the chip. */
+	outw(88, ioaddr+PCNET32_ADDR);
+	if (inw(ioaddr+PCNET32_ADDR) != 88) {
+		/* should never happen */
+		return ENODEV;
+	} else {			/* Good, it's a newer chip. */
+		int chip_version = inw(ioaddr+PCNET32_DATA);
+		outw(89, ioaddr+PCNET32_ADDR);
+		chip_version |= inw(ioaddr+PCNET32_DATA) << 16;
+		if (pcnet32_debug > 2)
+			printk("  PCnet chip version is %#x.\n", chip_version);
+		if ((chip_version & 0xfff) != 0x003)
+			return ENODEV;
+		chip_version = (chip_version >> 12) & 0xffff;
+		for (i = 0; chip_table[i].id_number; i++)
+			if (chip_table[i].id_number == chip_version)
+				break;
+		chipname = chip_table[i].name;
+	}
+
+	dev = init_etherdev(dev, 0);
+
+	printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
+
+	/* There is a 16 byte station address PROM at the base address.
+	   The first six bytes are the station address. */
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+
+	dev->base_addr = ioaddr;
+	request_region(ioaddr, PCNET32_TOTAL_SIZE, dev->name);
+
+	/* Data structures used by the PCnet32 are 16byte aligned and DMAble. */
+    lp = (struct pcnet32_private *)
+		(((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15);
+
+    memset(lp, 0, sizeof(*lp));
+	dev->priv = lp;
+
+	lp->next_module = root_pcnet32_dev;
+	root_pcnet32_dev = dev;
+
+    lp->name = chipname;
+    lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
+
+    lp->init_block.mode = le16_to_cpu(0x0003);	/* Disable Rx and Tx. */
+    lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
+    for (i = 0; i < 6; i++)
+      lp->init_block.phys_addr[i] = dev->dev_addr[i];
+    lp->init_block.filter[0] = 0x00000000;
+    lp->init_block.filter[1] = 0x00000000;
+    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+
+    /* switch pcnet32 to 32bit mode */
+    outw(0x0014, ioaddr+PCNET32_ADDR);
+    outw(0x0002, ioaddr+PCNET32_BUS_IF);
+
+    outw(0x0001, ioaddr+PCNET32_ADDR);
+    inw(ioaddr+PCNET32_ADDR);
+    outw(virt_to_bus(&lp->init_block) & 0xffff, ioaddr+PCNET32_DATA);
+    outw(0x0002, ioaddr+PCNET32_ADDR);
+    inw(ioaddr+PCNET32_ADDR);
+    outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
+    outw(0x0000, ioaddr+PCNET32_ADDR);
+    inw(ioaddr+PCNET32_ADDR);
+
+	dev->irq = irq_line;
+#ifdef __powerpc__
+		/* This is sooo bogus! -djb */
+	    irq_line = 15;
+#endif
+
+    outw(0x0002, ioaddr+PCNET32_ADDR);
+    /* only touch autoselect bit */
+    outw(inw(ioaddr+PCNET32_BUS_IF) | 0x0002, ioaddr+PCNET32_BUS_IF);
+
+    if (pcnet32_debug > 0)
+      printk(version);
+
+    /* The PCNET32-specific entries in the device structure. */
+    dev->open = &pcnet32_open;
+    dev->hard_start_xmit = &pcnet32_start_xmit;
+    dev->stop = &pcnet32_close;
+    dev->get_stats = &pcnet32_get_stats;
+    dev->set_multicast_list = &pcnet32_set_multicast_list;
+
+    /* Fill in the generic fields of the device structure. */
+    ether_setup(dev);
+    return 0;
+}
+
+
+static int
+pcnet32_open(struct device *dev)
+{
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+	unsigned int ioaddr = dev->base_addr;
+	int i;
+
+	if (dev->irq == 0 ||
+		request_irq(dev->irq, &pcnet32_interrupt, SA_SHIRQ,
+					dev->name, (void *)dev)) {
+		return -EAGAIN;
+	}
+	MOD_INC_USE_COUNT;
+
+	/* Reset the PCNET32 */
+	inw(ioaddr+PCNET32_RESET);
+
+	/* switch pcnet32 to 32bit mode */
+	outw(0x0014, ioaddr+PCNET32_ADDR);
+	outw(0x0002, ioaddr+PCNET32_BUS_IF);
+
+	/* Turn on auto-select of media (AUI, BNC). */
+	outw(0x0002, ioaddr+PCNET32_ADDR);
+	/* only touch autoselect bit */
+	outw(inw(ioaddr+PCNET32_BUS_IF) | 0x0002, ioaddr+PCNET32_BUS_IF);
+
+	if (pcnet32_debug > 1)
+		printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
+			   dev->name, dev->irq,
+		           (u32) virt_to_bus(lp->tx_ring),
+		           (u32) virt_to_bus(lp->rx_ring),
+			   (u32) virt_to_bus(&lp->init_block));
+
+	lp->init_block.mode = 0x0000;
+	lp->init_block.filter[0] = 0x00000000;
+	lp->init_block.filter[1] = 0x00000000;
+	pcnet32_init_ring(dev);
+
+	/* Re-initialize the PCNET32, and start it when done. */
+	outw(0x0001, ioaddr+PCNET32_ADDR);
+	outw(virt_to_bus(&lp->init_block) &0xffff, ioaddr+PCNET32_DATA);
+	outw(0x0002, ioaddr+PCNET32_ADDR);
+	outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
+
+	outw(0x0004, ioaddr+PCNET32_ADDR);
+	outw(0x0915, ioaddr+PCNET32_DATA);
+
+	outw(0x0000, ioaddr+PCNET32_ADDR);
+	outw(0x0001, ioaddr+PCNET32_DATA);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+	i = 0;
+	while (i++ < 100)
+		if (inw(ioaddr+PCNET32_DATA) & 0x0100)
+			break;
+	/*
+	 * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+	 * reports that doing so triggers a bug in the '974.
+	 */
+ 	outw(0x0042, ioaddr+PCNET32_DATA);
+
+	if (pcnet32_debug > 2)
+		printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
+			   dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+PCNET32_DATA));
+
+	return 0;					/* Always succeed */
+}
+
+/*
+ * The LANCE has been halted for one reason or another (busmaster memory
+ * arbitration error, Tx FIFO underflow, driver stopped it to reconfigure,
+ * etc.).  Modern LANCE variants always reload their ring-buffer
+ * configuration when restarted, so we must reinitialize our ring
+ * context before restarting.  As part of this reinitialization,
+ * find all packets still on the Tx ring and pretend that they had been
+ * sent (in effect, drop the packets on the floor) - the higher-level
+ * protocols will time out and retransmit.  It'd be better to shuffle
+ * these skbs to a temp list and then actually re-Tx them after
+ * restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
+ */
+
+static void
+pcnet32_purge_tx_ring(struct device *dev)
+{
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+	int i;
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (lp->tx_skbuff[i]) {
+			dev_kfree_skb(lp->tx_skbuff[i], FREE_WRITE);
+			lp->tx_skbuff[i] = NULL;
+		}
+	}
+}
+
+
+/* Initialize the PCNET32 Rx and Tx rings. */
+static void
+pcnet32_init_ring(struct device *dev)
+{
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+	int i;
+
+	lp->lock = 0, lp->tx_full = 0;
+	lp->cur_rx = lp->cur_tx = 0;
+	lp->dirty_rx = lp->dirty_tx = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ));
+		lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+	        lp->rx_ring[i].status = le16_to_cpu(0x8000);
+	}
+	/* The Tx buffer address is filled in as needed, but we do need to clear
+	   the upper ownership bit. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+	        lp->tx_ring[i].base = 0;
+	        lp->tx_ring[i].status = 0;
+	}
+
+	lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
+	for (i = 0; i < 6; i++)
+		lp->init_block.phys_addr[i] = dev->dev_addr[i];
+	lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
+	lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+}
+
+static void
+pcnet32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
+{
+        int i;
+	unsigned int ioaddr = dev->base_addr;
+
+	pcnet32_purge_tx_ring(dev);
+	pcnet32_init_ring(dev);
+
+	outw(0x0000, ioaddr + PCNET32_ADDR);
+        /* ReInit Ring */
+        outw(0x0001, ioaddr + PCNET32_DATA);
+	i = 0;
+	while (i++ < 100)
+		if (inw(ioaddr+PCNET32_DATA) & 0x0100)
+			break;
+
+	outw(csr0_bits, ioaddr + PCNET32_DATA);
+}
+
+static int
+pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+	unsigned int ioaddr = dev->base_addr;
+	int entry;
+	unsigned long flags;
+
+	/* Transmitter timeout, serious problems. */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 20)
+			return 1;
+		outw(0, ioaddr+PCNET32_ADDR);
+		printk("%s: transmit timed out, status %4.4x, resetting.\n",
+			   dev->name, inw(ioaddr+PCNET32_DATA));
+		outw(0x0004, ioaddr+PCNET32_DATA);
+		lp->stats.tx_errors++;
+#ifndef final_version
+		{
+			int i;
+			printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+				   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+				   lp->cur_rx);
+			for (i = 0 ; i < RX_RING_SIZE; i++)
+				printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+					   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+					   lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
+			for (i = 0 ; i < TX_RING_SIZE; i++)
+				printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+					   lp->tx_ring[i].base, -lp->tx_ring[i].length,
+					   lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
+			printk("\n");
+		}
+#endif
+		pcnet32_restart(dev, 0x0042, 1);
+
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+
+		return 0;
+	}
+
+	if (pcnet32_debug > 3) {
+		outw(0x0000, ioaddr+PCNET32_ADDR);
+		printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name,
+			   inw(ioaddr+PCNET32_DATA));
+		outw(0x0000, ioaddr+PCNET32_DATA);
+	}
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
+
+	if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
+		if (pcnet32_debug > 0)
+			printk("%s: tx queue lock!.\n", dev->name);
+		/* don't clear dev->tbusy flag. */
+		return 1;
+	}
+
+	/* Fill in a Tx ring entry */
+
+	/* Mask to ring buffer boundary. */
+	entry = lp->cur_tx & TX_RING_MOD_MASK;
+
+	/* Caution: the write order is important here, set the base address
+	   with the "ownership" bits last. */
+
+	lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+
+	lp->tx_ring[entry].misc = 0x00000000;
+
+	lp->tx_skbuff[entry] = skb;
+	lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
+	lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+
+	lp->cur_tx++;
+
+	/* Trigger an immediate send poll. */
+	outw(0x0000, ioaddr+PCNET32_ADDR);
+	outw(0x0048, ioaddr+PCNET32_DATA);
+
+	dev->trans_start = jiffies;
+
+	save_flags(flags);
+	cli();
+	lp->lock = 0;
+	if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
+		clear_bit(0, (void*)&dev->tbusy);
+	else
+		lp->tx_full = 1;
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The PCNET32 interrupt handler. */
+static void
+pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct device *dev = (struct device *)dev_id;
+	struct pcnet32_private *lp;
+	unsigned int csr0, ioaddr;
+	int boguscnt = max_interrupt_work;
+	int must_restart;
+
+	if (dev == NULL) {
+		printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	lp = (struct pcnet32_private *)dev->priv;
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+	dev->interrupt = 1;
+
+	outw(0x00, dev->base_addr + PCNET32_ADDR);
+	while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600
+		   && --boguscnt >= 0) {
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outw(csr0 & ~0x004f, dev->base_addr + PCNET32_DATA);
+
+		must_restart = 0;
+
+		if (pcnet32_debug > 5)
+			printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+				   dev->name, csr0, inw(dev->base_addr + PCNET32_DATA));
+
+		if (csr0 & 0x0400)			/* Rx interrupt */
+			pcnet32_rx(dev);
+
+		if (csr0 & 0x0200) {		/* Tx-done interrupt */
+			int dirty_tx = lp->dirty_tx;
+
+			while (dirty_tx < lp->cur_tx) {
+				int entry = dirty_tx & TX_RING_MOD_MASK;
+				int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
+
+				if (status < 0)
+					break;			/* It still hasn't been Txed */
+
+				lp->tx_ring[entry].base = 0;
+
+				if (status & 0x4000) {
+					/* There was an major error, log it. */
+					int err_status = le16_to_cpu(lp->tx_ring[entry].misc);
+					lp->stats.tx_errors++;
+					if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
+					if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
+					if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+					if (err_status & 0x40000000) {
+						/* Ackk!  On FIFO errors the Tx unit is turned off! */
+						lp->stats.tx_fifo_errors++;
+						/* Remove this verbosity later! */
+						printk("%s: Tx FIFO error! Status %4.4x.\n",
+							   dev->name, csr0);
+						/* Restart the chip. */
+						must_restart = 1;
+					}
+				} else {
+					if (status & 0x1800)
+						lp->stats.collisions++;
+					lp->stats.tx_packets++;
+				}
+
+				/* We must free the original skb */
+				if (lp->tx_skbuff[entry]) {
+					dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+					lp->tx_skbuff[entry] = 0;
+				}
+				dirty_tx++;
+			}
+
+#ifndef final_version
+			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dirty_tx, lp->cur_tx, lp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (lp->tx_full && dev->tbusy
+				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+				/* The ring is no longer full, clear tbusy. */
+				lp->tx_full = 0;
+				clear_bit(0, (void*)&dev->tbusy);
+				mark_bh(NET_BH);
+			}
+
+			lp->dirty_tx = dirty_tx;
+		}
+
+		/* Log misc errors. */
+		if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
+		if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
+		if (csr0 & 0x0800) {
+			printk("%s: Bus master arbitration failure, status %4.4x.\n",
+				   dev->name, csr0);
+			/* Restart the chip. */
+			must_restart = 1;
+		}
+
+		if (must_restart) {
+			/* stop the chip to clear the error condition, then restart */
+			outw(0x0000, dev->base_addr + PCNET32_ADDR);
+			outw(0x0004, dev->base_addr + PCNET32_DATA);
+			pcnet32_restart(dev, 0x0002, 0);
+		}
+	}
+
+	/* Clear any other interrupt, and set interrupt enable. */
+	outw(0x0000, dev->base_addr + PCNET32_ADDR);
+	outw(0x7940, dev->base_addr + PCNET32_DATA);
+
+	if (pcnet32_debug > 4)
+		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
+			   dev->name, inw(ioaddr + PCNET32_ADDR),
+			   inw(dev->base_addr + PCNET32_DATA));
+
+	dev->interrupt = 0;
+	return;
+}
+
+static int
+pcnet32_rx(struct device *dev)
+{
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+	int entry = lp->cur_rx & RX_RING_MOD_MASK;
+	int i;
+
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
+		int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
+
+		if (status != 0x03) {			/* There was an error. */
+			/* There is a tricky error noted by John Murphy,
+			   <murf@perftech.com> to Russ Nelson: Even with full-sized
+			   buffers it's possible for a jabber packet to use two
+			   buffers, with only the last correctly noting the error. */
+			if (status & 0x01)	/* Only count a general error at the */
+				lp->stats.rx_errors++; /* end of a packet.*/
+			if (status & 0x20) lp->stats.rx_frame_errors++;
+			if (status & 0x10) lp->stats.rx_over_errors++;
+			if (status & 0x08) lp->stats.rx_crc_errors++;
+			if (status & 0x04) lp->stats.rx_fifo_errors++;
+			lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+		}
+		else
+		{
+			/* Malloc up new buffer, compatible with net-2e. */
+			short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
+			struct sk_buff *skb;
+
+			if(pkt_len < 60) {
+				printk("%s: Runt packet!\n",dev->name);
+				lp->stats.rx_errors++;
+			} else {
+				skb = dev_alloc_skb(pkt_len+2);
+				if (skb == NULL) {
+					printk("%s: Memory squeeze, deferring packet.\n",
+						   dev->name);
+					for (i=0; i < RX_RING_SIZE; i++)
+						if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
+							break;
+
+					if (i > RX_RING_SIZE -2)
+					{
+						lp->stats.rx_dropped++;
+						lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+						lp->cur_rx++;
+					}
+					break;
+				}
+				skb->dev = dev;
+				skb_reserve(skb,2);	/* 16 byte align */
+				skb_put(skb,pkt_len);	/* Make room */
+				eth_copy_and_sum(skb,
+					(unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
+					pkt_len,0);
+				skb->protocol=eth_type_trans(skb,dev);
+				netif_rx(skb);
+				lp->stats.rx_packets++;
+			}
+		}
+		/* The docs say that the buffer length isn't touched, but Andrew Boyd
+		   of QNX reports that some revs of the 79C965 clear it. */
+		lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+		lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+	}
+
+	/* We should check that at least two ring entries are free.	 If not,
+	   we should free one and mark stats->rx_dropped++. */
+
+	return 0;
+}
+
+static int
+pcnet32_close(struct device *dev)
+{
+	unsigned int ioaddr = dev->base_addr;
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+
+	dev->start = 0;
+	set_bit(0, (void*)&dev->tbusy);
+
+	outw(112, ioaddr+PCNET32_ADDR);
+	lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
+
+	outw(0, ioaddr+PCNET32_ADDR);
+
+	if (pcnet32_debug > 1)
+		printk("%s: Shutting down ethercard, status was %2.2x.\n",
+			   dev->name, inw(ioaddr+PCNET32_DATA));
+
+	/* We stop the PCNET32 here -- it occasionally polls
+	   memory if we don't. */
+	outw(0x0004, ioaddr+PCNET32_DATA);
+
+	free_irq(dev->irq, dev);
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics *pcnet32_get_stats(struct device *dev)
+{
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+	unsigned int ioaddr = dev->base_addr;
+	unsigned short saved_addr;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	saved_addr = inw(ioaddr+PCNET32_ADDR);
+	outw(112, ioaddr+PCNET32_ADDR);
+	lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
+	outw(saved_addr, ioaddr+PCNET32_ADDR);
+	restore_flags(flags);
+
+	return &lp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ */
+
+static void pcnet32_set_multicast_list(struct device *dev)
+{
+	unsigned int ioaddr = dev->base_addr;
+	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+
+	if (dev->flags&IFF_PROMISC) {
+		/* Log any net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		lp->init_block.mode = 0x8000;
+	} else {
+		int num_addrs=dev->mc_count;
+		if(dev->flags&IFF_ALLMULTI)
+			num_addrs=1;
+		/* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
+		memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter));
+		lp->init_block.mode = 0x0000;
+	}
+
+	outw(0, ioaddr+PCNET32_ADDR);
+	outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance. */
+
+	pcnet32_restart(dev, 0x0042, 0); /*  Resume normal operation */
+
+}
+
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("AMD PCnet/PCI ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+#endif
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+	if (debug >= 0)
+		pcnet32_debug = debug;
+
+#ifdef CARDBUS
+	register_driver(&pcnet32_ops);
+	return 0;
+#else
+	return pcnet32_probe(NULL);
+#endif
+}
+
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+#ifdef CARDBUS
+	unregister_driver(&pcnet32_ops);
+#endif
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_pcnet32_dev) {
+		next_dev = ((struct pcnet32_private *)root_pcnet32_dev->priv)->next_module;
+		unregister_netdev(root_pcnet32_dev);
+		release_region(root_pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
+		kfree(root_pcnet32_dev);
+		root_pcnet32_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c pcnet32.c  `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.0.33/linux/drivers/net/ppp.c	Tue Aug 12 14:15:56 1997
+++ linux/drivers/net/ppp.c	Wed Jun  3 15:17:47 1998
@@ -5,8 +5,9 @@
  *
  *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
  *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
+ *  Fixed (I hope) the wait_queue trashing bug. Alan Cox <alan@redhat.com>
  *
- *  ==FILEVERSION 970703==
+ *  ==FILEVERSION 980512==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -448,8 +449,13 @@
 	ppp->ubuf	= NULL;
 	ppp->cbuf	= NULL;
 	ppp->slcomp	= NULL;
+#if 0
+	/* AC - We don't want to initialise this as the wait queue may still
+	   be live. Having someone waiting on the old and the new queue is fine
+	   the old people will unhook themselves so just set this up in ppp_alloc */
 	ppp->read_wait	= NULL;
 	ppp->write_wait = NULL;
+#endif	
 	ppp->last_xmit	= jiffies - flag_time;
 
 	/* clear statistics */
@@ -798,9 +804,7 @@
         }
 
 	if (ppp == NULL) {
-		if (ppp->flags & SC_DEBUG)
-			printk (KERN_ERR
-			"ppp_tty_open: couldn't allocate ppp channel\n");
+		printk (KERN_WARNING "ppp_tty_open: couldn't allocate ppp channel\n");
 		return -ENFILE;
 	}
 /*
diff -u --recursive --new-file v2.0.33/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.0.33/linux/drivers/net/rtl8139.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/rtl8139.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,1301 @@
+/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
+/*
+	Written 1997-1998 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+    All other rights reserved.
+
+	This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet
+	chips.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
+
+	Twister-tuning code contributed by Kinston <shangh@realtek.com.tw>.
+*/
+
+static const char *version =
+"rtl8139.c:v0.99B 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+
+/* A few user-configurable values. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 10;
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX	3			/* 0==8K, 1==16K, 2==32K, 3==64K */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE	1536
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
+#define RX_FIFO_THRESH	4		/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	4		/* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST	4
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((4000*HZ)/1000)
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define RUN_AT(x) (jiffies + (x))
+
+#include <linux/delay.h>
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
+/* The I/O extent. */
+#define RTL8129_TOTAL_SIZE 0x80
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry rtl8139_drv =
+{"RTL8139", rtl8139_probe, RTL8129_TOTAL_SIZE, NULL};
+#endif
+
+static int rtl8129_debug = 1;
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the RealTek RTL8129, the RealTek Fast
+Ethernet controllers for PCI.  This chip is used on a few clone boards.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Rx Ring buffers
+
+The receive unit uses a single linear ring buffer rather than the more
+common (and more efficient) descriptor-based architecture.  Incoming frames
+are sequentially stored into the Rx region, and the host copies them into
+skbuffs.
+
+Comment: While it is theoretically possible to process many frames in place,
+any delay in Rx processing would cause us to drop frames.  More importantly,
+the Linux protocol stack is not designed to operate in this manner.
+
+IIIb. Tx operation
+
+The RTL8129 uses a fixed set of four Tx descriptors in register space.
+In a stunningly bad design choice, Tx frames must be 32 bit aligned.  Linux
+aligns the IP header on word boundaries, and 14 byte ethernet header means
+that almost all frames will need to be copied to an alignment buffer.
+
+IVb. References
+
+http://www.realtek.com.tw/cn/cn.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+IVc. Errata
+
+*/
+
+#ifndef PCI_VENDOR_ID_REALTEK
+#define PCI_VENDOR_ID_REALTEK		0x10ec
+#endif
+#ifndef PCI_DEVICE_ID_REALTEK_8129
+#define PCI_DEVICE_ID_REALTEK_8129	0x8129
+#endif
+#ifndef PCI_DEVICE_ID_REALTEK_8139
+#define PCI_DEVICE_ID_REALTEK_8139	0x8139
+#endif
+
+/* The rest of these values should never change. */
+#define NUM_TX_DESC	4			/* Number of Tx descriptor registers. */
+
+/* Symbolic offsets to registers. */
+enum RTL8129_registers {
+	MAC0=0,						/* Ethernet hardware address. */
+	MAR0=8,						/* Multicast filter. */
+	TxStat0=0x10,				/* Transmit status (Four 32bit registers). */
+	TxAddr0=0x20,				/* Tx descriptors (also four 32bit). */
+	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
+	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
+	IntrMask=0x3C, IntrStatus=0x3E,
+	TxConfig=0x40, RxConfig=0x44,
+	Timer=0x48,					/* A general-purpose counter. */
+	RxMissed=0x4C,				/* 24 bits valid, write clears. */
+	Cfg9346=0x50, Config0=0x51, Config1=0x52,
+	FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
+	MultiIntr=0x5C, TxSummary=0x60,
+	BMCR=0x62, BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, NWayExpansion=0x6A,
+	/* Undocumented registers, but required for proper operation. */
+	FIFOTMS=0x70,	/* FIFO Test Mode Select */
+	CSCR=0x74,	/* Chip Status and Configuration Register. */
+	PARA78=0x78, PARA7c=0x7c,	/* Magic transceiver parameter register. */
+};
+
+enum ChipCmdBits {
+	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+	PCIErr=0x8000, PCSTimeout=0x4000,
+	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
+	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
+};
+enum TxStatusBits {
+	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
+	TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000,
+};
+enum RxStatusBits {
+	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
+	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
+	RxBadAlign=0x0002, RxStatusOK=0x0001,
+};
+
+enum CSCRBits {
+	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
+	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
+	CSCR_LinkDownCmd=0x0f3c0,
+};	
+
+/* Twister tuning parameters from RealTek.  Completely undocumented. */
+unsigned long param[4][4]={
+	{0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
+	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
+	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
+	{0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}
+};
+
+struct rtl8129_private {
+	char devname[8];			/* Used only for kernel debugging. */
+	const char *product_name;
+	struct device *next_module;
+	int chip_id;
+	int chip_revision;
+#if LINUX_VERSION_CODE > 0x20139
+	struct net_device_stats stats;
+#else
+	struct enet_statistics stats;
+#endif
+	struct timer_list timer;	/* Media selection timer. */
+	unsigned int cur_rx, cur_tx;		/* The next free and used entries */
+	unsigned int dirty_rx, dirty_tx;
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[NUM_TX_DESC];
+	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
+	unsigned char *rx_ring;
+	unsigned char *tx_bufs;				/* Tx bounce buffer region. */
+	unsigned char mc_filter[8];			/* Current multicast filter. */
+	char phys[4];						/* MII device addresses. */
+	int in_interrupt;					/* Alpha needs word-wide lock. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int media2:4;				/* Secondary monitored media port. */
+	unsigned int medialock:1;			/* Don't sense media type. */
+	unsigned int mediasense:1;			/* Media sensing in progress. */
+};
+
+#ifdef MODULE
+/* Used to pass the full-duplex flag, etc. */
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(max_interrupt_work, "i");
+#endif
+#endif
+
+static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
+									 int chip_id, int options, int card_idx);
+static int rtl8129_open(struct device *dev);
+static int read_eeprom(int ioaddr, int location);
+static int mdio_read(int ioaddr, int phy_id, int location);
+static void rtl8129_timer(unsigned long data);
+static void rtl8129_tx_timeout(struct device *dev);
+static void rtl8129_init_ring(struct device *dev);
+static int rtl8129_start_xmit(struct sk_buff *skb, struct device *dev);
+static int rtl8129_rx(struct device *dev);
+static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int rtl8129_close(struct device *dev);
+static struct enet_statistics *rtl8129_get_stats(struct device *dev);
+static void set_rx_mode(struct device *dev);
+
+
+#ifdef MODULE
+/* A list of all installed RTL8129 devices, for removing the driver module. */
+static struct device *root_rtl8129_dev = NULL;
+#endif
+
+int rtl8139_probe(struct device *dev)
+{
+	int cards_found = 0;
+	static int pci_index = 0;	/* Static, for multiple probe calls. */
+
+	/* Ideally we would detect all network cards in slot order.  That would
+	   be best done a central PCI probe dispatch, which wouldn't work
+	   well with the current structure.  So instead we detect just the
+	   Rtl81*9 cards in slot order. */
+
+	if (pcibios_present()) {
+		unsigned char pci_bus, pci_device_fn;
+
+		for (;pci_index < 0xff; pci_index++) {
+			u8 pci_irq_line, pci_latency;
+			u16 pci_command, new_command, vendor, device;
+			u32 pci_ioaddr;
+
+			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+#ifdef REVERSE_PROBE_ORDER
+									0xff - pci_index,
+#else
+									pci_index,
+#endif
+									&pci_bus, &pci_device_fn)
+				!= PCIBIOS_SUCCESSFUL)
+				break;
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_VENDOR_ID, &vendor);
+			if (vendor != PCI_VENDOR_ID_REALTEK)
+				continue;
+
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_DEVICE_ID, &device);
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			/* Remove I/O space marker in bit 0. */
+			pci_ioaddr &= ~3;
+
+			if (device != PCI_DEVICE_ID_REALTEK_8129
+				&&  device != PCI_DEVICE_ID_REALTEK_8139) {
+				printk(KERN_NOTICE "Unknown RealTek PCI ethernet chip type "
+					   "%4.4x detected: not configured.\n", device);
+				continue;
+			}
+			if (check_region(pci_ioaddr, RTL8129_TOTAL_SIZE))
+				continue;
+
+			/* Activate the card: fix for brain-damaged Win98 BIOSes. */
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+			if (pci_command != new_command) {
+				printk(KERN_INFO "  The PCI BIOS has not enabled this"
+					   " device!  Updating PCI config %4.4x->%4.4x.\n",
+					   pci_command, new_command);
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, new_command);
+			}
+
+#ifdef MODULE
+			dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,
+								 options[cards_found], cards_found);
+#else
+			dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,
+								 dev ? dev->mem_start : 0, -1);
+#endif
+
+			if (dev) {
+				pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_LATENCY_TIMER, &pci_latency);
+				if (pci_latency < 32) {
+					printk(KERN_NOTICE"  PCI latency timer (CFLT) is "
+						   "unreasonably low at %d.  Setting to 64 clocks.\n",
+						   pci_latency);
+					pcibios_write_config_byte(pci_bus, pci_device_fn,
+											  PCI_LATENCY_TIMER, 64);
+				} else if (rtl8129_debug > 1)
+					printk(KERN_INFO"  PCI latency timer (CFLT) is %#x.\n",
+						   pci_latency);
+				dev = 0;
+				cards_found++;
+			}
+		}
+	}
+
+#if defined (MODULE)
+	return cards_found;
+#else
+	return cards_found ? 0 : -ENODEV;
+#endif
+}
+
+static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
+								   int chip_id, int options, int card_idx)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct rtl8129_private *tp;
+	int i;
+
+	if (rtl8129_debug > 0  &&  did_version++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	dev = init_etherdev(dev, 0);
+
+	printk(KERN_INFO "%s: RealTek RTL%x at %#3x, IRQ %d, ",
+		   dev->name, chip_id, ioaddr, irq);
+
+	/* Bring the chip out of low-power mode. */
+	outb(0x00, ioaddr + Config1);
+
+	/* Perhaps this should be read from the EEPROM? */
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
+
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x.\n", dev->dev_addr[i]);
+
+	if (rtl8129_debug > 1) {
+		printk(KERN_INFO "%s: EEPROM contents\n", dev->name);
+		for (i = 0; i < 64; i++)
+			printk(" %4.4x%s", read_eeprom(ioaddr, i),
+				   i%16 == 15 ? "\n"KERN_INFO : "");
+	}
+
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, RTL8129_TOTAL_SIZE, "RealTek RTL8129/39 Fast Ethernet");
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* Some data structures must be quadword aligned. */
+	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
+	memset(tp, 0, sizeof(*tp));
+	dev->priv = tp;
+
+#ifdef MODULE
+	tp->next_module = root_rtl8129_dev;
+	root_rtl8129_dev = dev;
+#endif
+
+	tp->chip_id = chip_id;
+
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	if (chip_id == 0x8129) {
+		int phy, phy_idx;
+		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+			 phy++) {
+			int mii_status = mdio_read(ioaddr, phy, 1);
+
+			if (mii_status != 0xffff  && mii_status != 0x0000) {
+				tp->phys[phy_idx++] = phy;
+				printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
+					   dev->name, phy);
+			}
+		}
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
+				   "transceiver.\n",
+				   dev->name);
+			tp->phys[0] = -1;
+		}
+	} else {
+			tp->phys[0] = -1;
+	}
+
+	/* Put the chip into low-power mode. */
+	outb(0xC0, ioaddr + Cfg9346);
+	outb(0x03, ioaddr + Config1);
+	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
+
+	/* The lower four bits are the media type. */
+	if (options > 0) {
+		tp->full_duplex = (options & 16) ? 1 : 0;
+		tp->default_port = options & 15;
+		if (tp->default_port)
+			tp->medialock = 1;
+	}
+#ifdef MODULE
+	if (card_idx >= 0) {
+		if (full_duplex[card_idx] >= 0)
+			tp->full_duplex = full_duplex[card_idx];
+	}
+#endif
+
+	/* The Rtl8129-specific entries in the device structure. */
+	dev->open = &rtl8129_open;
+	dev->hard_start_xmit = &rtl8129_start_xmit;
+	dev->stop = &rtl8129_close;
+	dev->get_stats = &rtl8129_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+
+	return dev;
+}
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS			0x08	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x00
+#define EE_WRITE_1		0x02
+#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
+#define EE_ENB			(0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but 66Mhz is untested.
+ */
+
+#ifdef _LINUX_DELAY_H
+#define eeprom_delay(nanosec)	udelay(1)
+#else
+#define eeprom_delay(nanosec)	do { ; } while (0)
+#endif
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+static int read_eeprom(int ioaddr, int location)
+{
+	int i;
+	unsigned retval = 0;
+	int ee_addr = ioaddr + Cfg9346;
+	int read_cmd = location | EE_READ_CMD;
+
+	outb(EE_ENB & ~EE_CS, ee_addr);
+	outb(EE_ENB, ee_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outb(EE_ENB | dataval, ee_addr);
+		eeprom_delay(100);
+		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(150);
+		outb(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay(250);
+	}
+	outb(EE_ENB, ee_addr);
+
+	for (i = 16; i > 0; i--) {
+		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(100);
+		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outb(EE_ENB, ee_addr);
+		eeprom_delay(100);
+	}
+
+	/* Terminate the EEPROM access. */
+	outb(~EE_CS, ee_addr);
+	return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+   serial MDIO protocol.
+   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues. */
+#define MDIO_DIR		0x80
+#define MDIO_DATA_OUT	0x04
+#define MDIO_DATA_IN	0x02
+#define MDIO_CLK		0x01
+#ifdef _LINUX_DELAY_H
+#define mdio_delay()	udelay(1) /* Really 400ns. */
+#else
+#define mdio_delay()	do { ; } while (0)
+#endif
+
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync(int ioaddr)
+{
+	int i;
+	int mdio_addr = ioaddr + MII_SMI;
+
+	for (i = 32; i >= 0; i--) {
+		outb(MDIO_DIR | MDIO_DATA_OUT, mdio_addr);
+		mdio_delay();
+		outb(MDIO_DIR | MDIO_DATA_OUT | MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return;
+}
+static int mdio_read(int ioaddr, int phy_id, int location)
+{
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int retval = 0;
+	int mdio_addr = ioaddr + MII_SMI;
+
+	mdio_sync(ioaddr);
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval =
+		  (read_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+		outb(MDIO_DIR | dataval, mdio_addr);
+		mdio_delay();
+		outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outb(0, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
+		outb(MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static int
+rtl8129_open(struct device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+	int full_duplex = 0;
+
+	/* Soft reset the chip. */
+	outb(CmdReset, ioaddr + ChipCmd);
+
+	if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {
+		return -EAGAIN;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
+	tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);
+	if (tp->tx_bufs == NULL ||  tp->rx_ring == NULL) {
+		if (tp->tx_bufs)
+			kfree(tp->tx_bufs);
+		if (rtl8129_debug > 0)
+			printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
+				   dev->name, RX_BUF_LEN);
+		return -ENOMEM;
+	}
+	rtl8129_init_ring(dev);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--)
+		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
+			break;
+
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
+		 ioaddr + RxConfig);
+	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
+
+	full_duplex = tp->full_duplex;
+	if (tp->phys[0] >= 0  ||  tp->chip_id == 0x8139) {
+		u16 mii_reg5;
+		if (tp->chip_id == 0x8139)
+			mii_reg5 = inw(ioaddr + NWayLPAR);
+		else
+			mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
+		if (mii_reg5 == 0xffff)
+			;					/* Not there */
+		else if ((mii_reg5 & 0x0100) == 0x0100
+				 || (mii_reg5 & 0x00C0) == 0x0040)
+			full_duplex = 1;
+		if (rtl8129_debug > 1)
+			printk(KERN_INFO"%s: Setting %s%s-duplex based on"
+				   " auto-negotiated partner ability %4.4x.\n", dev->name,
+				   mii_reg5 == 0 ? "" :
+				   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
+				   full_duplex ? "full" : "half", mii_reg5);
+	}
+
+	outb(0xC0, ioaddr + Cfg9346);
+	outb(full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+	outb(0x00, ioaddr + Cfg9346);
+
+	outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);
+
+	/* Start the chip's Tx and Rx process. */
+	outl(0, ioaddr + RxMissed);
+	set_rx_mode(dev);
+
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* Enable all known interrupts by setting the interrupt mask. */
+	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		| TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
+
+	if (rtl8129_debug > 1)
+		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %4.4x IRQ %d"
+			   " GP Pins %2.2x %s-duplex.\n",
+			   dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
+			   full_duplex ? "full" : "half");
+
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer(&tp->timer);
+	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = &rtl8129_timer;				/* timer handler */
+	add_timer(&tp->timer);
+
+	return 0;
+}
+
+static void rtl8129_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int next_tick = 0;
+
+	if (tp->chip_id == 0x8139) {
+		u16 mii_reg5 = inw(ioaddr + NWayLPAR);
+		if ((mii_reg5 & 0x0100) == 0x0100
+			|| (mii_reg5 & 0x00C0) == 0x0040)
+			if ( ! tp->full_duplex) {
+				tp->full_duplex = 1;
+				if (rtl8129_debug > 0)
+					printk(KERN_INFO "%s: Switching to full-duplex based on "
+						   "link partner ability of %4.4x.\n",
+						   dev->name, mii_reg5);
+				outb(0xC0, ioaddr + Cfg9346);
+				outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+				outb(0x00, ioaddr + Cfg9346);
+			}
+	}
+	if (rtl8129_debug > 2) {
+		if (tp->chip_id == 0x8129)
+			printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
+				   dev->name, inb(ioaddr + GPPinData));
+		else
+			printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",
+				   dev->name, inw(ioaddr + NWayLPAR));
+		printk(KERN_DEBUG"%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
+			   " RxStatus %4.4x.\n",
+			   dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),
+			   inl(ioaddr + RxEarlyStatus));
+		printk(KERN_DEBUG"%s:  Chip config %2.2x %2.2x.\n",
+			   dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
+	}
+
+	if (next_tick) {
+		tp->timer.expires = RUN_AT(next_tick);
+		add_timer(&tp->timer);
+	}
+}
+
+static void rtl8129_tx_timeout(struct device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outw(0x0000, ioaddr + IntrMask);
+
+	if (rtl8129_debug > 0)
+		printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x.\n",
+			   dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus));
+	/* Emit info to figure out what went wrong. */
+	for (i = 0; i < NUM_TX_DESC; i++)
+		printk(KERN_DEBUG"%s:  Tx descriptor %d is %8.8x.%s\n",
+			   dev->name, i, inl(ioaddr + TxStat0 + i*4),
+			   i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
+	if (tp->chip_id == 0x8129) {
+		int mii_reg;
+		printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
+		for (mii_reg = 0; mii_reg < 8; mii_reg++)
+			printk(" %4.4x", mdio_read(ioaddr, tp->phys[0], mii_reg));
+		printk(".\n");
+	} else {
+		printk(KERN_DEBUG"%s: MII status register is %4.4x.\n",
+			   dev->name, inw(ioaddr + BMSR));
+	}
+
+	/* Soft reset the chip. */
+	outb(CmdReset, ioaddr + ChipCmd);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
+
+	{							/* Save the unsent Tx packets. */
+		struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
+		int j = 0;
+		for (; tp->cur_tx - tp->dirty_tx > 0 ; tp->dirty_tx++)
+			saved_skb[j++] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];
+		tp->dirty_tx = tp->cur_tx = 0;
+
+		for (i = 0; i < j; i++) {
+			skb = tp->tx_skbuff[i] = saved_skb[i];
+			if ((long)skb->data & 3) {		/* Must use alignment buffer. */
+				memcpy(tp->tx_buf[i], skb->data, skb->len);
+				outl(virt_to_bus(tp->tx_buf[i]), ioaddr + TxAddr0 + i*4);
+			} else
+				outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4);
+			/* Note: the chip doesn't have auto-pad! */
+			outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
+				 (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+				 ioaddr + TxStat0 + i*4);
+		}
+		tp->cur_tx = i;
+		while (i < NUM_TX_DESC)
+			tp->tx_skbuff[i] = 0;
+		if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
+			dev->tbusy = 0;
+		} else {
+			tp->tx_full = 1;
+		}
+	}
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	set_rx_mode(dev);
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
+		 ioaddr + RxConfig);
+	outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
+
+	dev->trans_start = jiffies;
+	tp->stats.tx_errors++;
+	/* Enable all known interrupts by setting the interrupt mask. */
+	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
+	return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+rtl8129_init_ring(struct device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int i;
+
+	tp->tx_full = 0;
+	tp->cur_rx = tp->cur_tx = 0;
+	tp->dirty_rx = tp->dirty_tx = 0;
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];
+	}
+}
+
+static int
+rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int entry;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start < TX_TIMEOUT)
+			return 1;
+		rtl8129_tx_timeout(dev);
+		return 1;
+	}
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % NUM_TX_DESC;
+
+	tp->tx_skbuff[entry] = skb;
+	if ((long)skb->data & 3) {			/* Must use alignment buffer. */
+		memcpy(tp->tx_buf[entry], skb->data, skb->len);
+		outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4);
+	} else
+		outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);
+	/* Note: the chip doesn't have auto-pad! */
+	outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
+		 (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+		 ioaddr + TxStat0 + entry*4);
+
+	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
+		dev->tbusy = 0;
+	} else {
+		tp->tx_full = 1;
+	}
+
+	dev->trans_start = jiffies;
+	if (rtl8129_debug > 4)
+		printk(KERN_DEBUG"%s: Queued Tx packet at %p size %ld to slot %d.\n",
+			   dev->name, skb->data, skb->len, entry);
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *)dev_instance;
+	struct rtl8129_private *tp;
+	int ioaddr, boguscnt = max_interrupt_work;
+	int status;
+
+	if (dev == NULL) {
+		printk (KERN_ERR"rtl8139_interrupt(): IRQ %d for unknown device.\n",
+				irq);
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	tp = (struct rtl8129_private *)dev->priv;
+	if (test_and_set_bit(0, (void*)&tp->in_interrupt)) {
+		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+		return;
+	}
+	dev->interrupt = 1;
+
+	do {
+		status = inw(ioaddr + IntrStatus);
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outw(status, ioaddr + IntrStatus);
+
+		if (rtl8129_debug > 4)
+			printk(KERN_DEBUG"%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
+				   dev->name, status, inw(ioaddr + IntrStatus));
+
+		if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver
+					   |TxErr|TxOK|RxErr|RxOK)) == 0)
+			break;
+
+		if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */
+			rtl8129_rx(dev);
+
+		if (status & (TxOK | TxErr)) {
+			unsigned int dirty_tx;
+
+			for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
+				int entry = dirty_tx % NUM_TX_DESC;
+				int txstatus = inl(ioaddr + TxStat0 + entry*4);
+
+				if ( ! (txstatus & TxHostOwns))
+					break;			/* It still hasn't been Txed */
+
+				/* Note: TxCarrierLost is always asserted at 100mbps. */
+				if (txstatus & (TxOutOfWindow | TxAborted)) {
+					/* There was an major error, log it. */
+#ifndef final_version
+					if (rtl8129_debug > 1)
+						printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
+							   dev->name, txstatus);
+#endif
+					tp->stats.tx_errors++;
+					if (txstatus&TxAborted) {
+						tp->stats.tx_aborted_errors++;
+						outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig);
+					}
+					if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++;
+					if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++;
+#ifdef ETHER_STATS
+					if ((txstatus & 0x0f000000) == 0x0f000000)
+						tp->stats.collisions16++;
+#endif
+				} else {
+#ifdef ETHER_STATS
+					/* No count for tp->stats.tx_deferred */
+#endif
+					if (txstatus & TxUnderrun) {
+						/* Todo: increase the Tx FIFO threshold. */
+						tp->stats.tx_fifo_errors++;
+					}
+					tp->stats.collisions += (txstatus >> 24) & 15;
+#if LINUX_VERSION_CODE > 0x20119
+					tp->stats.tx_bytes += txstatus & 0x7ff;
+#endif
+					tp->stats.tx_packets++;
+				}
+
+				/* Free the original skb. */
+				dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+				tp->tx_skbuff[entry] = 0;
+			}
+
+#ifndef final_version
+			if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+				printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+				dirty_tx += NUM_TX_DESC;
+			}
+#endif
+
+			if (tp->tx_full && dev->tbusy
+				&& dirty_tx > tp->cur_tx - NUM_TX_DESC) {
+				/* The ring is no longer full, clear tbusy. */
+				tp->tx_full = 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+
+			tp->dirty_tx = dirty_tx;
+		}
+
+		/* Check uncommon events with one test. */
+		if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
+					  |TxErr|RxErr)) {
+			/* Update the error count. */
+			tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+			outl(0, ioaddr + RxMissed);
+
+			if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
+				tp->stats.rx_errors++;
+
+			if (status & (PCSTimeout)) tp->stats.rx_length_errors++;
+			if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++;
+			if (status & RxOverflow) {
+				tp->stats.rx_over_errors++;
+				tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
+				outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
+			}
+			/* Error sources cleared above. */
+		}
+		if (--boguscnt < 0) {
+			printk(KERN_WARNING"%s: Too much work at interrupt, "
+				   "IntrStatus=0x%4.4x.\n",
+				   dev->name, status);
+			/* Clear all interrupt sources. */
+			outw(0xffff, ioaddr + IntrStatus);
+			break;
+		}
+	} while (1);
+
+	if (rtl8129_debug > 3)
+		printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
+			   dev->name, inl(ioaddr + IntrStatus));
+
+	dev->interrupt = 0;
+	clear_bit(0, (void*)&tp->in_interrupt);
+	return;
+}
+
+/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
+   field alignments and semantics. */
+static int
+rtl8129_rx(struct device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	unsigned char *rx_ring = tp->rx_ring;
+	u16 cur_rx = tp->cur_rx;
+
+	if (rtl8129_debug > 4)
+		printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x,"
+			   " free to %4.4x, Cmd %2.2x.\n",
+			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
+			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
+
+	while ((inb(ioaddr + ChipCmd) & 1) == 0) {
+		int ring_offset = cur_rx % RX_BUF_LEN;
+		u32 rx_status = *(u32*)(rx_ring + ring_offset);
+		int rx_size = rx_status >> 16;
+
+		if (rtl8129_debug > 4) {
+			int i;
+			printk(KERN_DEBUG"%s:  rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n",
+				   dev->name, rx_status, rx_size, cur_rx);
+			printk(KERN_DEBUG"%s: Frame contents ", dev->name);
+			for (i = 0; i < 70; i++)
+				printk(" %2.2x", rx_ring[ring_offset + i]);
+			printk(".\n");
+		}
+		if (rx_status & RxTooLong) {
+			if (rtl8129_debug > 0)
+				printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",
+					   dev->name, rx_status);
+			tp->stats.rx_length_errors++;
+		} else if (rx_status &
+				   (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {
+			if (rtl8129_debug > 1)
+				printk(KERN_DEBUG"%s: Ethernet frame had errors,"
+					   " status %4.4x.\n", dev->name, rx_status);
+			tp->stats.rx_errors++;
+			if (rx_status & (RxBadSymbol|RxBadAlign))
+				tp->stats.rx_frame_errors++;
+			if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;
+			if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;
+			/* Reset the receiver, based on RealTek recommendation. (Bug?) */
+			tp->cur_rx = 0;
+			outb(CmdTxEnb, ioaddr + ChipCmd);
+			outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+			outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) |
+				 (RX_DMA_BURST<<8), ioaddr + RxConfig);
+		} else {
+			/* Malloc up new buffer, compatible with net-2e. */
+			/* Omit the four octet CRC from the length. */
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb(rx_size + 2);
+			if (skb == NULL) {
+				printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",
+					   dev->name);
+				/* We should check that some rx space is free.
+				   If not, free one and mark stats->rx_dropped++. */
+				tp->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* 16 byte align the IP fields. */
+			if (ring_offset+rx_size+4 > RX_BUF_LEN) {
+				int semi_count = RX_BUF_LEN - ring_offset - 4;
+				memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],
+					   semi_count);
+				memcpy(skb_put(skb, rx_size-semi_count), rx_ring,
+					   rx_size-semi_count);
+				if (rtl8129_debug > 4) {
+					int i;
+					printk(KERN_DEBUG"%s:  Frame wrap @%d",
+						   dev->name, semi_count);
+					for (i = 0; i < 16; i++)
+						printk(" %2.2x", rx_ring[i]);
+					printk(".\n");
+					memset(rx_ring, 0xcc, 16);
+				}
+			} else
+				memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
+					   rx_size);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+#if LINUX_VERSION_CODE > 0x20119
+			tp->stats.rx_bytes += rx_size;
+#endif
+			tp->stats.rx_packets++;
+		}
+
+		cur_rx += rx_size + 4;
+		cur_rx = (cur_rx + 3) & ~3;
+		outw(cur_rx - 16, ioaddr + RxBufPtr);
+	}
+	if (rtl8129_debug > 4)
+		printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"
+			   " free to %4.4x, Cmd %2.2x.\n",
+			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
+			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
+	tp->cur_rx = cur_rx;
+	return 0;
+}
+
+static int
+rtl8129_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (rtl8129_debug > 1)
+		printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
+			   dev->name, inw(ioaddr + IntrStatus));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outw(0x0000, ioaddr + IntrMask);
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	outb(0x00, ioaddr + ChipCmd);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+	outl(0, ioaddr + RxMissed);
+
+	del_timer(&tp->timer);
+
+	free_irq(dev->irq, dev);
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		if (tp->tx_skbuff[i])
+			dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+		tp->tx_skbuff[i] = 0;
+	}
+	kfree(tp->rx_ring);
+	kfree(tp->tx_bufs);
+
+	/* Green! Put the chip in low-power mode. */
+	outb(0xC0, ioaddr + Cfg9346);
+	outb(0x03, ioaddr + Config1);
+	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics *
+rtl8129_get_stats(struct device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (dev->start) {
+		tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+		outl(0, ioaddr + RxMissed);
+	}
+
+	return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling tp->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+
+/* The little-endian AUTODIN II ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+static void set_rx_mode(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	unsigned char mc_filter[8];		 /* Multicast hash filter */
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		outb(0x0F, ioaddr + RxConfig);
+	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		outb(0x0E, ioaddr + RxConfig);
+	} else if (dev->mc_count == 0) {
+		outb(0x0A, ioaddr + RxConfig);
+		return;
+	} else {
+		struct dev_mc_list *mclist;
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next)
+			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
+					mc_filter);
+	}
+	/* ToDo: perhaps we need to stop the Tx and Rx process here? */
+	if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) {
+		for (i = 0; i < 2; i++)
+			outl(((u32 *)mc_filter)[i], ioaddr + MAR0 + i*4);
+		memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter));
+	}
+	if (rtl8129_debug > 3)
+		printk(KERN_DEBUG"%s:   set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+			   dev->name, dev->flags, inl(ioaddr + RxConfig));
+	return;
+}
+
+#ifdef MODULE
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+	int cards_found;
+
+	if (debug >= 0)
+		rtl8129_debug = debug;
+
+	root_rtl8129_dev = NULL;
+	cards_found = rtl8139_probe(0);
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_rtl8129_dev) {
+		next_dev = ((struct rtl8129_private *)root_rtl8129_dev->priv)->next_module;
+		unregister_netdev(root_rtl8129_dev);
+		release_region(root_rtl8129_dev->base_addr, RTL8129_TOTAL_SIZE);
+		kfree(root_rtl8129_dev);
+		root_rtl8129_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.0.33/linux/drivers/net/sdla.c	Tue Apr  8 08:47:46 1997
+++ linux/drivers/net/sdla.c	Wed Jun  3 15:17:47 1998
@@ -32,6 +32,7 @@
  *		2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.0.33/linux/drivers/net/sk_g16.c	Mon May  6 02:26:09 1996
+++ linux/drivers/net/sk_g16.c	Wed Jun  3 15:17:47 1998
@@ -778,16 +778,16 @@
 	    dev->dev_addr[4],
 	    dev->dev_addr[5]);
 
-    /* Grab the I/O Port region */
-    request_region(ioaddr, ETHERCARD_TOTAL_SIZE,"sk_g16");
-
-    /* Initialize device structure */
-
     /* Allocate memory for private structure */
     p = dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL);
-    if (p == NULL)
+    if (p == NULL) {
+	   printk("%s: ERROR - no memory for driver data!\n", dev->name);
 	   return -ENOMEM;
+    }
     memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */
+
+    /* Grab the I/O Port region */
+    request_region(ioaddr, ETHERCARD_TOTAL_SIZE,"sk_g16");
 
     /* Assign our Device Driver functions */
 
diff -u --recursive --new-file v2.0.33/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.0.33/linux/drivers/net/smc-ultra.c	Wed Jun  5 23:54:05 1996
+++ linux/drivers/net/smc-ultra.c	Wed Jun  3 15:17:47 1998
@@ -2,7 +2,7 @@
 /*
 	This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards.
 
-	Written 1993-1996 by Donald Becker.
+	Written 1993-1998 by Donald Becker.
 
 	Copyright 1993 United States Government as represented by the
 	Director, National Security Agency.
@@ -14,7 +14,7 @@
 	Center of Excellence in Space Data and Information Sciences
 		Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
-	This driver uses the cards in the 8390-compatible, shared memory mode.
+	This driver uses the cards in the 8390-compatible mode.
 	Most of the run-time complexity is handled by the generic code in
 	8390.c.  The code in this file is responsible for
 
@@ -27,6 +27,8 @@
 
 		ultra_block_input()		Routines for reading and writing blocks of
 		ultra_block_output()	packet buffer memory.
+		ultra_pio_input()
+		ultra_pio_output()
 
 	This driver enables the shared memory only when doing the actual data
 	transfers to avoid a bug in early version of the card that corrupted
@@ -34,7 +36,7 @@
 
 	This driver now supports the programmed-I/O (PIO) data transfer mode of
 	the EtherEZ. It does not use the non-8390-compatible "Altego" mode.
-	That support (if available) is smc-ez.c.
+	That support (if available) is in smc-ez.c.
 
 	Changelog:
 
@@ -44,8 +46,7 @@
 */
 
 static const char *version =
-	"smc-ultra.c:v2.00 6/6/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
+	"smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
 
@@ -69,18 +70,18 @@
 
 static int ultra_open(struct device *dev);
 static void ultra_reset_8390(struct device *dev);
-static void ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, 
+static void ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void ultra_block_input(struct device *dev, int count,
 						  struct sk_buff *skb, int ring_offset);
 static void ultra_block_output(struct device *dev, int count,
 							const unsigned char *buf, const start_page);
-static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, 
+static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void ultra_pio_input(struct device *dev, int count,
 						  struct sk_buff *skb, int ring_offset);
 static void ultra_pio_output(struct device *dev, int count,
-							const unsigned char *buf, const start_page);
+							 const unsigned char *buf, const start_page);
 static int ultra_close_card(struct device *dev);
 
 
@@ -151,11 +152,8 @@
 	if ((checksum & 0xff) != 0xFF)
 		return ENODEV;
 
-	/* We should have a "dev" from Space.c or the static module table. */
-	if (dev == NULL) {
-		printk("smc-ultra.c: Passed a NULL device.\n");
+	if (dev == NULL)
 		dev = init_etherdev(0, 0);
-	}
 
 	if (ei_debug  &&  version_printed++ == 0)
 		printk(version);
@@ -201,7 +199,7 @@
 		printk (", no memory for dev->priv.\n");
                 return -ENOMEM;
         }
- 
+
 	/* OK, we are certain this is going to work.  Setup the device. */
 	request_region(ioaddr, ULTRA_IO_EXTENT, model_name);
 
@@ -251,12 +249,19 @@
 ultra_open(struct device *dev)
 {
 	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+	unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40,
+							   0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, };
 
-	if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, NULL))
+	if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev))
 		return -EAGAIN;
 
 	outb(0x00, ioaddr);	/* Disable shared memory for safety. */
 	outb(0x80, ioaddr + 5);
+	/* Set the IRQ line. */
+	outb(inb(ioaddr + 4) | 0x80, ioaddr + 4);
+	outb((inb(ioaddr + 13) & ~0x4C) | irq2reg[dev->irq], ioaddr + 13);
+	outb(inb(ioaddr + 4) & 0x7f, ioaddr + 4);
+
 	if (ei_status.block_input == &ultra_pio_input) {
 		outb(0x11, ioaddr + 6);		/* Enable interrupts and PIO. */
 		outb(0x01, ioaddr + 0x19);  	/* Enable ring read auto-wrap. */
@@ -354,10 +359,10 @@
    byte-sequentially to IOPA, with no intervening I/O operations, and the
    data is read or written to the IOPD data port.
    The only potential complication is that the address register is shared
-   must be always be rewritten between each read/write direction change.
+   and must be always be rewritten between each read/write direction change.
    This is no problem for us, as the 8390 code ensures that we are single
    threaded. */
-static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, 
+static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page)
 {
 	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
@@ -375,12 +380,8 @@
 	/* For now set the address again, although it should already be correct. */
 	outb(ring_offset, ioaddr + IOPA);	/* Set the address, LSB first. */
 	outb(ring_offset >> 8, ioaddr + IOPA);
+	/* We know skbuffs are padded to at least word alignment. */
 	insw(ioaddr + IOPD, buf, (count+1)>>1);
-#ifdef notdef
-	/* We don't need this -- skbuffs are padded to at least word alignment. */
-	if (count & 0x01) {
-		buf[count-1] = inb(ioaddr + IOPD);
-#endif
 }
 
 static void ultra_pio_output(struct device *dev, int count,
@@ -389,6 +390,7 @@
 	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
 	outb(0x00, ioaddr + IOPA);	/* Set the address, LSB first. */
 	outb(start_page, ioaddr + IOPA);
+	/* An extra odd byte is OK here as well. */
 	outsw(ioaddr + IOPD, buf, (count+1)>>1);
 }
 
@@ -404,7 +406,7 @@
 		printk("%s: Shutting down ethercard.\n", dev->name);
 
 	outb(0x00, ioaddr + 6);		/* Disable interrupts. */
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 	irq2dev_map[dev->irq] = 0;
 
 	NS8390_init(dev, 0);
@@ -488,6 +490,7 @@
  *  version-control: t
  *  kept-new-versions: 5
  *  c-indent-level: 4
+ *  c-basic-offset: 4
  *  tab-width: 4
  * End:
  */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/smc-ultra32.c linux/drivers/net/smc-ultra32.c
--- v2.0.33/linux/drivers/net/smc-ultra32.c	Tue Aug 12 16:04:57 1997
+++ linux/drivers/net/smc-ultra32.c	Wed Jun  3 15:17:47 1998
@@ -238,8 +238,9 @@
 static int ultra32_open(struct device *dev)
 {
 	int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
+	int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : SA_SHIRQ;
 
-	if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, NULL))
+	if (request_irq(dev->irq, ei_interrupt, irq_flags, ei_status.name, dev))
 		return -EAGAIN;
 
 	outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
diff -u --recursive --new-file v2.0.33/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.0.33/linux/drivers/net/strip.c	Sat Aug 17 11:19:26 1996
+++ linux/drivers/net/strip.c	Wed Jun  3 15:17:47 1998
@@ -73,7 +73,6 @@
 #include <linux/version.h>
 #endif
 
-#include <stdlib.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
diff -u --recursive --new-file v2.0.33/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.0.33/linux/drivers/net/tlan.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tlan.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,2703 @@
+/********************************************************************
+ *
+ *  Linux ThunderLAN Driver
+ *
+ *  tlan.c
+ *  by James Banks, james.banks@caldera.com
+ *
+ *  (C) 1997 Caldera, Inc.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ *
+ ** This file is best viewed/edited with tabstop=4 and colums>=132.
+ *
+ ** Useful (if not required) reading:
+ *
+ *		Texas Instruments, ThunderLAN Programmer's Guide,
+ *			TI Literature Number SPWU013A
+ *			available in PDF format from www.ti.com
+ *		National Semiconductor, DP83840A Data Sheet
+ *			available in PDF format from www.national.com
+ *		Microchip Technology, 24C01A/02A/04A Data Sheet
+ *			available in PDF format from www.microchip.com
+ *
+ ********************************************************************/
+
+
+#include <linux/module.h>
+
+#include "tlan.h"
+
+#include <linux/bios32.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+
+
+typedef u32 (TLanIntVectorFunc)( struct device *, u16 );
+
+
+#ifdef MODULE
+
+static	struct device	*TLanDevices = NULL;
+static	int		TLanDevicesInstalled = 0;
+
+#endif
+
+
+static  int		debug = 0;
+static	int		aui = 0;
+static	u8		*TLanPadBuffer;
+static	char		TLanSignature[] = "TLAN";
+static	int		TLanVersionMajor = 0;
+static	int		TLanVersionMinor = 38;
+
+
+static	TLanPciId TLanDeviceList[] = {
+	{ PCI_VENDOR_ID_COMPAQ, 
+	  PCI_DEVICE_ID_NETELLIGENT_10,
+	  "Compaq Netelligent 10"
+	},
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETELLIGENT_10_100,
+	  "Compaq Netelligent 10/100"
+	}, 
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED,
+	  "Compaq Integrated NetFlex-3/P"
+	}, 
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETFLEX_3P,
+	  "Compaq NetFlex-3/P"
+	},
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETFLEX_3P_BNC,
+	  "Compaq NetFlex-3/P"
+	},
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT,
+	  "Compaq ProLiant Netelligent 10/100"
+	},
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL,
+	  "Compaq Dual Port Netelligent 10/100"
+	},
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_DESKPRO_4000_5233MMX,
+	  "Compaq Deskpro 4000 5233MMX"
+	},
+	{ 0,
+	  0,
+	  NULL
+	} /* End of List */
+};
+
+
+static int	TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * );
+static int	TLan_Init( struct device * );
+static int	TLan_Open(struct device *dev);
+static int	TLan_StartTx(struct sk_buff *, struct device *);
+static void	TLan_HandleInterrupt(int, void *, struct pt_regs *);
+static int	TLan_Close(struct device *);
+static struct	net_device_stats *TLan_GetStats( struct device * );
+static void	TLan_SetMulticastList( struct device * );
+
+static u32	TLan_HandleInvalid( struct device *, u16 );
+static u32	TLan_HandleTxEOF( struct device *, u16 );
+static u32	TLan_HandleStatOverflow( struct device *, u16 );
+static u32	TLan_HandleRxEOF( struct device *, u16 );
+static u32	TLan_HandleDummy( struct device *, u16 );
+static u32	TLan_HandleTxEOC( struct device *, u16 );
+static u32	TLan_HandleStatusCheck( struct device *, u16 );
+static u32	TLan_HandleRxEOC( struct device *, u16 );
+
+static void	TLan_Timer( unsigned long );
+
+static void	TLan_ResetLists( struct device * );
+static void	TLan_PrintDio( u16 );
+static void	TLan_PrintList( TLanList *, char *, int );
+static void	TLan_ReadAndClearStats( struct device *, int );
+static int	TLan_Reset( struct device * );
+static void	TLan_SetMac( struct device *, int areg, char *mac );
+
+static int	TLan_PhyNop( struct device * );
+static void	TLan_PhyPrint( struct device * );
+static void	TLan_PhySelect( struct device * );
+static int	TLan_PhyInternalCheck( struct device * );
+static int	TLan_PhyInternalService( struct device * );
+static int	TLan_PhyDp83840aCheck( struct device * );
+
+static int	TLan_MiiReadReg(u16, u16, u16, u16 *);
+static void	TLan_MiiSendData( u16, u32, unsigned );
+static void	TLan_MiiSync(u16);
+static void	TLan_MiiWriteReg(u16, u16, u16, u16);
+
+static void	TLan_EeSendStart( u16 );
+static int	TLan_EeSendByte( u16, u8, int );
+static void	TLan_EeReceiveByte( u16, u8 *, int );
+static int	TLan_EeReadByte( u16, u8, u8 * );
+
+
+static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
+	TLan_HandleInvalid,
+	TLan_HandleTxEOF,
+	TLan_HandleStatOverflow,
+	TLan_HandleRxEOF,
+	TLan_HandleDummy,
+	TLan_HandleTxEOC,
+	TLan_HandleStatusCheck,
+	TLan_HandleRxEOC
+};
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Primary Functions
+
+	These functions are more or less common to all Linux network drivers.
+
+******************************************************************************
+*****************************************************************************/
+
+
+#ifdef MODULE
+
+	/***************************************************************
+	 *	init_module
+	 *
+	 *	Returns:
+	 *		0 if module installed ok, non-zero if not.
+	 *	Parms:
+	 *		None
+	 *
+	 *	This function begins the setup of the driver creating a
+	 *	pad buffer, finding all TLAN devices (matching
+	 *	TLanDeviceList entries), and creating and initializing a
+	 *	device structure for each adapter.
+	 *
+	 **************************************************************/
+
+extern int init_module(void)
+{
+	TLanPrivateInfo	*priv;
+	u8		bus;
+	struct device	*dev;
+	size_t		dev_size;
+	u8		dfn;
+	u32		dl_ix;
+	int		failed;
+	int		found;
+	u32		io_base;
+	u8		irq;
+	u8		rev;
+
+	printk( "TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n",
+		TLanVersionMajor,
+		TLanVersionMinor
+	      );
+	TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE,
+					( GFP_KERNEL | GFP_DMA )
+				      );
+	if ( TLanPadBuffer == NULL ) {
+		printk( "TLAN:  Could not allocate memory for pad buffer.\n" );
+		return -ENOMEM;
+	}
+
+	memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
+
+	dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo);
+
+	while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) ) {
+		dev = (struct device *) kmalloc( dev_size, GFP_KERNEL );
+		if ( dev == NULL ) {
+			printk( "TLAN:  Could not allocate memory for device.\n" );
+			continue;
+		}
+		memset( dev, 0, dev_size );
+
+		dev->priv = priv = ( (void *) dev ) + sizeof(struct device);
+		dev->name = priv->devName;
+		strcpy( priv->devName, "    " );
+		dev->base_addr = io_base;
+		dev->irq = irq;
+		dev->init = TLan_Init;
+
+		priv->pciBus = bus;
+		priv->pciDeviceFn = dfn;
+		priv->pciRevision = rev;
+		priv->pciEntry = dl_ix;
+
+		ether_setup( dev );
+
+		failed = register_netdev( dev );
+
+		if ( failed ) {
+			printk( "TLAN:  Could not register network device.  Freeing struct.\n" );
+			kfree( dev );
+		} else {
+			priv->nextDevice = TLanDevices;
+			TLanDevices = dev;
+			TLanDevicesInstalled++;
+			printk("TLAN:  %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName );
+		}
+	}
+	
+	// printk( "TLAN:  Found %d device(s).\n", TLanDevicesInstalled );
+
+    return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV );
+
+} /* init_module */
+
+
+
+
+	/***************************************************************
+	 *	cleanup_module
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		None
+	 *
+	 *	Goes through the TLanDevices list and frees the device
+	 *	structs and memory associated with each device (lists
+	 *	and buffers).  It also ureserves the IO port regions
+	 *	associated with this device.
+	 *
+	 **************************************************************/
+
+extern void cleanup_module(void)
+{
+	struct device	*dev;
+	TLanPrivateInfo	*priv;
+
+	while (TLanDevicesInstalled) {
+		dev = TLanDevices;
+		priv = (TLanPrivateInfo *) dev->priv;
+		if ( priv->dmaStorage )
+			kfree( priv->dmaStorage );
+		release_region( dev->base_addr, 0x10 );
+		unregister_netdev( dev );
+		TLanDevices = priv->nextDevice;
+		kfree( dev );
+		TLanDevicesInstalled--;
+	}
+	kfree( TLanPadBuffer );
+
+} /* cleanup_module */
+
+
+#else /* MODULE */
+
+
+
+
+	/***************************************************************
+	 *	tlan_probe
+	 *
+	 *	Returns:
+	 *		0 on success, error code on error
+	 *	Parms:
+	 *		dev	device struct to use if adapter is
+	 *			found.
+	 *
+	 *	The name is lower case to fit in with all the rest of
+	 *	the netcard_probe names.  This function looks for a/
+	 *	another TLan based adapter, setting it up with the
+	 *	provided device struct if one is found.
+	 *
+	 **************************************************************/
+	 
+extern int tlan_probe( struct device *dev )
+{
+	static int	pad_allocated = 0;
+	int		found;
+	TLanPrivateInfo	*priv;
+	u8		bus, dfn, irq, rev;
+	u32		io_base, dl_ix;
+
+	found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix );
+	if ( found ) {
+		dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
+		if ( dev->priv == NULL ) {
+			printk( "TLAN:  Could not allocate memory for device.\n" );
+		}
+		memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
+		priv = (TLanPrivateInfo *) dev->priv;
+
+		dev->name = priv->devName;
+		strcpy( priv->devName, "    " );
+
+		dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
+
+		dev->base_addr = io_base;
+		dev->irq = irq;
+
+		priv->pciBus = bus;
+		priv->pciDeviceFn = dfn;
+		priv->pciRevision = rev;
+		priv->pciEntry = dl_ix;
+
+		if ( ! pad_allocated ) {
+			TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA );
+			if ( TLanPadBuffer == NULL ) {
+				printk( "TLAN:  Could not allocate memory for pad buffer.\n" );
+			} else {
+				pad_allocated = 1;
+				memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
+			}
+		}
+		printk("TLAN %d.%d:  %s irq=%2d io=%04x, %s\n",TLanVersionMajor,
+			TLanVersionMinor,
+			dev->name, 
+			(int) irq, 
+			io_base, 
+			TLanDeviceList[dl_ix].deviceName );
+		TLan_Init( dev );
+	}
+			
+   	return ( ( found ) ? 0 : -ENODEV );
+
+} /* tlan_probe */
+
+
+#endif /* MODULE */
+
+
+
+
+	/***************************************************************
+	 *	TLan_PciProbe
+	 *
+	 *	Returns:
+	 *		1 if another TLAN card was found, 0 if not.
+	 *	Parms:
+	 *		pci_bus		The PCI bus the card was found
+	 *				on.
+	 *		pci_dfn		The PCI whatever the card was
+	 *				found at.
+	 *		pci_irq		The IRQ of the found adapter.
+	 *		pci_rev		The revision of the adapter.
+	 *		pci_io_base	The first IO port used by the
+	 *				adapter.
+	 *		dl_ix		The index in the device list
+	 *				of the adapter.
+	 *
+	 *	This function searches for an adapter with PCI vendor
+	 *	and device IDs matching those in the TLanDeviceList.
+	 *	The function 'remembers' the last device it found,
+	 *	and so finds a new device (if anymore are to be found)
+	 *	each time the function is called.  It then looks up
+	 *	pertinent PCI info and returns it to the caller.
+	 *
+	 **************************************************************/
+
+int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
+{
+	static int dl_index = 0;
+	static int pci_index = 0;
+
+	int	not_found;
+	u8	pci_latency;
+	u16	pci_command;
+	int	reg;
+
+
+	if ( ! pcibios_present() ) {
+		printk( "TLAN:   PCI Bios not present.\n" );
+		return 0;
+	}
+
+	for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) {
+
+		not_found = pcibios_find_device(
+			TLanDeviceList[dl_index].vendorId,
+			TLanDeviceList[dl_index].deviceId,
+			pci_index,
+			pci_bus,
+			pci_dfn
+		);
+
+		if ( ! not_found ) {
+
+			TLAN_DBG(
+				TLAN_DEBUG_GNRL,
+				"TLAN:  found: Vendor Id = 0x%hx, Device Id = 0x%hx\n",
+				TLanDeviceList[dl_index].vendorId,
+				TLanDeviceList[dl_index].deviceId
+			);
+
+			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_REVISION_ID, pci_rev);
+			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_INTERRUPT_LINE, pci_irq);
+			pcibios_read_config_word ( *pci_bus,  *pci_dfn, PCI_COMMAND, &pci_command);
+			pcibios_read_config_dword( *pci_bus,  *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base);
+			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_LATENCY_TIMER, &pci_latency);
+
+			if (pci_latency < 0x10) {
+				pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff);
+				TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Setting latency timer to max.\n");
+			}
+
+			for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) {
+				pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base);
+				if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) {
+					*pci_io_base &= PCI_BASE_ADDRESS_IO_MASK;
+					TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    IO mapping is available at %x.\n", *pci_io_base);
+					break;
+				} else {
+					*pci_io_base = 0;
+				}
+			}
+
+			if ( *pci_io_base == 0 )
+				printk("TLAN:    IO mapping not available, ignoring device.\n");
+
+			if (pci_command & PCI_COMMAND_MASTER) {
+				TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Bus mastering is active.\n");
+			}
+
+			pci_index++;
+
+			if ( *pci_io_base ) {
+				*dl_ix = dl_index;
+				return 1;
+			}
+
+		} else {
+			pci_index = 0;
+		}
+	}
+
+	return 0;
+
+} /* TLan_PciProbe */
+
+
+
+
+	/***************************************************************
+	 *	TLan_Init
+	 *
+	 *	Returns:
+	 *		0 on success, error code otherwise.
+	 *	Parms:
+	 *		dev	The structure of the device to be
+	 *			init'ed.
+	 *
+	 *	This function completes the initialization of the
+	 *	device structure and driver.  It reserves the IO
+	 *	addresses, allocates memory for the lists and bounce
+	 *	buffers, retrieves the MAC address from the eeprom
+	 *	and assignes the device's methods.
+	 *	
+	 **************************************************************/
+
+int TLan_Init( struct device *dev )
+{
+	int				dma_size;
+	int				err;
+	int				i;
+	TLanPrivateInfo	*priv;
+
+	priv = (TLanPrivateInfo *) dev->priv;
+
+	err = check_region( dev->base_addr, 0x10 );
+	if ( err ) {
+		printk( "TLAN:  %s: Io port region 0x%lx size 0x%x in use.\n",
+			dev->name,
+			dev->base_addr,
+			0x10 );
+		return -EIO;
+	}
+	request_region( dev->base_addr, 0x10, TLanSignature );
+
+	dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+	           * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
+	priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA );
+	if ( priv->dmaStorage == NULL ) {
+		printk( "TLAN:  Could not allocate lists and buffers for %s.\n",
+			dev->name );
+		return -ENOMEM;
+	}
+	memset( priv->dmaStorage, 0, dma_size );
+	priv->rxList = (TLanList *) 
+		       ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
+	priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
+	priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
+	priv->txBuffer = priv->rxBuffer
+			 + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+
+	err = 0;
+	for ( i = 0;  i < 6 ; i++ )
+		err |= TLan_EeReadByte( dev->base_addr,
+					(u8) 0x83 + i,
+					(u8 *) &dev->dev_addr[i] );
+	if ( err )
+		printk( "TLAN:  %s: Error reading MAC from eeprom: %d\n",
+			dev->name,
+			err );
+	dev->addr_len = 6;
+
+	dev->open = &TLan_Open;
+	dev->hard_start_xmit = &TLan_StartTx;
+	dev->stop = &TLan_Close;
+	dev->get_stats = &TLan_GetStats;
+	dev->set_multicast_list = &TLan_SetMulticastList;
+
+#ifndef MODULE
+
+	aui = dev->mem_start & 0x01;
+	debug = dev->mem_end;
+
+#endif /* MODULE */
+
+	return 0;
+
+} /* TLan_Init */
+
+
+
+
+	/***************************************************************
+	 *	TLan_Open
+	 *
+	 *	Returns:
+	 *		0 on success, error code otherwise.
+	 *	Parms:
+	 *		dev	Structure of device to be opened.
+	 *
+	 *	This routine puts the driver and TLAN adapter in a
+	 *	state where it is ready to send and receive packets.
+	 *	It allocates the IRQ, resets and brings the adapter
+	 *	out of reset, and allows interrupts.  It also delays
+	 *	the startup for autonegotiation or sends a Rx GO
+	 *	command to the adapter, as appropriate.
+	 *
+	 **************************************************************/
+
+int TLan_Open( struct device *dev )
+{
+	int				err;
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+
+	priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
+	err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
+	if ( err ) {
+		printk( "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
+		return -EAGAIN;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* NOTE: It might not be necessary to read the stats before a
+			 reset if you don't care what the values are.
+	*/
+	TLan_ResetLists( dev );
+	TLan_ReadAndClearStats( dev, TLAN_IGNORE );
+	TLan_Reset( dev );
+	TLan_Reset( dev );
+	TLan_SetMac( dev, 0, dev->dev_addr );
+	outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+	if ( debug >= 1 )
+		outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+
+	init_timer( &priv->timer );
+	priv->timer.data = (unsigned long) dev;
+	priv->timer.function = &TLan_Timer;
+	if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
+		priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
+		priv->timerSetAt = jiffies;
+		priv->timerType = TLAN_TIMER_LINK;
+		add_timer( &priv->timer );
+	} else {
+		outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+		outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+	}
+
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Device %s opened.  Revision = %x\n", dev->name, priv->tlanRev );
+
+	return 0;
+
+} /* TLan_Open */
+
+
+
+
+	/***************************************************************
+	 *	TLan_StartTx
+	 *  
+	 *	Returns:
+	 *		0 on success, non-zero on failure.
+	 *	Parms:
+	 *		skb	A pointer to the sk_buff containing the
+	 *			frame to be sent.
+	 *		dev	The device to send the data on.
+	 *
+	 *	This function adds a frame to the Tx list to be sent
+	 *	ASAP.  First it	verifies that the adapter is ready and
+	 *	there is room in the queue.  Then it sets up the next
+	 *	available list, copies the frame to the	corresponding
+	 *	buffer.  If the adapter Tx channel is idle, it gives
+	 *	the adapter a Tx Go command on the list, otherwise it
+	 *	sets the forward address of the previous list to point
+	 *	to this one.  Then it frees the sk_buff.
+	 *
+	 **************************************************************/
+
+int TLan_StartTx( struct sk_buff *skb, struct device *dev )
+{
+	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+	TLanList		*tail_list;
+	u8				*tail_buffer;
+	int				pad;
+
+	if ( ! priv->phyOnline ) {
+		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s PHY is not ready\n", dev->name );
+		dev_kfree_skb( skb, FREE_WRITE );
+		return 0;
+	}
+
+	tail_list = priv->txList + priv->txTail;
+	if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
+		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
+		dev->tbusy = 1;
+		priv->txBusyCount++;
+		return 1;
+	}
+	tail_list->forward = 0;
+	tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
+	memcpy( tail_buffer, skb->data, skb->len );
+	pad = TLAN_MIN_FRAME_SIZE - skb->len;
+	if ( pad > 0 ) {
+		tail_list->frameSize = (u16) skb->len + pad;
+		tail_list->buffer[0].count = (u32) skb->len;
+		tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad;
+		tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer );
+	} else {
+		tail_list->frameSize = (u16) skb->len;
+		tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len;
+		tail_list->buffer[1].count = 0;
+		tail_list->buffer[1].address = 0;
+	}
+	// are we transferring?
+	cli();
+	tail_list->cStat = TLAN_CSTAT_READY;
+	if ( ! priv->txInProgress ) {
+		priv->txInProgress = 1;
+		outw( 0x4, dev->base_addr + TLAN_HOST_INT );
+		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Starting TX on buffer %d\n", priv->txTail );
+		outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM );
+		outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );
+	} else {
+		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Adding buffer %d to TX channel\n", priv->txTail );
+		if ( priv->txTail == 0 )
+			( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list );
+		else
+			( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list );
+	}
+	sti();
+	priv->txTail++;
+	if ( priv->txTail >= TLAN_NUM_TX_LISTS )
+		priv->txTail = 0;
+
+	dev_kfree_skb( skb, FREE_WRITE );
+		
+	dev->trans_start = jiffies;
+	return 0;
+
+} /* TLan_StartTx */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleInterrupt
+	 *  
+	 *	Returns:	
+	 *		Nothing
+	 *	Parms:
+	 *		irq	The line on which the interrupt
+	 *			occurred.
+	 *		dev_id	A pointer to the device assigned to
+	 *			this irq line.
+	 *		regs	???
+	 *
+	 *	This function handles an interrupt generated by its
+	 *	assigned TLAN adapter.  The function deactivates
+	 *	interrupts on its adapter, records the type of
+	 *	interrupt, executes the appropriate subhandler, and
+	 *	acknowdges the interrupt to the adapter (thus
+	 *	re-enabling adapter interrupts.
+	 *
+	 **************************************************************/
+
+void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32				ack;
+	struct device	*dev;
+	u32				host_cmd;
+	u16				host_int;
+	int				type;
+
+	dev = (struct device *) dev_id;
+
+	if ( dev->interrupt )
+		printk( "TLAN:   Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt );
+	dev->interrupt++;
+
+	cli();
+
+	host_int = inw( dev->base_addr + TLAN_HOST_INT );
+	outw( host_int, dev->base_addr + TLAN_HOST_INT ); // Deactivate Ints
+
+	type = ( host_int & TLAN_HI_IT_MASK ) >> 2;
+
+	ack = TLanIntVector[type]( dev, host_int );
+
+	sti();
+
+	if ( ack ) {
+		host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
+		outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
+	}
+
+	dev->interrupt--;
+
+} /* TLan_HandleInterrupts */
+
+
+
+
+	/***************************************************************
+	 *	TLan_Close
+	 *  
+	 * 	Returns:
+	 *		An error code.
+	 *	Parms:
+	 *		dev	The device structure of the device to
+	 *			close.
+	 *
+	 *	This function shuts down the adapter.  It records any
+	 *	stats, puts the adapter into reset state, deactivates
+	 *	its time as needed, and	frees the irq it is using.
+	 *
+	 **************************************************************/
+
+int TLan_Close(struct device *dev)
+{
+	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	TLan_ReadAndClearStats( dev, TLAN_RECORD );
+	outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
+	if ( priv->timerSetAt != 0 )
+		del_timer( &priv->timer );
+	free_irq( dev->irq, dev );
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:   Device %s closed.\n", dev->name );
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+
+} /* TLan_Close */
+
+
+
+
+	/***************************************************************
+	 *	TLan_GetStats
+	 *  
+	 *	Returns:
+	 *		A pointer to the device's statistics structure.
+	 *	Parms:
+	 *		dev	The device structure to return the
+	 *			stats for.
+	 *
+	 *	This function updates the devices statistics by reading
+	 *	the TLAN chip's onboard registers.  Then it returns the
+	 *	address of the statistics structure.
+	 *
+	 **************************************************************/
+
+struct net_device_stats *TLan_GetStats( struct device *dev )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	int i;
+
+	/* Should only read stats if open ? */
+	TLan_ReadAndClearStats( dev, TLAN_RECORD );
+
+	TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  %s EOC count = %d\n", dev->name, priv->rxEocCount );
+	TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s Busy count = %d\n", dev->name, priv->txBusyCount );
+	if ( debug & TLAN_DEBUG_GNRL ) {
+		TLan_PrintDio( dev->base_addr );
+		TLan_PhyPrint( dev );
+	}
+	if ( debug & TLAN_DEBUG_LIST ) {
+		for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ )
+			TLan_PrintList( priv->rxList + i, "RX", i );
+		for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ )
+			TLan_PrintList( priv->txList + i, "TX", i );
+	}
+	
+	return ( &( (TLanPrivateInfo *) dev->priv )->stats );
+
+} /* TLan_GetStats */
+
+
+
+
+	/***************************************************************
+	 *	TLan_SetMulticastList
+	 *  
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	The device structure to set the
+	 *			multicast list for.
+	 *
+	 *	This function sets the TLAN adaptor to various receive
+	 *	modes.  If the IFF_PROMISC flag is set, promiscuous
+	 *	mode is acitviated.  Otherwise,	promiscuous mode is
+	 *	turned off.  If the IFF_ALLMULTI flag is set, then
+	 *	the hash table is set to receive all group addresses.
+	 *	Otherwise, the first three multicast addresses are
+	 *	stored in AREG_1-3, and the rest are selected via the
+	 *	hash table, as necessary.
+	 *
+	 **************************************************************/
+
+void TLan_SetMulticastList( struct device *dev )
+{	
+	struct dev_mc_list	*dmi = dev->mc_list;
+	u32					hash1 = 0;
+	u32					hash2 = 0;
+	int					i;
+	u32					offset;
+	u8					tmp;
+
+	if ( dev->flags & IFF_PROMISC ) {
+		tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
+		TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF );
+	} else {
+		tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
+		TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
+		if ( dev->flags & IFF_ALLMULTI ) {
+			for ( i = 0; i < 3; i++ ) 
+				TLan_SetMac( dev, i + 1, NULL );
+			TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF );
+			TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );
+		} else {
+			for ( i = 0; i < dev->mc_count; i++ ) {
+				if ( i < 3 ) {
+					TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr );
+				} else {
+					offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );
+					if ( offset < 32 ) 
+						hash1 |= ( 1 << offset );
+					else
+						hash2 |= ( 1 << ( offset - 32 ) );
+				}
+				dmi = dmi->next;
+			}
+			for ( ; i < 3; i++ ) 
+				TLan_SetMac( dev, i + 1, NULL );
+			TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 );
+			TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 );
+		}
+	}
+
+} /* TLan_SetMulticastList */
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+        ThunderLAN Driver Interrupt Vectors and Table
+
+	Please see Chap. 4, "Interrupt Handling" of the "ThunderLAN
+	Programmer's Guide" for more informations on handling interrupts
+	generated by TLAN based adapters.  
+
+******************************************************************************
+*****************************************************************************/
+
+
+	/***************************************************************
+	 *	TLan_HandleInvalid
+	 *
+	 *	Returns:
+	 *		0
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This function handles invalid interrupts.  This should
+	 *	never happen unless some other adapter is trying to use
+	 *	the IRQ line assigned to the device.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleInvalid( struct device *dev, u16 host_int )
+{
+	host_int = 0;
+	// printk( "TLAN:  Invalid interrupt on %s.\n", dev->name );
+	return 0;
+
+} /* TLan_HandleInvalid */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleTxEOF
+	 *
+	 *	Returns:
+	 *		1
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This function handles Tx EOF interrupts which are raised
+	 *	by the adapter when it has completed sending the
+	 *	contents of a buffer.  If detemines which list/buffer
+	 *	was completed and resets it.  If the buffer was the last
+	 *	in the channel (EOC), then the function checks to see if
+	 *	another buffer is ready to send, and if so, sends a Tx
+	 *	Go command.  Finally, the driver activates/continues the
+	 *	activity LED.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	int				eoc = 0;
+	TLanList		*head_list;
+	u32				ack = 1;
+
+	TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+	host_int = 0;
+	head_list = priv->txList + priv->txHead;
+	if ( head_list->cStat & TLAN_CSTAT_EOC )
+		eoc = 1;
+	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
+		printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );
+	}
+	// printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat );
+
+#if LINUX_KERNEL_VERSION > 0x20100
+	priv->stats->tx_bytes += head_list->frameSize;
+#endif
+
+	head_list->cStat = TLAN_CSTAT_UNUSED;
+	dev->tbusy = 0;
+	priv->txHead++;
+	if ( priv->txHead >= TLAN_NUM_TX_LISTS )
+		priv->txHead = 0;
+	if ( eoc ) {
+		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+		head_list = priv->txList + priv->txHead;
+		if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
+			outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+			ack |= TLAN_HC_GO;
+		} else {
+			priv->txInProgress = 0;
+		}
+	}
+	TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+	if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
+		if ( priv->timerSetAt == 0 ) {
+			// printk("TxEOF Starting timer...\n");
+			priv->timerSetAt = jiffies;
+			priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+			priv->timerType = TLAN_TIMER_ACT;
+			add_timer( &priv->timer );
+		} else if ( priv->timerType == TLAN_TIMER_ACT ) {
+			priv->timerSetAt = jiffies;
+			// printk("TxEOF continuing timer...\n");
+		}
+	}
+
+	return ack;
+
+} /* TLan_HandleTxEOF */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleStatOverflow
+	 *
+	 *	Returns:
+	 *		1
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This function handles the Statistics Overflow interrupt
+	 *	which means that one or more of the TLAN statistics
+	 *	registers has reached 1/2 capacity and needs to be read.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleStatOverflow( struct device *dev, u16 host_int )
+{
+	host_int = 0;
+	TLan_ReadAndClearStats( dev, TLAN_RECORD );
+
+	return 1;
+
+} /* TLan_HandleStatOverflow */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleRxEOF
+	 *
+	 *	Returns:
+	 *		1
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This function handles the Rx EOF interrupt which
+	 *	indicates a frame has been received by the adapter from
+	 *	the net and the frame has been transferred to memory.
+	 *	The function determines the bounce buffer the frame has
+	 *	been loaded into, creates a new sk_buff big enough to
+	 *	hold the frame, and sends it to protocol stack.  It
+	 *	then resets the used buffer and appends it to the end
+	 *	of the list.  If the frame was the last in the Rx
+	 *	channel (EOC), the function restarts the receive channel
+	 *	by sending an Rx Go command to the adapter.  Then it
+	 *	activates/continues the activity LED.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u32		ack = 1;
+	int		eoc = 0;
+	u8		*head_buffer;
+	TLanList	*head_list;
+	struct sk_buff	*skb;
+	TLanList	*tail_list;
+	void		*t;
+
+	TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+	host_int = 0;
+	head_list = priv->rxList + priv->rxHead;
+	tail_list = priv->rxList + priv->rxTail;
+	if ( head_list->cStat & TLAN_CSTAT_EOC )
+		eoc = 1;
+	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
+		printk( "TLAN:  Received interrupt for uncompleted RX frame.\n" );
+	} else {
+		skb = dev_alloc_skb( head_list->frameSize + 7 );
+		if ( skb == NULL ) { 
+			printk( "TLAN:  Couldn't allocate memory for received data.\n" );
+		} else {
+			head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE );
+			skb->dev = dev;
+			skb_reserve( skb, 2 );
+			t = (void *) skb_put( skb, head_list->frameSize );
+			// printk( " %hd %p %p\n", head_list->frameSize, skb->data, t );
+
+#if LINUX_KERNEL_VERSION > 0x20100
+			priv->stats->rx_bytes += head_list->frameSize;
+#endif
+
+			memcpy( t, head_buffer, head_list->frameSize );
+			skb->protocol = eth_type_trans( skb, dev );
+			netif_rx( skb );
+		}
+	}
+	head_list->forward = 0;
+	head_list->frameSize = TLAN_MAX_FRAME_SIZE;
+	head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
+	tail_list->forward = virt_to_bus( head_list );
+	priv->rxHead++;
+	if ( priv->rxHead >= TLAN_NUM_RX_LISTS )
+		priv->rxHead = 0;
+	priv->rxTail++;
+	if ( priv->rxTail >= TLAN_NUM_RX_LISTS )
+		priv->rxTail = 0;
+	if ( eoc ) { 
+		TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+		head_list = priv->rxList + priv->rxHead;
+		outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+		ack |= TLAN_HC_GO | TLAN_HC_RT;
+		priv->rxEocCount++;
+	}
+	TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+	if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
+		if ( priv->timerSetAt == 0 )  {
+			// printk("RxEOF Starting timer...\n");
+			priv->timerSetAt = jiffies;
+			priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+			priv->timerType = TLAN_TIMER_ACT;
+			add_timer( &priv->timer );
+		} else if ( priv->timerType == TLAN_TIMER_ACT ) {
+			// printk("RxEOF tarting continuing timer...\n");
+			priv->timerSetAt = jiffies;
+		}
+	}
+	dev->last_rx = jiffies;
+
+	return ack;
+
+} /* TLan_HandleRxEOF */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleDummy
+	 *
+	 *	Returns:
+	 *		1
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This function handles the Dummy interrupt, which is
+	 *	raised whenever a test interrupt is generated by setting
+	 *	the Req_Int bit of HOST_CMD to 1.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleDummy( struct device *dev, u16 host_int )
+{
+	host_int = 0;
+	printk( "TLAN:  Dummy interrupt on %s.\n", dev->name );
+	return 1;
+
+} /* TLan_HandleDummy */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleTxEOC
+	 *
+	 *	Returns:
+	 *		1
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This driver is structured to determine EOC occurances by
+	 *	reading the CSTAT member of the list structure.  Tx EOC
+	 *	interrupts are disabled via the DIO INTDIS register.
+	 *	However, TLAN chips before revision 3.0 didn't have this
+	 *	functionality, so process EOC events if this is the
+	 *	case.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleTxEOC( struct device *dev, u16 host_int )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	TLanList		*head_list;
+	u32				ack = 1;
+
+	host_int = 0;
+	if ( priv->tlanRev < 0x30 ) {
+		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );
+		head_list = priv->txList + priv->txHead;
+		if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
+			outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+			ack |= TLAN_HC_GO;
+		} else {
+			priv->txInProgress = 0;
+		}
+	}
+
+	return ack;
+
+} /* TLan_HandleTxEOC */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleStatusCheck
+	 *
+	 *	Returns:
+	 *		0 if Adapter check, 1 if Network Status check.
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This function handles Adapter Check/Network Status
+	 *	interrupts generated by the adapter.  It checks the
+	 *	vector in the HOST_INT register to determine if it is
+	 *	an Adapter Check interrupt.  If so, it resets the
+	 *	adapter.  Otherwise it clears the status registers
+	 *	and services the PHY.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int )
+{	
+	u32				ack;
+	u32				error;
+	u8				net_sts;
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	
+	ack = 1;
+	if ( host_int & TLAN_HI_IV_MASK ) {
+		error = inl( dev->base_addr + TLAN_CH_PARM );
+		printk( "TLAN:   Adaptor Check on device %s err = 0x%x\n", dev->name, error );
+		TLan_ReadAndClearStats( dev, TLAN_RECORD );
+		outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
+		TLan_ResetLists( dev );
+		TLan_Reset( dev );
+		dev->tbusy = 0;
+		TLan_SetMac( dev, 0, dev->dev_addr );
+		if ( priv->timerType == 0 ) {
+			if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
+				priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
+				priv->timerSetAt = jiffies;
+				priv->timerType = TLAN_TIMER_LINK;
+				add_timer( &priv->timer );
+			} else {
+				//printk( " RX GO---->\n" );
+				outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+				outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+			}
+		}
+		ack = 0;
+	} else {
+		net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
+		if ( net_sts )
+			TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
+		if ( net_sts & TLAN_NET_STS_MIRQ ) {
+			(*priv->phyService)( dev );
+			if (debug) {
+				TLan_PhyPrint( dev );
+			}
+		}
+		TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts );
+	}
+
+	return ack;
+
+} /* TLan_HandleStatusCheck */
+
+
+
+
+	/***************************************************************
+	 *	TLan_HandleRxEOC
+	 *
+	 *	Returns:
+	 *		1
+	 *	Parms:
+	 *		dev		Device assigned the IRQ that was
+	 *				raised.
+	 *		host_int	The contents of the HOST_INT
+	 *				port.
+	 *
+	 *	This driver is structured to determine EOC occurances by
+	 *	reading the CSTAT member of the list structure.  Rx EOC
+	 *	interrupts are disabled via the DIO INTDIS register.
+	 *	However, TLAN chips before revision 3.0 didn't have this
+	 *	CSTAT member or a INTDIS register, so if this chip is
+	 *	pre-3.0, process EOC interrupts normally.
+	 *
+	 **************************************************************/
+
+u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	TLanList		*head_list;
+	u32				ack = 1;
+
+	host_int = 0;
+	if (  priv->tlanRev < 0x30 ) {
+		TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail );
+		head_list = priv->rxList + priv->rxHead;
+		outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+		ack |= TLAN_HC_GO | TLAN_HC_RT;
+		priv->rxEocCount++;
+	}
+
+	return ack;
+
+} /* TLan_HandleRxEOC */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Timer Function
+
+******************************************************************************
+*****************************************************************************/
+
+
+	/***************************************************************
+	 *	TLan_Timer
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		data	A value given to add timer when
+	 *			add_timer was called.
+	 *
+	 *	This function handles timed functionality for the
+	 *	TLAN driver.  The two current timer uses are for
+	 *	delaying for autonegotionation and driving the ACT LED.
+	 *	-	Autonegotiation requires being allowed about
+	 *		2 1/2 seconds before attempting to transmit a
+	 *		packet.  It would be a very bad thing to hang
+	 *		the kernel this long, so the driver doesn't
+	 *		allow transmission 'til after this time, for
+	 *		certain PHYs.  It would be much nicer if all
+	 *		PHYs were interrupt-capable like the internal
+	 *		PHY.
+	 *	-	The ACT LED, which shows adapter activity, is
+	 *		driven by the driver, and so must be left on
+	 *		for a short period to power up the LED so it
+	 *		can be seen.  This delay can be changed by
+	 *		changing the TLAN_TIMER_ACT_DELAY in tlan.h,
+	 *		if desired.  10 jiffies produces a slightly
+	 *		sluggish response.
+	 *
+	 **************************************************************/
+
+void TLan_Timer( unsigned long data )
+{
+	struct device	*dev = (struct device *) data;
+	u16		gen_sts;
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+
+	// printk( "TLAN:  %s Entered Timer, type = %d\n", dev->name, priv->timerType );
+
+	switch ( priv->timerType ) {
+		case TLAN_TIMER_LINK:
+			TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts );
+			if ( gen_sts & MII_GS_LINK ) {
+				priv->phyOnline = 1;
+				outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+				outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+				priv->timerSetAt = 0;
+				priv->timerType = 0;
+			} else {
+				priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 );
+				add_timer( &priv->timer );
+			}
+			break;
+		case TLAN_TIMER_ACT:
+			if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) {
+				TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+				priv->timerSetAt = 0;
+				priv->timerType = 0;
+			} else {
+				priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
+				add_timer( &priv->timer );
+			}
+			break;
+		default:
+			break;
+	}
+
+} /* TLan_Timer */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Adapter Related Routines
+
+******************************************************************************
+*****************************************************************************/
+
+
+	/***************************************************************
+	 *	TLan_ResetLists
+	 *  
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	The device structure with the list
+	 *			stuctures to be reset.
+	 *
+	 *	This routine sets the variables associated with managing
+	 *	the TLAN lists to their initial values.
+	 *
+	 **************************************************************/
+
+void TLan_ResetLists( struct device *dev )
+{
+	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+	int		i;
+	TLanList	*list;
+
+	priv->txHead = 0;
+	priv->txTail = 0;
+	for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
+		list = priv->txList + i;
+		list->cStat = TLAN_CSTAT_UNUSED;
+		list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+		list->buffer[2].count = 0;
+		list->buffer[2].address = 0;
+	}
+
+	priv->rxHead = 0;
+	priv->rxTail = TLAN_NUM_RX_LISTS - 1;
+	for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
+		list = priv->rxList + i;
+		list->cStat = TLAN_CSTAT_READY;
+		list->frameSize = TLAN_MAX_FRAME_SIZE;
+		list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
+		list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+		list->buffer[1].count = 0;
+		list->buffer[1].address = 0;
+		if ( i < TLAN_NUM_RX_LISTS - 1 )
+			list->forward = virt_to_bus( list + 1 );
+		else
+			list->forward = 0;
+	}
+
+} /* TLan_ResetLists */
+
+
+
+
+	/***************************************************************
+	 *	TLan_PrintDio
+	 *  
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		io_base		Base IO port of the device of
+	 *				which to print DIO registers.
+	 *
+	 *	This function prints out all the internal (DIO)
+	 *	registers of a TLAN chip.
+	 *
+	 **************************************************************/
+
+void TLan_PrintDio( u16 io_base )
+{
+	u32 data0, data1;
+	int	i;
+
+	printk( "TLAN:   Contents of internal registers for io base 0x%04hx.\n", io_base );
+	printk( "TLAN:      Off.  +0         +4\n" );
+	for ( i = 0; i < 0x4C; i+= 8 ) {
+		data0 = TLan_DioRead32( io_base, i );
+		data1 = TLan_DioRead32( io_base, i + 0x4 );
+		printk( "TLAN:      0x%02x  0x%08x 0x%08x\n", i, data0, data1 );
+	}
+
+} /* TLan_PrintDio */
+
+
+
+
+	/***************************************************************
+	 *	TLan_PrintList
+	 *  
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		list	A pointer to the TLanList structure to
+	 *			be printed.
+	 *		type	A string to designate type of list,
+	 *			"Rx" or "Tx".
+	 *		num	The index of the list.
+	 *
+	 *	This function prints out the contents of the list
+	 *	pointed to by the list parameter.
+	 *
+	 **************************************************************/
+
+void TLan_PrintList( TLanList *list, char *type, int num)
+{
+	int i;
+
+	printk( "TLAN:   %s List %d at 0x%08x\n", type, num, (u32) list );
+	printk( "TLAN:      Forward    = 0x%08x\n",  list->forward );
+	printk( "TLAN:      CSTAT      = 0x%04hx\n", list->cStat );
+	printk( "TLAN:      Frame Size = 0x%04hx\n", list->frameSize );
+	// for ( i = 0; i < 10; i++ ) {
+	for ( i = 0; i < 2; i++ ) {
+		printk( "TLAN:      Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address );
+	}
+
+} /* TLan_PrintList */
+
+
+
+
+	/***************************************************************
+	 *	TLan_ReadAndClearStats
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	Pointer to device structure of adapter
+	 *			to which to read stats.
+	 *		record	Flag indicating whether to add 
+	 *
+	 *	This functions reads all the internal status registers
+	 *	of the TLAN chip, which clears them as a side effect.
+	 *	It then either adds the values to the device's status
+	 *	struct, or discards them, depending on whether record
+	 *	is TLAN_RECORD (!=0)  or TLAN_IGNORE (==0).
+	 *
+	 **************************************************************/
+
+void TLan_ReadAndClearStats( struct device *dev, int record )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u32				tx_good, tx_under;
+	u32				rx_good, rx_over;
+	u32				def_tx, crc, code;
+	u32				multi_col, single_col;
+	u32				excess_col, late_col, loss;
+
+	outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR );
+	tx_good  = inb( dev->base_addr + TLAN_DIO_DATA );
+	tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+	tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;
+	tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+
+	outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR );
+	rx_good  = inb( dev->base_addr + TLAN_DIO_DATA );
+	rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+	rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;
+	rx_over  = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+		
+	outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR );
+	def_tx  = inb( dev->base_addr + TLAN_DIO_DATA );
+	def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+	crc     = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
+	code    = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+	
+	outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR );
+	multi_col   = inb( dev->base_addr + TLAN_DIO_DATA );
+	multi_col  += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+	single_col  = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
+	single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8;
+
+	outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR );
+	excess_col = inb( dev->base_addr + TLAN_DIO_DATA );
+	late_col   = inb( dev->base_addr + TLAN_DIO_DATA + 1 );
+	loss       = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
+
+	if ( record ) {
+		priv->stats.rx_packets += rx_good;
+		priv->stats.rx_errors  += rx_over + crc + code;
+		priv->stats.tx_packets += tx_good;
+		priv->stats.tx_errors  += tx_under + loss;
+		priv->stats.collisions += multi_col + single_col + excess_col + late_col;
+
+		priv->stats.rx_over_errors    += rx_over;
+		priv->stats.rx_crc_errors     += crc;
+		priv->stats.rx_frame_errors   += code;
+
+		priv->stats.tx_aborted_errors += tx_under;
+		priv->stats.tx_carrier_errors += loss;
+	}
+			
+} /* TLan_ReadAndClearStats */
+
+
+
+
+	/***************************************************************
+	 *	TLan_Reset
+	 *
+	 *	Returns:
+	 *		0
+	 *	Parms:
+	 *		dev	Pointer to device structure of adapter
+	 *			to be reset.
+	 *
+	 *	This function resets the adapter and it's physical
+	 *	device.  See Chap. 3, pp. 9-10 of the "ThunderLAN
+	 *	Programmer's Guide" for details.  The routine tries to
+	 *	implement what is detailed there, though adjustments
+	 *	have been made.
+	 *
+	 **************************************************************/
+
+int TLan_Reset( struct device *dev )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	int		i;
+	u32		addr;
+	u32		data;
+	u8		data8;
+
+//  1.	Assert reset bit.
+
+	data = inl(dev->base_addr + TLAN_HOST_CMD);
+	data |= TLAN_HC_AD_RST;
+	outl(data, dev->base_addr + TLAN_HOST_CMD);
+
+//  2.	Turn off interrupts. ( Probably isn't necessary )
+
+	data = inl(dev->base_addr + TLAN_HOST_CMD);
+	data |= TLAN_HC_INT_OFF;
+	outl(data, dev->base_addr + TLAN_HOST_CMD);
+
+//  3.	Clear AREGs and HASHs.
+
+ 	for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) {
+		TLan_DioWrite32( dev->base_addr, (u16) i, 0 );
+	}
+
+//  4.	Setup NetConfig register.
+
+	data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
+	TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data );
+
+//  5.	Load Ld_Tmr and Ld_Thr in HOST_CMD.
+
+ 	outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD );
+ 	outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD );
+
+//  6.	Unreset the MII by setting NMRST (in NetSio) to 1.
+
+	outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR );
+	addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
+	TLan_SetBit( TLAN_NET_SIO_NMRST, addr );
+
+//  7.	Setup the remaining registers.
+
+	if ( priv->tlanRev >= 0x30 ) {
+		data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC;
+		TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 );
+	}
+	TLan_PhySelect( dev );
+	data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
+	if ( priv->phyFlags & TLAN_PHY_BIT_RATE ) {
+		data |= TLAN_NET_CFG_BIT;
+		if ( aui == 1 ) {
+			TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a );
+		} else {
+			TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 );
+		}
+	}
+	if ( priv->phyFlags & TLAN_PHY_INTERNAL ) {
+		data |= TLAN_NET_CFG_PHY_EN;
+	}
+	TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data );
+	(*priv->phyCheck)( dev ); 
+	data8 = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
+	TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data8 );
+	data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; 
+	if ( priv->phyFlags & TLAN_PHY_INTS ) {
+		data8 |= TLAN_NET_MASK_MASK7; 
+	}
+	TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 );
+	TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE );
+
+	if ( priv->phyFlags & TLAN_PHY_UNMANAGED ) {
+		priv->phyOnline = 1;
+	}
+
+	return 0;
+
+} /* TLan_Reset */
+
+
+
+
+	/***************************************************************
+	 *	TLan_SetMac
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	Pointer to device structure of adapter
+	 *			on which to change the AREG.
+	 *		areg	The AREG to set the address in (0 - 3).
+	 *		mac	A pointer to an array of chars.  Each
+	 *			element stores one byte of the address.
+	 *			IE, it isn't in ascii.
+	 *
+	 *	This function transfers a MAC address to one of the
+	 *	TLAN AREGs (address registers).  The TLAN chip locks
+	 *	the register on writing to offset 0 and unlocks the
+	 *	register after writing to offset 5.  If NULL is passed
+	 *	in mac, then the AREG is filled with 0's.
+	 *
+	 **************************************************************/
+
+void TLan_SetMac( struct device *dev, int areg, char *mac )
+{
+	int i;
+			
+	areg *= 6;
+
+	if ( mac != NULL ) {
+		for ( i = 0; i < 6; i++ )
+			TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] );
+	} else {
+		for ( i = 0; i < 6; i++ )
+			TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 );
+	}
+
+} /* TLan_SetMac */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver PHY Layer Routines
+
+	The TLAN chip can drive any number of PHYs (physical devices).  Rather
+	than having lots of 'if' or '#ifdef' statements, I have created a
+	second driver layer for the PHYs.  Each PHY can be identified from its
+	id in registers 2 and 3, and can be given a Check and Service routine
+	that will be called when the adapter is reset and when the adapter
+	receives a Network Status interrupt, respectively.
+	
+******************************************************************************
+*****************************************************************************/
+
+
+static TLanPhyIdEntry	TLanPhyIdTable[] = {
+	  { 0x4000,
+	    0x5014,
+	    &TLan_PhyInternalCheck,
+	    &TLan_PhyInternalService,
+	    TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
+	  { 0x4000,
+	    0x5015,
+	    &TLan_PhyInternalCheck,
+	    &TLan_PhyInternalService,
+	    TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
+	  { 0x4000,
+	    0x5016,
+	    &TLan_PhyInternalCheck,
+	    &TLan_PhyInternalService,
+	    TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
+	  { 0x2000,
+	    0x5C00,
+	    &TLan_PhyDp83840aCheck,
+	    &TLan_PhyNop,
+	    TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
+	  { 0x2000,
+	    0x5C01,
+	    &TLan_PhyDp83840aCheck,
+	    &TLan_PhyNop,
+	    TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
+	  { 0x7810,
+	    0x0000,
+	    &TLan_PhyDp83840aCheck,
+	    &TLan_PhyNop,
+	    TLAN_PHY_AUTONEG },
+	  { 0x0000,
+	    0x0000,
+	    NULL,
+	    NULL,
+	    0
+	  }
+	};
+
+
+	/*********************************************************************
+	 *	TLan_PhyPrint
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	A pointer to the device structure of the adapter
+	 *			which the desired PHY is located.
+	 *				
+	 *	This function prints the registers a PHY.
+	 *
+	 ********************************************************************/
+
+void TLan_PhyPrint( struct device *dev )
+{
+	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+	u16 i, data0, data1, data2, data3, phy;
+	u32 io;
+
+	phy = priv->phyAddr;
+	io = dev->base_addr;
+
+	if ( ( phy > 0 ) && ( phy <= TLAN_PHY_MAX_ADDR ) ) {
+		printk( "TLAN:   Device %s, PHY 0x%02x.\n", dev->name, phy );
+		printk( "TLAN:      Off.  +0     +1     +2     +3 \n" );
+                for ( i = 0; i < 0x20; i+= 4 ) {
+			printk( "TLAN:      0x%02x", i );
+			TLan_MiiReadReg( io, phy, i, &data0 );
+			printk( " 0x%04hx", data0 );
+			TLan_MiiReadReg( io, phy, i + 1, &data1 );
+			printk( " 0x%04hx", data1 );
+			TLan_MiiReadReg( io, phy, i + 2, &data2 );
+			printk( " 0x%04hx", data2 );
+			TLan_MiiReadReg( io, phy, i + 3, &data3 );
+			printk( " 0x%04hx\n", data3 );
+		}
+	} else {
+		printk( "TLAN:   Device %s, PHY 0x%02x (Unmanaged/Unknown).\n",
+			dev->name,
+			phy
+		      );
+	}
+
+} /* TLan_PhyPrint */
+
+
+
+
+	/*********************************************************************
+	 *	TLan_PhySelect
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	A pointer to the device structure of the adapter
+	 *			for which the PHY needs determined.
+	 *
+	 *	This function decides which PHY amoung those attached to the
+	 *	TLAN chip is to be used.  The TLAN chip can be attached to
+	 *	multiple PHYs, and the driver needs to decide which one to
+	 *	talk to.  Currently this routine picks the PHY with the lowest
+	 *	address as the internal PHY address is 0x1F, the highest
+	 *	possible.  This strategy assumes that there can be only one
+	 *	other PHY, and, if it exists, it is the one to be used.  If
+	 *	token ring PHYs are ever supported, this routine will become
+	 *	a little more interesting...
+	 *
+	 ********************************************************************/
+
+void TLan_PhySelect( struct device *dev )
+{
+	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+	int		 	phy;
+	int			entry;
+	u16			id_hi[TLAN_PHY_MAX_ADDR + 1];
+	u16			id_lo[TLAN_PHY_MAX_ADDR + 1];
+	u16			hi;
+	u16			lo;
+	u16			vendor;
+	u16			device;
+
+	priv->phyCheck = &TLan_PhyNop;	// Make sure these aren't ever NULL
+	priv->phyService = &TLan_PhyNop;
+	
+	vendor = TLanDeviceList[priv->pciEntry].vendorId;
+	device = TLanDeviceList[priv->pciEntry].deviceId;
+
+	// This is a bit uglier than I'd like, but the 0xF130 device must
+	// NOT be assigned a valid PHY as it uses an unmanaged, bit-rate
+	// PHY.  It is simplest just to use another goto, rather than
+	// nesting the two for loops in the if statement.
+
+	if ( ( vendor == PCI_VENDOR_ID_COMPAQ ) &&
+	     ( device == PCI_DEVICE_ID_NETFLEX_3P ) ) {
+		entry = 0;
+		phy = 0;
+		goto FINISH;
+	}
+
+	for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
+		hi = lo = 0;
+		TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &hi );
+		TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &lo );
+		id_hi[phy] = hi;
+		id_lo[phy] = lo;
+		TLAN_DBG( TLAN_DEBUG_GNRL,
+			  "TLAN: Phy %2x, hi = %hx, lo = %hx\n",
+			  phy,
+			  hi,
+			  lo
+			);
+	}
+
+	for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
+		if ( ( aui == 1 ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
+			if ( id_hi[phy] != 0xFFFF ) {
+				TLan_MiiSync(dev->base_addr);
+				TLan_MiiWriteReg(dev->base_addr,
+						 phy,
+						 MII_GEN_CTL,
+						 MII_GC_PDOWN | 
+						 MII_GC_LOOPBK | 
+						 MII_GC_ISOLATE );
+
+			}
+			continue;
+		}
+		for ( entry = 0; TLanPhyIdTable[entry].check; entry++) {
+			if ( ( id_hi[phy] == TLanPhyIdTable[entry].idHi ) &&
+			     ( id_lo[phy] == TLanPhyIdTable[entry].idLo ) ) {
+				TLAN_DBG( TLAN_DEBUG_GNRL,
+					  "TLAN: Selected Phy %hx\n",
+					  phy
+					);
+				goto FINISH;
+			}
+		}
+	}
+
+	entry = 0;
+	phy = 0;
+
+FINISH:
+	
+	if ( ( entry == 0 ) && ( phy == 0 ) ) {
+		priv->phyAddr = phy;
+		priv->phyEntry = entry;
+		priv->phyCheck = TLan_PhyNop;
+		priv->phyService = TLan_PhyNop;
+		priv->phyFlags = TLAN_PHY_BIT_RATE | 
+                                 TLAN_PHY_UNMANAGED |
+				 TLAN_PHY_ACTIVITY;
+	} else {
+		priv->phyAddr = phy;
+		priv->phyEntry = entry;
+		priv->phyCheck = TLanPhyIdTable[entry].check;
+		priv->phyService = TLanPhyIdTable[entry].service;
+		priv->phyFlags = TLanPhyIdTable[entry].flags;
+	}
+
+} /* TLan_PhySelect */
+
+
+
+
+	/***************************************************************
+	 *	TLan_PhyNop
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	A pointer to a device structure.
+	 *
+	 *	This function does nothing and is meant as a stand-in
+	 *	for when a Check or Service function would be
+	 *	meaningless.
+	 *
+	 **************************************************************/
+
+int TLan_PhyNop( struct device *dev )
+{
+	dev = NULL;
+	return 0;
+
+} /* TLan_PhyNop */
+
+
+
+
+	/***************************************************************
+	 *  TLan_PhyInternalCheck
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	A pointer to a device structure of the
+	 *			adapter	holding the PHY to be checked.
+	 *
+	 *	This function resets the internal PHY on a TLAN chip.
+	 *	See Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
+	 *	Programmer's Guide"
+	 *
+	 **************************************************************/
+
+int TLan_PhyInternalCheck( struct device *dev )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u16				gen_ctl;
+	u32				io;
+	u16				phy;
+	u16				value;
+	u8				sio;
+
+	io = dev->base_addr;
+	phy = priv->phyAddr;
+
+	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
+	if ( gen_ctl & MII_GC_PDOWN ) {
+		TLan_MiiSync( io );
+		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
+		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
+		udelay(50000);
+		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
+		TLan_MiiSync( io );
+	}
+
+	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+	while ( value & MII_GC_RESET )
+		TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+
+	// TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX );
+	// TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX );
+	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
+
+	udelay(500000);
+
+	TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+	if ( aui ) 
+		value |= TLAN_TC_AUISEL;
+	else
+		value &= ~TLAN_TC_AUISEL;
+	TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+
+	// Read Possible Latched Link Status
+	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+	// Read Real Link Status
+       	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+	if ( ( value & MII_GS_LINK ) || aui ) {
+		priv->phyOnline = 1;
+		TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+	} else {
+		priv->phyOnline = 0;
+		TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+	}
+
+	// Enable Interrupts
+       	TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+	value |= TLAN_TC_INTEN;
+	TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+
+	sio = TLan_DioRead8( io, TLAN_NET_SIO );
+	sio |= TLAN_NET_SIO_MINTEN;
+	TLan_DioWrite8( io, TLAN_NET_SIO, sio );
+			
+	return 0;
+
+} /* TLanPhyInternalCheck */
+
+
+
+
+	/***************************************************************
+	 *	TLan_PhyInternalService
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	A pointer to a device structure of the
+	 *			adapter	holding the PHY to be serviced.
+	 *
+	 *	This function services an interrupt generated by the
+	 *	internal PHY.  It can turn on/off the link LED.  See
+	 *	Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
+	 *	Programmer's Guide".
+	 *
+	 **************************************************************/
+
+int TLan_PhyInternalService( struct device *dev )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u16			tlphy_sts;
+	u16			gen_sts;
+	u16			an_exp;
+	u32			io;
+	u16			phy;
+
+	io = dev->base_addr;
+	phy = priv->phyAddr;
+
+	TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts );
+	TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); 
+	TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); 
+	if ( ( gen_sts & MII_GS_LINK ) || aui ) {
+		priv->phyOnline = 1;
+		TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+	} else {
+		priv->phyOnline = 0;
+		TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+	}
+
+        if ( ( tlphy_sts & TLAN_TS_POLOK ) == 0) {
+                u16     value;
+                TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value);
+                value |= TLAN_TC_SWAPOL;
+                TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value);
+        }
+
+	return 0;
+
+} /* TLan_PhyInternalService */
+
+
+
+
+	/***************************************************************
+	 *	TLan_PhyDp83840aCheck
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		dev	A pointer to a device structure of the
+	 *			adapter holding the PHY to be reset.
+	 *
+	 *	This function resets a National Semiconductor DP83840A
+	 *	10/100 Mb/s PHY device.  See National Semiconductor's
+	 *	data sheet for more info.  This PHY is used on Compaq
+	 *	Netelligent 10/100 cards.
+	 *
+	 **************************************************************/
+
+static int TLan_PhyDp83840aCheck( struct device *dev )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u16			gen_ctl;
+	int			i;
+	u32			io;
+	u16			phy;
+	u16			value;
+	u8			sio;
+
+	io = dev->base_addr;
+	phy = priv->phyAddr;
+
+	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
+	if ( gen_ctl & MII_GC_PDOWN ) {
+		TLan_MiiSync( io );
+		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
+		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
+		for ( i = 0; i < 500000; i++ )
+			SLOW_DOWN_IO;
+		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
+		TLan_MiiSync( io );
+	}
+
+	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+	while ( value & MII_GC_RESET )
+		TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+
+	// TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX );
+	// TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX );
+	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
+	TLan_MiiReadReg( io, phy, MII_AN_ADV, &value );
+	value &= ~0x0140;
+	TLan_MiiWriteReg( io, phy, MII_AN_ADV, value );
+       	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 );
+	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 );
+
+	for ( i = 0; i < 50000; i++ )
+		SLOW_DOWN_IO;
+
+/*
+	// Read Possible Latched Link Status
+	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+	// Read Real Link Status
+	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+	if ( value & MII_GS_LINK ) {
+		priv->phyOnline = 1;
+		TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+	} else {
+		priv->phyOnline = 0;
+		TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+	}
+
+	// Enable Interrupts
+	TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+	value |= TLAN_TC_INTEN;
+	TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+*/
+	sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
+	sio &= ~TLAN_NET_SIO_MINTEN;
+	TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
+//	priv->phyOnline = 1;
+			
+	return 0;
+
+} /* TLan_PhyDp83840aCheck */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver MII Routines
+
+	These routines are based on the information in Chap. 2 of the
+	"ThunderLAN Programmer's Guide", pp. 15-24.
+
+******************************************************************************
+*****************************************************************************/
+
+
+	/***************************************************************
+	 *	TLan_MiiReadReg
+	 *
+	 *	Returns:
+	 *		0	if ack received ok
+	 *		1	otherwise.
+	 *
+	 *	Parms:
+	 *		base_port	The base IO port of the adapter in
+	 *				question.
+	 *		dev		The address of the PHY to be queried.
+	 *		reg		The register whose contents are to be
+	 *				retreived.
+	 *		val		A pointer to a variable to store the
+	 *				retrieved value.
+	 *
+	 *	This function uses the TLAN's MII bus to retreive the contents
+	 *	of a given register on a PHY.  It sends the appropriate info
+	 *	and then reads the 16-bit register value from the MII bus via
+	 *	the TLAN SIO register.
+	 *
+	 **************************************************************/
+
+int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val)
+{
+	u8	nack;
+	u16 sio, tmp;
+	u32 i;
+	int	err;
+	int minten;
+
+	err = FALSE;
+	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	cli();
+
+	TLan_MiiSync(base_port);
+
+	minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
+	if ( minten )
+		TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
+
+	TLan_MiiSendData( base_port, 0x1, 2 );		/* Start ( 01b ) */
+	TLan_MiiSendData( base_port, 0x2, 2 );		/* Read  ( 10b ) */
+	TLan_MiiSendData( base_port, dev, 5 );		/* Device #      */
+	TLan_MiiSendData( base_port, reg, 5 );		/* Register #    */
+
+
+	TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);		/* Change direction */
+
+	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);		/* Clock Idle bit */
+	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);		/* Wait 300ns */
+
+	nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio);	/* Check for ACK */
+	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);		/* Finish ACK */
+	if (nack) {					/* No ACK, so fake it */
+		for (i = 0; i < 16; i++) {
+			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+		}
+		tmp = 0xffff;
+		err = TRUE;
+	} else {					/* ACK, so read data */
+		for (tmp = 0, i = 0x8000; i; i >>= 1) {
+			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+			if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio))
+				tmp |= i;
+			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+		}
+	}
+
+
+	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);		/* Idle cycle */
+	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+
+	if ( minten )
+		TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
+
+	*val = tmp;
+
+	sti();
+
+	return err;
+
+} /* TLan_MiiReadReg */
+
+
+
+
+	/***************************************************************
+	 *	TLan_MiiSendData
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		base_port	The base IO port of the adapter	in
+	 *				question.
+	 *		dev		The address of the PHY to be queried.
+	 *		data		The value to be placed on the MII bus.
+	 *		num_bits	The number of bits in data that are to
+	 *				be placed on the MII bus.
+	 *
+	 *	This function sends on sequence of bits on the MII
+	 *	configuration bus.
+	 *
+	 **************************************************************/
+
+void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits )
+{
+	u16 sio;
+	u32 i;
+
+	if ( num_bits == 0 )
+		return;
+
+	outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR );
+	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+	TLan_SetBit( TLAN_NET_SIO_MTXEN, sio );
+
+	for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) {
+		TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );
+		TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
+		if ( data & i )
+			TLan_SetBit( TLAN_NET_SIO_MDATA, sio );
+		else
+			TLan_ClearBit( TLAN_NET_SIO_MDATA, sio );
+		TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
+		TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
+	}
+
+} /* TLan_MiiSendData */
+
+
+
+
+	/***************************************************************
+	 *	TLan_MiiSync
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		base_port	The base IO port of the adapter in
+	 *				question.
+	 *
+	 *	This functions syncs all PHYs in terms of the MII configuration
+	 *	bus.
+	 *
+	 **************************************************************/
+
+void TLan_MiiSync( u16 base_port )
+{
+	int i;
+	u16 sio;
+
+	outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR );
+	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio );
+	for ( i = 0; i < 32; i++ ) {
+		TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );
+		TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
+	}
+
+} /* TLan_MiiSync */
+
+
+
+
+	/***************************************************************
+	 *	TLan_MiiWriteReg
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		base_port	The base IO port of the adapter in
+	 *				question.
+	 *		dev		The address of the PHY to be written to.
+	 *		reg		The register whose contents are to be
+	 *				written.
+	 *		val		The value to be written to the register.
+	 *
+	 *	This function uses the TLAN's MII bus to write the contents of a
+	 *	given register on a PHY.  It sends the appropriate info and then
+	 *	writes the 16-bit register value from the MII configuration bus
+	 *	via the TLAN SIO register.
+	 *
+	 **************************************************************/
+
+void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val)
+{
+	u16 sio;
+	int	minten;
+
+	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	cli();
+
+	TLan_MiiSync( base_port );
+
+	minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
+	if ( minten )
+		TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio );
+
+	TLan_MiiSendData( base_port, 0x1, 2 );		/* Start ( 01b ) */
+	TLan_MiiSendData( base_port, 0x1, 2 );		/* Write ( 01b ) */
+	TLan_MiiSendData( base_port, dev, 5 );		/* Device #      */
+	TLan_MiiSendData( base_port, reg, 5 );		/* Register #    */
+
+	TLan_MiiSendData( base_port, 0x2, 2 );		/* Send ACK */
+	TLan_MiiSendData( base_port, val, 16 );		/* Send Data */
+
+	TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );	/* Idle cycle */
+	TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
+
+	if ( minten )
+		TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
+
+	sti();
+
+} /* TLan_MiiWriteReg */
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Eeprom routines
+
+	The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A
+	EEPROM.  These functions are based on information in Microchip's
+	data sheet.  I don't know how well this functions will work with
+	other EEPROMs.
+
+******************************************************************************
+*****************************************************************************/
+
+
+	/***************************************************************
+	 *	TLan_EeSendStart
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:	
+	 *		io_base		The IO port base address for the
+	 *				TLAN device with the EEPROM to
+	 *				use.
+	 *
+	 *	This function sends a start cycle to an EEPROM attached
+	 *	to a TLAN chip.
+	 *
+	 **************************************************************/
+
+void TLan_EeSendStart( u16 io_base )
+{
+	u16	sio;
+
+	outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR );
+	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+	TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+	TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
+	TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
+	TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+
+} /* TLan_EeSendStart */
+
+
+
+
+	/***************************************************************
+	 *	TLan_EeSendByte
+	 *
+	 *	Returns:
+	 *		If the correct ack was received, 0, otherwise 1
+	 *	Parms:	io_base		The IO port base address for the
+	 *				TLAN device with the EEPROM to
+	 *				use.
+	 *		data		The 8 bits of information to
+	 *				send to the EEPROM.
+	 *		stop		If TLAN_EEPROM_STOP is passed, a
+	 *				stop cycle is sent after the
+	 *				byte is sent after the ack is
+	 *				read.
+	 *
+	 *	This function sends a byte on the serial EEPROM line,
+	 *	driving the clock to send each bit. The function then
+	 *	reverses transmission direction and reads an acknowledge
+	 *	bit.
+	 *
+	 **************************************************************/
+
+int TLan_EeSendByte( u16 io_base, u8 data, int stop )
+{
+	int	err;
+	u8	place;
+	u16	sio;
+
+	outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR );
+	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	// Assume clock is low, tx is enabled;
+	for ( place = 0x80; place != 0; place >>= 1 ) {
+		if ( place & data )
+			TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+		else
+			TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
+		TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+		TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+	}
+	TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio );
+	TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+	err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio );
+	TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+	TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
+
+	if ( ( ! err ) && stop ) {
+		TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );	// STOP, raise data while clock is high
+		TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+		TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+	}
+
+	return ( err );
+
+} /* TLan_EeSendByte */
+
+
+
+
+	/***************************************************************
+	 *	TLan_EeReceiveByte
+	 *
+	 *	Returns:
+	 *		Nothing
+	 *	Parms:
+	 *		io_base		The IO port base address for the
+	 *				TLAN device with the EEPROM to
+	 *				use.
+	 *		data		An address to a char to hold the
+	 *				data sent from the EEPROM.
+	 *		stop		If TLAN_EEPROM_STOP is passed, a
+	 *				stop cycle is sent after the
+	 *				byte is received, and no ack is
+	 *				sent.
+	 *
+	 *	This function receives 8 bits of data from the EEPROM
+	 *	over the serial link.  It then sends and ack bit, or no
+	 *	ack and a stop bit.  This function is used to retrieve
+	 *	data after the address of a byte in the EEPROM has been
+	 *	sent.
+	 *
+	 **************************************************************/
+
+void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
+{
+	u8  place;
+	u16 sio;
+
+	outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR );
+	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+	*data = 0;
+
+	// Assume clock is low, tx is enabled;
+	TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio );
+	for ( place = 0x80; place; place >>= 1 ) {
+		TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+		if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) )
+			*data |= place;
+		TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+	}
+
+	TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
+	if ( ! stop ) {
+		TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );	// Ack = 0
+		TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+		TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+	} else {
+		TLan_SetBit( TLAN_NET_SIO_EDATA, sio );		// No ack = 1 (?)
+		TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+		TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+		TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );	// STOP, raise data while clock is high
+		TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+		TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+	}
+
+} /* TLan_EeReceiveByte */
+
+
+
+
+	/***************************************************************
+	 *	TLan_EeReadByte
+	 *
+	 *	Returns:
+	 *		No error = 0, else, the stage at which the error
+	 *		occured.
+	 *	Parms:
+	 *		io_base		The IO port base address for the
+	 *				TLAN device with the EEPROM to
+	 *				use.
+	 *		ee_addr		The address of the byte in the
+	 *				EEPROM whose contents are to be
+	 *				retrieved.
+	 *		data		An address to a char to hold the
+	 *				data obtained from the EEPROM.
+	 *
+	 *	This function reads a byte of information from an byte
+	 *	cell in the EEPROM.
+	 *
+	 **************************************************************/
+
+int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data )
+{
+	int err;
+
+	cli();
+
+	TLan_EeSendStart( io_base );
+	err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK );
+	if (err)
+		return 1;
+	err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK );
+	if (err)
+		return 2;
+	TLan_EeSendStart( io_base );
+	err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK );
+	if (err)
+		return 3;
+	TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP );
+
+	sti();
+
+	return 0;
+
+} /* TLan_EeReadByte */
+
+
+
+
+
diff -u --recursive --new-file v2.0.33/linux/drivers/net/tlan.h linux/drivers/net/tlan.h
--- v2.0.33/linux/drivers/net/tlan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tlan.h	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,507 @@
+#ifndef TLAN_H
+#define TLAN_H
+/********************************************************************
+ *
+ *  Linux ThunderLAN Driver
+ *
+ *  tlan.h
+ *  by James Banks, james.banks@caldera.com
+ *
+ *  (C) 1997 Caldera, Inc.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ *
+ ** This file is best viewed/edited with tabstop=4, colums>=132
+ *
+ ********************************************************************/
+
+
+#include <asm/io.h>
+#include <asm/types.h>
+#include <linux/netdevice.h>
+
+#if LINUX_VERSION_CODE <= 0x20100
+#define net_device_stats	enet_statistics
+#endif
+
+
+
+
+	/*****************************************************************
+	 * TLan Definitions
+	 *
+	 ****************************************************************/
+
+#define FALSE				0
+#define TRUE				1
+
+#define TLAN_MIN_FRAME_SIZE	64
+#define TLAN_MAX_FRAME_SIZE	1600
+
+#define TLAN_NUM_RX_LISTS 4
+#define TLAN_NUM_TX_LISTS 8
+
+#define TLAN_IGNORE	0
+#define TLAN_RECORD	1
+
+#define TLAN_DBG(lvl, format, args...)	if (debug&lvl) printk( format, ##args );
+#define TLAN_DEBUG_GNRL	0x0001
+#define TLAN_DEBUG_TX	0x0002
+#define TLAN_DEBUG_RX	0x0004 
+#define TLAN_DEBUG_LIST	0x0008
+
+
+
+
+	/*****************************************************************
+	 * Device Identification Definitions
+	 *
+	 ****************************************************************/
+		
+	/* NOTE: These have been moved to pci.h, will use them
+	   eventually */
+#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34
+#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32
+#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35
+#define PCI_DEVICE_ID_NETFLEX_3P 0xF130
+#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40
+#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011
+
+
+typedef struct tlan_pci_id {
+	u16	vendorId;
+	u16	deviceId;
+	char *deviceName;
+} TLanPciId;
+
+
+
+
+	/*****************************************************************
+	 * Rx/Tx List Definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_BUFFERS_PER_LIST	10
+#define TLAN_LAST_BUFFER	0x80000000
+#define TLAN_CSTAT_UNUSED	0x8000
+#define TLAN_CSTAT_FRM_CMP	0x4000
+#define TLAN_CSTAT_READY	0x3000
+#define TLAN_CSTAT_EOC		0x0800
+#define TLAN_CSTAT_RX_ERROR	0x0400
+#define TLAN_CSTAT_PASS_CRC	0x0200
+#define TLAN_CSTAT_DP_PR	0x0100
+
+
+typedef struct tlan_buffer_ref_tag {
+	u32	count;
+	u32	address;
+} TLanBufferRef;
+
+
+typedef struct tlan_list_tag {
+	u32		forward;
+	u16		cStat;
+	u16		frameSize;
+	TLanBufferRef	buffer[TLAN_BUFFERS_PER_LIST];
+} TLanList;
+
+
+typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];
+
+
+
+
+	/*****************************************************************
+	 * PHY definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_PHY_MAX_ADDR	0x1F
+
+#define TLAN_PHY_ACTIVITY	0x00000001
+#define TLAN_PHY_AUTONEG	0x00000002
+#define TLAN_PHY_INTS		0x00000004
+#define TLAN_PHY_BIT_RATE	0x00000008
+#define TLAN_PHY_UNMANAGED	0x00000010
+#define TLAN_PHY_INTERNAL	0x00000020
+
+
+typedef int (TLanPhyFunc)( struct device * );
+
+
+typedef struct tlan_phy_id_entry_tag {
+	u16		idHi;
+	u16		idLo;
+	TLanPhyFunc	*check;
+	TLanPhyFunc	*service;
+	u32		flags;
+} TLanPhyIdEntry;
+
+
+
+
+	/*****************************************************************
+	 * TLAN Private Information Structure
+	 *
+	 ****************************************************************/
+
+typedef struct tlan_private_tag {
+	struct device           *nextDevice;
+	void			*dmaStorage;
+	u8			*padBuffer;
+	TLanList                *rxList;
+	u8			*rxBuffer;
+	u32                     rxHead;
+	u32                     rxTail;
+	u32			rxEocCount;
+	TLanList                *txList;
+	u8			*txBuffer;
+	u32                     txHead;
+	u32                     txInProgress;
+	u32                     txTail;
+	u32			txBusyCount;
+	u32                     phyAddr;
+	u32                     phyEntry;
+	u32                     phyOnline;
+	u32                     phyFlags;
+	TLanPhyFunc             *phyCheck;
+	TLanPhyFunc             *phyService;
+	u32			timerSetAt;
+	u32			timerType;
+	struct timer_list	timer;
+	struct net_device_stats	stats;
+	u32                     pciEntry;
+	u8                      pciRevision;
+	u8                      pciBus;
+	u8                      pciDeviceFn;
+	u8			tlanRev;
+	char                    devName[8];
+} TLanPrivateInfo;
+
+
+
+
+	/*****************************************************************
+	 * TLan Driver Timer Definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_TIMER_LINK			1
+#define TLAN_TIMER_ACT			2
+
+#define TLAN_TIMER_LINK_DELAY	230
+#define TLAN_TIMER_ACT_DELAY	10
+
+
+
+
+	/*****************************************************************
+	 * TLan Driver Eeprom Definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_EEPROM_ACK		0
+#define TLAN_EEPROM_STOP	1
+
+
+
+
+	/*****************************************************************
+	 * Host Register Offsets and Contents
+	 *
+	 ****************************************************************/
+
+#define TLAN_HOST_CMD		0x00
+#define 	TLAN_HC_GO		0x80000000
+#define		TLAN_HC_STOP	0x40000000
+#define		TLAN_HC_ACK		0x20000000
+#define		TLAN_HC_CS_MASK 0x1FE00000
+#define		TLAN_HC_EOC		0x00100000
+#define		TLAN_HC_RT		0x00080000
+#define		TLAN_HC_NES		0x00040000
+#define		TLAN_HC_AD_RST	0x00008000
+#define		TLAN_HC_LD_TMR	0x00004000
+#define		TLAN_HC_LD_THR	0x00002000
+#define		TLAN_HC_REQ_INT	0x00001000
+#define		TLAN_HC_INT_OFF	0x00000800
+#define		TLAN_HC_INT_ON	0x00000400
+#define		TLAN_HC_AC_MASK	0x000000FF
+#define TLAN_CH_PARM		0x04
+#define TLAN_DIO_ADR		0x08
+#define		TLAN_DA_ADR_INC	0x8000
+#define		TLAN_DA_RAM_ADR	0x4000
+#define TLAN_HOST_INT		0x0A
+#define		TLAN_HI_IV_MASK	0x1FE0
+#define		TLAN_HI_IT_MASK	0x001C
+#define TLAN_DIO_DATA		0x0C
+
+
+/* ThunderLAN Internal Register DIO Offsets */
+
+#define TLAN_NET_CMD			0x00
+#define		TLAN_NET_CMD_NRESET	0x80
+#define		TLAN_NET_CMD_NWRAP	0x40
+#define		TLAN_NET_CMD_CSF	0x20
+#define		TLAN_NET_CMD_CAF	0x10
+#define		TLAN_NET_CMD_NOBRX	0x08
+#define		TLAN_NET_CMD_DUPLEX	0x04
+#define		TLAN_NET_CMD_TRFRAM	0x02
+#define		TLAN_NET_CMD_TXPACE	0x01
+#define TLAN_NET_SIO			0x01
+#define 	TLAN_NET_SIO_MINTEN	0x80
+#define		TLAN_NET_SIO_ECLOK	0x40
+#define		TLAN_NET_SIO_ETXEN	0x20
+#define		TLAN_NET_SIO_EDATA	0x10
+#define		TLAN_NET_SIO_NMRST	0x08
+#define		TLAN_NET_SIO_MCLK	0x04
+#define		TLAN_NET_SIO_MTXEN	0x02
+#define		TLAN_NET_SIO_MDATA	0x01
+#define TLAN_NET_STS			0x02
+#define		TLAN_NET_STS_MIRQ	0x80
+#define		TLAN_NET_STS_HBEAT	0x40
+#define		TLAN_NET_STS_TXSTOP	0x20
+#define		TLAN_NET_STS_RXSTOP 0x10
+#define		TLAN_NET_STS_RSRVD	0x0F
+#define TLAN_NET_MASK			0x03
+#define		TLAN_NET_MASK_MASK7	0x80
+#define		TLAN_NET_MASK_MASK6	0x40
+#define		TLAN_NET_MASK_MASK5	0x20
+#define		TLAN_NET_MASK_MASK4	0x10
+#define		TLAN_NET_MASK_RSRVD	0x0F
+#define TLAN_NET_CONFIG			0x04
+#define 	TLAN_NET_CFG_RCLK	0x8000
+#define		TLAN_NET_CFG_TCLK	0x4000
+#define		TLAN_NET_CFG_BIT	0x2000
+#define		TLAN_NET_CFG_RXCRC	0x1000
+#define		TLAN_NET_CFG_PEF	0x0800
+#define		TLAN_NET_CFG_1FRAG	0x0400
+#define		TLAN_NET_CFG_1CHAN	0x0200
+#define		TLAN_NET_CFG_MTEST	0x0100
+#define		TLAN_NET_CFG_PHY_EN	0x0080
+#define		TLAN_NET_CFG_MSMASK	0x007F
+#define TLAN_MAN_TEST		0x06
+#define TLAN_DEF_VENDOR_ID	0x08
+#define TLAN_DEF_DEVICE_ID	0x0A
+#define TLAN_DEF_REVISION	0x0C
+#define TLAN_DEF_SUBCLASS	0x0D
+#define TLAN_DEF_MIN_LAT	0x0E
+#define TLAN_DEF_MAX_LAT	0x0F
+#define TLAN_AREG_0			0x10
+#define TLAN_AREG_1			0x16
+#define TLAN_AREG_2			0x1C
+#define TLAN_AREG_3			0x22
+#define TLAN_HASH_1			0x28
+#define TLAN_HASH_2			0x2C
+#define TLAN_GOOD_TX_FRMS	0x30
+#define TLAN_TX_UNDERUNS	0x33
+#define TLAN_GOOD_RX_FRMS	0x34
+#define TLAN_RX_OVERRUNS	0x37
+#define TLAN_DEFERRED_TX	0x38
+#define TLAN_CRC_ERRORS		0x3A
+#define TLAN_CODE_ERRORS	0x3B
+#define TLAN_MULTICOL_FRMS	0x3C
+#define TLAN_SINGLECOL_FRMS	0x3E
+#define TLAN_EXCESSCOL_FRMS	0x40
+#define TLAN_LATE_COLS		0x41
+#define TLAN_CARRIER_LOSS	0x42
+#define TLAN_ACOMMIT		0x43
+#define TLAN_LED_REG		0x44
+#define		TLAN_LED_ACT	0x10
+#define		TLAN_LED_LINK	0x01
+#define TLAN_BSIZE_REG		0x45
+#define TLAN_MAX_RX			0x46
+#define TLAN_INT_DIS			0x48
+#define		TLAN_ID_TX_EOC		0x04
+#define		TLAN_ID_RX_EOF		0x02
+#define		TLAN_ID_RX_EOC		0x01
+
+
+
+/* ThunderLAN Interrupt Codes */
+
+#define TLAN_INT_NUMBER_OF_INTS	8
+
+#define TLAN_INT_NONE			0x0000
+#define TLAN_INT_TX_EOF			0x0001
+#define TLAN_INT_STAT_OVERFLOW	0x0002
+#define TLAN_INT_RX_EOF			0x0003
+#define TLAN_INT_DUMMY			0x0004
+#define TLAN_INT_TX_EOC			0x0005
+#define TLAN_INT_STATUS_CHECK	0x0006
+#define TLAN_INT_RX_EOC			0x0007
+
+
+
+/* ThunderLAN MII Registers */
+
+/* Generic MII/PHY Registers */
+
+#define MII_GEN_CTL				0x00
+#define 	MII_GC_RESET		0x8000
+#define		MII_GC_LOOPBK		0x4000
+#define		MII_GC_SPEEDSEL		0x2000
+#define		MII_GC_AUTOENB		0x1000
+#define		MII_GC_PDOWN		0x0800
+#define		MII_GC_ISOLATE		0x0400
+#define		MII_GC_AUTORSRT		0x0200
+#define		MII_GC_DUPLEX		0x0100
+#define		MII_GC_COLTEST		0x0080
+#define		MII_GC_RESERVED		0x007F
+#define MII_GEN_STS				0x01
+#define		MII_GS_100BT4		0x8000
+#define		MII_GS_100BTXFD		0x4000
+#define		MII_GS_100BTXHD		0x2000
+#define		MII_GS_10BTFD		0x1000
+#define		MII_GS_10BTHD		0x0800
+#define		MII_GS_RESERVED		0x07C0
+#define		MII_GS_AUTOCMPLT	0x0020
+#define		MII_GS_RFLT			0x0010
+#define		MII_GS_AUTONEG		0x0008
+#define		MII_GS_LINK			0x0004
+#define		MII_GS_JABBER		0x0002
+#define		MII_GS_EXTCAP		0x0001
+#define MII_GEN_ID_HI			0x02
+#define MII_GEN_ID_LO			0x03
+#define 	MII_GIL_OUI			0xFC00
+#define 	MII_GIL_MODEL		0x03F0
+#define 	MII_GIL_REVISION	0x000F
+#define MII_AN_ADV				0x04
+#define MII_AN_LPA				0x05
+#define MII_AN_EXP				0x06
+
+/* ThunderLAN Specific MII/PHY Registers */
+
+#define TLAN_TLPHY_ID			0x10
+#define TLAN_TLPHY_CTL			0x11
+#define 	TLAN_TC_IGLINK		0x8000
+#define		TLAN_TC_SWAPOL		0x4000
+#define		TLAN_TC_AUISEL		0x2000
+#define		TLAN_TC_SQEEN		0x1000
+#define		TLAN_TC_MTEST		0x0800
+#define		TLAN_TC_RESERVED	0x07F8
+#define		TLAN_TC_NFEW		0x0004
+#define		TLAN_TC_INTEN		0x0002
+#define		TLAN_TC_TINT		0x0001
+#define TLAN_TLPHY_STS			0x12
+#define		TLAN_TS_MINT		0x8000
+#define		TLAN_TS_PHOK		0x4000
+#define		TLAN_TS_POLOK		0x2000
+#define		TLAN_TS_TPENERGY	0x1000
+#define		TLAN_TS_RESERVED	0x0FFF
+
+
+
+/* Routines to access internal registers. */
+
+inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3)));
+	
+} /* TLan_DioRead8 */
+
+
+
+
+inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2)));
+
+} /* TLan_DioRead16 */
+
+
+
+
+inline u32 TLan_DioRead32(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inl(base_addr + TLAN_DIO_DATA));
+
+} /* TLan_DioRead32 */
+
+
+
+
+inline void TLan_DioWrite8(u16 base_addr, u16 internal_addr, u8 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outb(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x3));
+
+}
+
+
+
+
+inline void TLan_DioWrite16(u16 base_addr, u16 internal_addr, u16 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outw(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2));
+
+}
+
+
+
+
+inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outl(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2));
+
+}
+
+
+
+
+inline void TLan_ClearBit(u8 bit, u16 port)
+{
+	outb_p(inb_p(port) & ~bit, port);
+}
+
+
+
+
+inline int TLan_GetBit(u8 bit, u16 port)
+{
+	return ((int) (inb_p(port) & bit));
+}
+
+
+
+
+inline void TLan_SetBit(u8 bit, u16 port)
+{
+	outb_p(inb_p(port) | bit, port);
+}
+
+
+inline	u32	xor( u32 a, u32 b )
+{
+	return ( ( a && ! b ) || ( ! a && b ) );
+}
+#define XOR8( a, b, c, d, e, f, g, h )	xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) )
+#define DA( a, bit )					( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) )
+
+inline u32 TLan_HashFunc( u8 *a )
+{
+	u32	hash;
+
+	hash  = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) );
+	hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1;
+	hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2;
+	hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3;
+	hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4;
+	hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5;
+
+	return hash;
+
+} 
+
+
+
+
+#endif
diff -u --recursive --new-file v2.0.33/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.0.33/linux/drivers/net/tulip.c	Sun Sep  7 12:28:36 1997
+++ linux/drivers/net/tulip.c	Wed Jun  3 15:17:47 1998
@@ -1,7 +1,6 @@
 /* tulip.c: A DEC 21040-family ethernet driver for linux. */
 /*
-   NOTICE: THIS IS THE ALPHA TEST VERSION!
-	Written 1994-1997 by Donald Becker.
+	Written 1994-1998 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -17,10 +16,20 @@
 	http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
 */
 
-static const char *version = "tulip.c:v0.79 9/3/97 becker@cesdis.gsfc.nasa.gov\n";
+#define SMP_CHECK
+static const char version[] = "tulip.c:v0.88 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values. */
 
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, };			/* Jumbo MTU for interfaces. */
+
 /* Set if the PCI BIOS detects the chips on a multiport board backwards. */
 #ifdef REVERSE_PROBE_ORDER
 static int reverse_probe = 1;
@@ -33,10 +42,14 @@
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE	16
-#define RX_RING_SIZE	16
+#define RX_RING_SIZE	32
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
-static const rx_copybreak = 200;
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
 
 /* The following example shows how to always use the 10base2 port. */
 #ifdef notdef
@@ -125,6 +138,7 @@
 #endif
 
 #if (LINUX_VERSION_CODE < 0x20123)
+#define hard_smp_processor_id() smp_processor_id()
 #define test_and_set_bit(val, addr) set_bit(val, addr)
 #endif
 
@@ -156,7 +170,7 @@
 
 This device driver is designed for the DECchip "Tulip", Digital's
 single-chip ethernet controllers for PCI.  Supported members of the family
-are the 21040, 21041, 21140, 21140A and 21142.  These chips are used on
+are the 21040, 21041, 21140, 21140A, 21142, and 21143.  These chips are used on
 many PCI boards including the SMC EtherPower series.
 
 
@@ -251,30 +265,61 @@
 #ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS
 #define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014		/* 21041. */
 #endif
-
 #ifndef PCI_DEVICE_ID_DEC_TULIP_21142
 #define PCI_DEVICE_ID_DEC_TULIP_21142	0x0019
 #endif
 
+#ifndef PCI_VENDOR_ID_LITEON
+#define PCI_VENDOR_ID_LITEON	0x11AD
+#endif
+#define PCI_DEVICE_ID_PNIC		0x0002
+#define PCI_DEVICE_ID_PNIC_X	0x0168
+
+#ifndef PCI_VENDOR_ID_MXIC
+#define	PCI_VENDOR_ID_MXIC		0x10d9
+#define PCI_DEVICE_ID_MX98713	0x0512
+#define PCI_DEVICE_ID_MX98715	0x0531
+#define PCI_DEVICE_ID_MX98725	0x0531
+#endif
+
 /* The rest of these values should never change. */
 
 static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
 
 /* A table describing the chip types. */
+enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2};
 static struct tulip_chip_table {
-  int device_id;
-  char *chip_name;
-  int flags;
-  void (*media_timer)(unsigned long data);
+	int device_id;
+	char *chip_name;
+	int io_size;
+	int valid_intrs;			/* CSR7 interrupt enable settings */
+	int flags;
+	void (*media_timer)(unsigned long data);
 } tulip_tbl[] = {
-  { PCI_DEVICE_ID_DEC_TULIP, "DS21040 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_PLUS, "DS21041 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_FAST, "DS21140 Tulip", 0, tulip_timer }, /* + 21140A*/
-  { PCI_DEVICE_ID_DEC_TULIP_21142, "DS21142 Tulip", 0, tulip_timer }, /* + 21143 */
+  { PCI_DEVICE_ID_DEC_TULIP, "Digital DC21040 Tulip", 128, 0x0001ebef,
+	0, tulip_timer },
+  { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DC21041 Tulip", 128, 0x0001ebef,
+	HAS_MEDIA_TABLE, tulip_timer },
+  { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE, tulip_timer },
+  { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 256, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
+  { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+	0, pnic_timer },
+  { PCI_DEVICE_ID_MX98713, "Macronix 98713 PMAC", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE, tulip_timer /* Tulip-like! */ },
+  { PCI_DEVICE_ID_MX98715, "Macronix 98715 PMAC", 256, 0x0001ebef,
+	HAS_MEDIA_TABLE, mxic_timer },
+  { PCI_DEVICE_ID_MX98725, "Macronix 98725 PMAC", 256, 0x0001ebef,
+	HAS_MEDIA_TABLE, mxic_timer },
   {0, 0, 0, 0},
 };
 /* This matches the table above. */
-enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, };
+enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+			 LC82C168, MX98713, MX98715, MX98725};
 
 static const char * const medianame[] = {
   "10baseT", "10base2", "AUI", "100baseTx",
@@ -283,15 +328,17 @@
   "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
 };
 /* A full-duplex map for above. */
-static const char media_fd[] =
-{0,0,0,0,  0xff,0xff,0,0,  0xff,0,0xff,0x01, 0,0,0xff,0 };
+enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+		  MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
 /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
 static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
 static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
 static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
 
-static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0001, 0x0001, };
-static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x7F3F, 0x7F3D, };
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
 static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
 
 /* Offsets to the Command and Status Registers, "CSRs".  All accesses
@@ -304,9 +351,9 @@
 /* The bits in the CSR5 status registers, mostly interrupt sources. */
 enum status_bits {
 	TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+	NormalIntr=0x10000, AbnormalIntr=0x8000,
 	RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
-	TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02,
-	TxIntr=0x01,
+	TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
 };
 
 /* The Tulip Rx and Tx buffer descriptors. */
@@ -339,7 +386,6 @@
 	struct mediainfo *next;
 	int info_type;
 	int index;
-	struct non_mii { char media; unsigned char csr12val; char bitnum, flags;}  non_mii;
 	unsigned char *info;
 };
 
@@ -354,7 +400,7 @@
 	/* The addresses of receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	char *rx_buffs;				/* Address of temporary Rx buffers. */
-	int setup_frame[48];		/* Pseudo-Tx frame to init address table. */
+	u32 setup_frame[48];		/* Pseudo-Tx frame to init address table. */
 	int chip_id;
 	int revision;
 #if LINUX_VERSION_CODE > 0x20139
@@ -363,32 +409,37 @@
 	struct enet_statistics stats;
 #endif
 	struct timer_list timer;	/* Media selection timer. */
+	int interrupt;				/* In-interrupt flag. */
+#ifdef SMP_CHECK
+	int smp_proc_id;			/* Which processor in IRQ handler. */
+#endif
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int full_duplex_lock:1;
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	unsigned int media2:4;				/* Secondary monitored media port. */
 	unsigned int medialock:1;			/* Don't sense media type. */
 	unsigned int mediasense:1;			/* Media sensing in progress. */
 	unsigned int csr6;					/* Current CSR6 control settings. */
 	unsigned char eeprom[128];			/* Serial EEPROM contents. */
-	signed char phys[4];				/* MII device addresses. */
+	u16 to_advertise;					/* NWay capabilities advertised.  */
+	u16 advertising[4];
+	signed char phys[4], mii_cnt;		/* MII device addresses. */
 	struct mediatable *mtable;
 	int cur_index;						/* Current media index. */
-	unsigned char pci_bus, pci_device_fn;
+	unsigned char pci_bus, pci_dev_fn;
 	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
-/* Used to pass the full-duplex flag, etc. */
-static int full_duplex[8] = {0, };
-static int options[8] = {0, };
-
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_devfn,
+								   struct device *dev, int ioaddr,
 								   int chip_id, int options);
 static void parse_eeprom(struct device *dev);
 static int read_eeprom(int ioaddr, int location);
 static int mdio_read(int ioaddr, int phy_id, int location);
+static void mdio_write(int ioaddr, int phy_id, int location, int value);
 static void select_media(struct device *dev, int startup);
 static int tulip_open(struct device *dev);
 static void tulip_timer(unsigned long data);
@@ -399,18 +450,19 @@
 static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
 static int tulip_close(struct device *dev);
 static struct enet_statistics *tulip_get_stats(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
 #ifdef NEW_MULTICAST
-static void set_multicast_list(struct device *dev);
+static void set_rx_mode(struct device *dev);
 #else
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
 #endif
 
 
 
-#ifdef MODULE
 /* A list of all installed Tulip devices, for removing the driver module. */
 static struct device *root_tulip_dev = NULL;
-#endif
 
 /* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
    but now receives directly into full-sized skbuffs that are allocated
@@ -432,9 +484,9 @@
 		unsigned char pci_bus, pci_device_fn;
 
 		for (;pci_index < 0xff; pci_index++) {
-			unsigned char pci_irq_line, pci_latency;
-			unsigned short pci_command, vendor, device;
-			unsigned int pci_ioaddr, chip_idx = 0;
+			u16 vendor, device, pci_command, new_command;
+			u32 pci_ioaddr;
+			int chip_idx = 0;
 
 			if (pcibios_find_class
 				(PCI_CLASS_NETWORK_ETHERNET << 8,
@@ -448,64 +500,71 @@
 									 PCI_VENDOR_ID, &vendor);
 			pcibios_read_config_word(pci_bus, pci_device_fn,
 									 PCI_DEVICE_ID, &device);
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_INTERRUPT_LINE, &pci_irq_line);
 			pcibios_read_config_dword(pci_bus, pci_device_fn,
 									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
 			/* Remove I/O space marker in bit 0. */
 			pci_ioaddr &= ~3;
 
-			if (vendor != PCI_VENDOR_ID_DEC)
+			if (vendor != PCI_VENDOR_ID_DEC
+				&& vendor != PCI_VENDOR_ID_LITEON
+				&& vendor != PCI_VENDOR_ID_MXIC)
 				continue;
+			if (vendor == PCI_VENDOR_ID_LITEON)
+				device = PCI_DEVICE_ID_PNIC_X;
+			else if (vendor == PCI_VENDOR_ID_MXIC)
+				device = PCI_DEVICE_ID_MX98713;
 
 			for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
 				if (device == tulip_tbl[chip_idx].device_id)
 					break;
 			if (tulip_tbl[chip_idx].chip_name == 0) {
-				printk(KERN_INFO "Unknown Digital PCI ethernet chip type"
-					   " %4.4x"" detected: not configured.\n", device);
+				printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
+					   " %4.4x %4.4x"" detected: not configured.\n",
+					   vendor, device);
 				continue;
 			}
 			if (tulip_debug > 2)
-				printk(KERN_DEBUG "Found DEC PCI Tulip at I/O %#x, IRQ %d.\n",
-					   pci_ioaddr, pci_irq_line);
+				printk(KERN_DEBUG "Found %s at I/O %#x.\n",
+					   tulip_tbl[chip_idx].chip_name, pci_ioaddr);
 
-			if (check_region(pci_ioaddr, TULIP_TOTAL_SIZE))
+			if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
 				continue;
 
-#ifdef MODULE
-			dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
-						 cards_found);
-#else
-			dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, -1);
-#endif
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+			if (pci_command != new_command) {
+				printk(KERN_INFO "  The PCI BIOS has not enabled this"
+					   " device!  Updating PCI command %4.4x->%4.4x.\n",
+					   pci_command, new_command);
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, new_command);
+			}
 
+			dev = tulip_probe1(pci_bus, pci_device_fn, dev,
+							   pci_ioaddr, chip_idx, cards_found);
+
+			/* Get and check the bus-master and latency values. */
 			if (dev) {
-			  /* Get and check the bus-master and latency values. */
-			  pcibios_read_config_word(pci_bus, pci_device_fn,
-									   PCI_COMMAND, &pci_command);
-			  if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-				printk(KERN_INFO "  PCI Master Bit has not been set! Setting...\n");
-				pci_command |= PCI_COMMAND_MASTER;
-				pcibios_write_config_word(pci_bus, pci_device_fn,
-										  PCI_COMMAND, pci_command);
-			  }
-			  pcibios_read_config_byte(pci_bus, pci_device_fn,
-									   PCI_LATENCY_TIMER, &pci_latency);
-			  if (pci_latency < 10) {
-				printk(KERN_INFO "  PCI latency timer (CFLT) is unreasonably"
-					   " low at %d.  Setting to 64 clocks.\n", pci_latency);
-				pcibios_write_config_byte(pci_bus, pci_device_fn,
-										  PCI_LATENCY_TIMER, 64);
-			  } else if (tulip_debug > 1)
-				printk(KERN_INFO "  PCI latency timer (CFLT) is %#x.\n",
-					   pci_latency);
-			  /* Bring the 21143 out power-down mode. */
-			  if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
-				pcibios_write_config_dword(pci_bus, pci_device_fn,
-										  	0x40, 0x40000000);
-			  dev = 0;
-			  cards_found++;
+				unsigned char pci_latency;
+				pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_LATENCY_TIMER, &pci_latency);
+				if (pci_latency < 10) {
+					printk(KERN_INFO "  PCI latency timer (CFLT) is "
+						   "unreasonably low at %d.  Setting to 64 clocks.\n",
+						   pci_latency);
+					pcibios_write_config_byte(pci_bus, pci_device_fn,
+											  PCI_LATENCY_TIMER, 64);
+				} else if (tulip_debug > 1)
+					printk(KERN_INFO "  PCI latency timer (CFLT) is %#x, "
+						   " PCI command is %4.4x.\n",
+						   pci_latency, new_command);
+				/* Bring the 21143 out power-down mode. */
+				if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
+					pcibios_write_config_dword(pci_bus, pci_device_fn,
+											   0x40, 0x40000000);
+				dev = 0;
+				cards_found++;
 			}
 		}
 	}
@@ -513,7 +572,8 @@
 	return cards_found ? 0 : -ENODEV;
 }
 
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
+								   struct device *dev, int ioaddr,
 								   int chip_id, int board_idx)
 {
 	static int did_version = 0;			/* Already printed version info. */
@@ -521,6 +581,7 @@
 	/* See note below on the multiport cards. */
 	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
 	static int last_irq = 0;
+	u8 pci_irq_line;
 	int i;
 	unsigned short sum;
 
@@ -529,13 +590,15 @@
 
 	dev = init_etherdev(dev, 0);
 
-	printk(KERN_INFO "%s: DEC %s at %#3x,",
+	pcibios_read_config_byte(pci_bus, pci_device_fn,
+							 PCI_INTERRUPT_LINE, &pci_irq_line);
+	printk(KERN_INFO "%s: %s at %#3x,",
 		   dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
 
 	/* Stop the chip's Tx and Rx processes. */
 	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
 	/* Clear the missed-packet counter. */
-	(volatile)inl(ioaddr + CSR8);
+	(volatile int)inl(ioaddr + CSR8);
 
 	if (chip_id == DC21041) {
 		if (inl(ioaddr + CSR9) & 0x8000) {
@@ -561,6 +624,16 @@
 			dev->dev_addr[i] = value;
 			sum += value & 0xff;
 		}
+	} else if (chip_id == LC82C168) {
+		for (i = 0; i < 3; i++) {
+			int value, boguscnt = 100000;
+			outl(0x600 | i, ioaddr + 0x98);
+			do
+				value = inl(ioaddr + CSR9);
+			while (value < 0  && --boguscnt > 0);
+			((u16*)dev->dev_addr)[i] = value;
+			sum += value & 0xffff;
+		}
 	} else {	/* Must be a new chip, with a serial EEPROM interface. */
 		/* We read the whole EEPROM, and sort it out later.  DEC has a
 		   specification _Digital Semiconductor 21X4 Serial ROM Format_
@@ -581,6 +654,13 @@
 			sum += ee_data[i + sa_offset];
 		}
 	}
+	/* Lite-On boards have the address byte-swapped. */
+	if (dev->dev_addr[0] == 0xA0  &&  dev->dev_addr[1] == 0x00)
+		for (i = 0; i < 6; i+=2) {
+			char tmp = dev->dev_addr[i];
+			dev->dev_addr[i] = dev->dev_addr[i+1];
+			dev->dev_addr[i+1] = tmp;
+		}
 	/* On the Zynx 315 Etherarray and other multiport boards only the
 	   first Tulip has an EEPROM.
 	   The addresses of the subsequent ports are derived from the first.
@@ -591,33 +671,37 @@
 		for (i = 0; i < 5; i++)
 			dev->dev_addr[i] = last_phys_addr[i];
 		dev->dev_addr[i] = last_phys_addr[i] + 1;
-		irq = last_irq;
+#if defined(__i386__)		/* This BIOS bug doesn't exist on Alphas. */
+		pci_irq_line = last_irq;
+#endif
 	}
 	for (i = 0; i < 6; i++)
 		printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
-	printk(", IRQ %d.\n", irq);
-	last_irq = irq;
+	printk(", IRQ %d.\n", pci_irq_line);
+	last_irq = pci_irq_line;
 
 	/* We do a request_region() only to register /proc/ioports info. */
+	/* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
 	request_region(ioaddr, TULIP_TOTAL_SIZE, tulip_tbl[chip_id].chip_name);
 
 	dev->base_addr = ioaddr;
-	dev->irq = irq;
+	dev->irq = pci_irq_line;
 
 	/* Make certain the data structures are quadword aligned. */
 	tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
 	memset(tp, 0, sizeof(*tp));
 	dev->priv = tp;
 
-#ifdef MODULE
 	tp->next_module = root_tulip_dev;
 	root_tulip_dev = dev;
-#endif
 
+	tp->pci_bus = pci_bus;
+	tp->pci_dev_fn = pci_device_fn;
 	tp->chip_id = chip_id;
 
 #ifdef TULIP_FULL_DUPLEX
 	tp->full_duplex = 1;
+	tp->full_duplex_lock = 1;
 #endif
 #ifdef TULIP_DEFAULT_MEDIA
 	tp->default_port = TULIP_DEFAULT_MEDIA;
@@ -627,32 +711,64 @@
 #endif
 
 	/* The lower four bits are the media type. */
-	if (board_idx >= 0) {
-		tp->full_duplex = (options[board_idx]&16) || full_duplex[board_idx]>0;
+	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
 		tp->default_port = options[board_idx] & 15;
-		if (tp->default_port)
-			tp->medialock = 1;
+		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+			tp->full_duplex = 1;
+		if (mtu[board_idx] > 0)
+			dev->mtu = mtu[board_idx];
+	}
+	if (dev->mem_start)
+		tp->default_port = dev->mem_start;
+	if (tp->default_port) {
+		tp->medialock = 1;
+		if (media_cap[tp->default_port] & MediaAlwaysFD)
+			tp->full_duplex = 1;
 	}
+	if (tp->full_duplex)
+		tp->full_duplex_lock = 1;
 
 	/* This is logically part of probe1(), but too complex to write inline. */
-	if (chip_id != DC21040)
+	if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
 		parse_eeprom(dev);
 
-	if (tp->mtable  &&  tp->mtable->has_mii) {
+	if (media_cap[tp->default_port] & MediaIsMII) {
+		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+		tp->to_advertise = media2advert[tp->default_port - 9];
+	} else
+		tp->to_advertise = 0x03e1;
+
+	if ((tp->mtable  &&  tp->mtable->has_mii) ||
+		( ! tp->mtable  &&  (tulip_tbl[tp->chip_id].flags & HAS_MII))) {
 		int phy, phy_idx;
 		/* Find the connected MII xcvrs.
 		   Doing this in open() would allow detecting external xcvrs later,
 		   but takes much time. */
 		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
 			 phy++) {
-			int mii_status = mdio_read(ioaddr, phy, 0);
-			if (mii_status != 0xffff  && mii_status != 0x0000) {
-				tp->phys[phy_idx++] = phy;
-				printk(KERN_INFO "%s:  MII transceiver found at MDIO address %d.\n",
-					   dev->name, phy);
+			int mii_status = mdio_read(ioaddr, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				int mii_reg0 = mdio_read(ioaddr, phy, 0);
+				int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+				tp->phys[phy_idx] = phy;
+				tp->advertising[phy_idx++] = reg4;
+				printk(KERN_INFO "%s:  MII transceiver found at MDIO address "
+					   "%d, config %4.4x status %4.4x.\n",
+					   dev->name, phy, mii_reg0, mii_status);
+				if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
+					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
+						   " previously advertising %4.4x.\n",
+						   dev->name, reg4, phy, mdio_read(ioaddr, phy, 4));
+					mdio_write(ioaddr, phy, 4, reg4);
+				}
+				/* Enable autonegotiation: some boards default to off. */
+				mdio_write(ioaddr, phy, 0, mii_reg0 |
+						   (tp->full_duplex ? 0x1100 : 0x1000) |
+						   (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
 			}
 		}
-		if (phy_idx == 0) {
+		tp->mii_cnt = phy_idx;
+		if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
 			printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
 				   dev->name);
 			tp->phys[0] = 1;
@@ -664,8 +780,11 @@
 	dev->hard_start_xmit = &tulip_start_xmit;
 	dev->stop = &tulip_close;
 	dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+	dev->do_ioctl = &private_ioctl;
+#endif
 #ifdef HAVE_MULTICAST
-	dev->set_multicast_list = &set_multicast_list;
+	dev->set_multicast_list = &set_rx_mode;
 #endif
 
 	/* Reset the xcvr interface and turn on heartbeat. */
@@ -674,17 +793,36 @@
 		outl(0x00000000, ioaddr + CSR13);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
-		outl(inl(ioaddr + CSR6) | 0x200, ioaddr + CSR6);
+		outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
 		outl(0x0000EF05, ioaddr + CSR13);
 		break;
-	case DC21140:  case DC21142:
-		if (tp->mtable)
-			outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
-		break;
 	case DC21040:
 		outl(0x00000000, ioaddr + CSR13);
 		outl(0x00000004, ioaddr + CSR13);
 		break;
+	case DC21140: default:
+		if (tp->mtable)
+			outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+		break;
+	case DC21142:
+		outl(0x82420200, ioaddr + CSR6);
+		outl(0x0001, ioaddr + CSR13);
+		outl(0x0003FFFF, ioaddr + CSR14);
+		outl(0x0008, ioaddr + CSR15);
+		outl(0x0001, ioaddr + CSR13);
+		outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+		break;
+	case LC82C168:
+		outl(0x00420000, ioaddr + CSR6);
+		outl(0x30, ioaddr + CSR12);
+		outl(0x0001F078, ioaddr + 0xB8);
+		outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+		break;
+	case MX98713: case MX98715: case MX98725:
+		outl(0x00000000, ioaddr + CSR6);
+		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+		outl(0x00000001, ioaddr + CSR13);
+		break;
 	}
 
 	return dev;
@@ -722,49 +860,50 @@
   {0, 0, 0, 0, {}}};
 
 static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
- "21142 non-MII PHY", "21142 MII PHY", };
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
 
 #define EEPROM_SIZE 128
+#if defined(__i386__)
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
 static void parse_eeprom(struct device *dev)
 {
 	/* The last media info list parsed, for multiport boards.  */
 	static struct mediatable *last_mediatable = NULL;
 	static unsigned char *last_ee_data = NULL;
-	static controller_index = 0;
+	static int controller_index = 0;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int ioaddr = dev->base_addr;
 	unsigned char *ee_data = tp->eeprom;
 	int i;
 
-	{
-	  static int done_did_that = 0;
-	  if (done_did_that++ == 0)
-		printk(KERN_INFO"  The following verbose information is emitted for\n"
-			   KERN_INFO"  bug reports on media selection.\n");
-	}
 	tp->mtable = 0;
 	for (i = 0; i < EEPROM_SIZE/2; i++)
-	  ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
+		((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
 
 	/* Detect an old-style (SA only) EEPROM layout:
 	   memcmp(eedata, eedata+16, 8). */
 	for (i = 0; i < 8; i ++)
-	  if (ee_data[i] != ee_data[16+i])
-		break;
+		if (ee_data[i] != ee_data[16+i])
+			break;
 	if (i >= 8) {
-	  if (ee_data[0] == 0xff) {
-		if (last_mediatable) {
-		  controller_index++;
-		  printk(KERN_INFO "%s:  Controller %d of multiport board.\n",
-				 dev->name, controller_index);
-		  tp->mtable = last_mediatable;
-		  ee_data = last_ee_data;
-		  goto subsequent_board;
-		} else
-		printk(KERN_INFO "%s:  Missing EEPROM, this device may not work correctly!\n",
+		if (ee_data[0] == 0xff) {
+			if (last_mediatable) {
+				controller_index++;
+				printk(KERN_INFO "%s:  Controller %d of multiport board.\n",
+					   dev->name, controller_index);
+				tp->mtable = last_mediatable;
+				ee_data = last_ee_data;
+				goto subsequent_board;
+			} else
+				printk(KERN_INFO "%s:  Missing EEPROM, this interface may "
+					   "not work correctly!\n",
 			   dev->name);
-		return;
-	  }
+			return;
+		}
 	  /* Do a fix-up based on the vendor half of the station address prefix. */
 	  for (i = 0; eeprom_fixups[i].name; i++) {
 		if (dev->dev_addr[0] == eeprom_fixups[i].addr0
@@ -787,7 +926,7 @@
 	  }
 	}
 	if (tulip_debug > 1) {
-	  printk(KERN_DEBUG "\nread_eeprom:");
+	  printk(KERN_DEBUG "read_eeprom:");
 	  for (i = 0; i < 64; i++) {
 		printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ",
 			   read_eeprom(ioaddr, i));
@@ -801,30 +940,44 @@
 	}
 subsequent_board:
 
-	if (tp->chip_id == DC21041) {
+	if (ee_data[27] == 0) {		/* No valid media table. */
+	} else if (tp->chip_id == DC21041) {
 		unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
-		short media = *(u16 *)p;
-		int count = p[2];
+		short media;
+		int count;
+
+		media = get_u16(p);
+		p += 2;
+		count = *p++;
 
 		printk(KERN_INFO "%s:21041 Media information at %d, default media "
 			   "%4.4x (%s).\n", dev->name, ee_data[27], media,
 			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
 		for (i = 0; i < count; i++) {
-			unsigned char media_code = p[3 + i*7];
-			unsigned short *csrvals = (unsigned short *)&p[3 + i*7 + 1];
-			printk(KERN_INFO "%s:  21041 media %2.2x (%s),"
-				   " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
-				   dev->name, media_code & 15, medianame[media_code & 15],
-				   csrvals[0], csrvals[1], csrvals[2]);
+			unsigned char media_code = *p++;
+			u16 csrvals[3];
+			for (i = 0; i < 3; i++) {
+				csrvals[i] = get_u16(p);
+				p += 2;
+			}
+			if (media_code & 0x40) {
+				printk(KERN_INFO "%s:  21041 media %2.2x (%s),"
+					   " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
+					   dev->name, media_code & 15, medianame[media_code & 15],
+					   csrvals[0], csrvals[1], csrvals[2]);
+			} else
+				printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
+					   dev->name, media_code & 15, medianame[media_code & 15]);
 		}
 	} else {
 		unsigned char *p = (void *)ee_data + ee_data[27];
 		unsigned char csr12dir = 0;
 		int count;
 		struct mediatable *mtable;
-		short media = *((u16 *)p)++;
+		u16 media = get_u16(p);
 
-		if (tp->chip_id == DC21140)
+		p += 2;
+		if (tp->chip_id == DC21140  ||  tp->chip_id == MX98713)
 			csr12dir = *p++;
 		count = *p++;
 		mtable = (struct mediatable *)
@@ -847,6 +1000,8 @@
 				leaf->type = 0;
 				leaf->media = p[0] & 0x3f;
 				leaf->leafdata = p;
+				if ((p[2] & 0x61) == 0x01)	/* Bogus, but Znyx boards do it. */
+					mtable->has_mii = 1;
 				p += 4;
 			} else {
 				leaf->type = p[1];
@@ -864,16 +1019,7 @@
 					   "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
 					   dev->name, bp[0], bp[1], bp[1 + bp[1]*2],
 					   bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
-				if (tulip_debug > 2) {
-					int mii_reg;
-					printk(KERN_DEBUG "%s:  MII xcvr control registers:",
-						   dev->name);
-					for (mii_reg = 0; mii_reg < 32; mii_reg++)
-						printk(" %4.4x", mdio_read(ioaddr,bp[0], mii_reg));
-					printk(".\n");
-				}
 			}
-
 			printk(KERN_INFO "%s:  Index #%d - Media %s (#%d) described "
 				   "by a %s (%d) block.\n",
 				   dev->name, i, medianame[leaf->media], leaf->media,
@@ -941,6 +1087,16 @@
 	return retval;
 }
 
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
 /* Read and write the MII registers using software-generated serial
    MDIO protocol.  It is just different enough from the EEPROM protocol
    to not share code.  The maxium data clock rate is 2.5 Mhz. */
@@ -950,17 +1106,12 @@
 #define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */
 #define MDIO_ENB_IN		0x40000
 #define MDIO_DATA_READ	0x80000
-#ifdef _LINUX_DELAY_H
-#define mdio_delay()	udelay(1)
-#else
-#define mdio_delay()	__SLOW_DOWN_IO
-#endif
 
 static int mdio_read(int ioaddr, int phy_id, int location)
 {
 	int i;
 	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	unsigned short retval = 0;
+	int retval = 0;
 	int mdio_addr = ioaddr + CSR9;
 
 	/* Establish sync by sending at least 32 logic ones. */ 
@@ -971,35 +1122,54 @@
 		mdio_delay();
 	}
 	/* Shift the read command bits out. */
-	for (i = 17; i >= 0; i--) {
+	for (i = 15; i >= 0; i--) {
 		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
 
-		outl(dataval, mdio_addr);
+		outl(MDIO_ENB | dataval, mdio_addr);
 		mdio_delay();
-		outl(dataval | MDIO_SHIFT_CLK, mdio_addr);
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
 		mdio_delay();
-		outl(dataval, mdio_addr);
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outl(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
 		mdio_delay();
 	}
-	outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-	mdio_delay();
-	outl(MDIO_ENB_IN, mdio_addr);
+	return (retval>>1) & 0xffff;
+}
 
-	for (i = 16; i > 0; i--) {
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+static void mdio_write(int ioaddr, int phy_id, int location, int value)
+{
+	int i;
+	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+	int mdio_addr = ioaddr + CSR9;
+
+	/* Establish sync by sending 32 logic ones. */ 
+	for (i = 32; i >= 0; i--) {
+		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
 		mdio_delay();
-		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		outl(MDIO_ENB_IN, mdio_addr);
+		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
 		mdio_delay();
 	}
-	/* Clear out extra bits. */
-	for (i = 16; i > 0; i--) {
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+		outl(MDIO_ENB | dataval, mdio_addr);
 		mdio_delay();
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
 		outl(MDIO_ENB_IN, mdio_addr);
 		mdio_delay();
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
 	}
-	return retval;
+	return;
 }
 
 
@@ -1011,7 +1181,7 @@
 	int i = 0;
 
 	/* On some chip revs we must set the MII/SYM port before the reset!? */
-	if (tp->mtable  &&  tp->mtable->has_mii)
+	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
 		outl(0x00040000, ioaddr + CSR6);
 
 	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
@@ -1033,23 +1203,30 @@
 	   Tx and Rx queues and the address filter list. */
 #if defined(__alpha__)
 	/* ToDo: Alpha setting could be better. */
-	outl(0x00200000 | 0xE000, ioaddr + CSR0);
-#else
+	outl(0x01A00000 | 0xE000, ioaddr + CSR0);
+#elif defined(__powerpc__)
+	outl(0x01A00080 | 0x8000, ioaddr + CSR0);
+#elif defined(__i386__)
 #if defined(MODULE)
 	/* When a module we don't have 'x86' to check. */
-	outl(0x00200000 | 0x4800, ioaddr + CSR0);
+	outl(0x01A00000 | 0x4800, ioaddr + CSR0);
 #else
-	outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
+#if (LINUX_VERSION_CODE > 0x2014c)
+#define x86 boot_cpu_data.x86
+#endif
+	outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
 	if (x86 <= 4)
 	  printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
 			 "alignment to %x.\n", dev->name,
-			 0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000));
+			 0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
 #endif
+#else
+	outl(0x01A00000 | 0x4800, ioaddr + CSR0);
+#warning Processor architecture undefined!
 #endif
 
 #ifdef SA_SHIRQ
-	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ,
-					tulip_tbl[tp->chip_id].chip_name, dev)) {
+	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
 		return -EAGAIN;
 	}
 #else
@@ -1073,7 +1250,7 @@
 	/* Fill the whole address filter table with our physical address. */
 	{
 		u16 *eaddrs = (u16 *)dev->dev_addr;
-		int *setup_frm = tp->setup_frame, i;
+		u32 *setup_frm = tp->setup_frame, i;
 
 		/* You must add the broadcast address when doing perfect filtering! */
 		*setup_frm++ = 0xffff;
@@ -1097,7 +1274,7 @@
 	outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
 
 	if (dev->if_port == 0)
-	  dev->if_port = tp->default_port;
+		dev->if_port = tp->default_port;
 	if (tp->chip_id == DC21041  &&  dev->if_port > 4)
 		/* Invalid: Select initial TP, autosense, autonegotiate.  */
 		dev->if_port = 4;
@@ -1105,14 +1282,16 @@
 	/* Allow selecting a default media. */
 	if (tp->mtable == NULL)
 		goto media_picked;
-	if (dev->if_port)
+	if (dev->if_port) {
+		int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
+			(dev->if_port == 12 ? 0 : dev->if_port);
 		for (i = 0; i < tp->mtable->leafcount; i++)
-		  if (tp->mtable->mleaf[i].media ==
-			  (dev->if_port == 12 ? 0 : dev->if_port)) {
+		  if (tp->mtable->mleaf[i].media == looking_for) {
 			printk(KERN_INFO "%s: Using user-specified media %s.\n",
 				   dev->name, medianame[dev->if_port]);
 			goto media_picked;
 		  }
+	}
 	if ((tp->mtable->defaultmedia & 0x0800) == 0)
 		for (i = 0; i < tp->mtable->leafcount; i++)
 		  if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) {
@@ -1120,26 +1299,33 @@
 				   dev->name, medianame[tp->mtable->mleaf[i].media]);
 			goto media_picked;
 		  }
+	/* Start sensing first non-full-duplex media. */
 	for (i = tp->mtable->leafcount - 1;
-		 (media_fd[tp->mtable->mleaf[i].media] & 2) && i > 0; i--)
+		 (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
 	  ;
 media_picked:
 
-	tp->cur_index = i;
 	tp->csr6 = 0;
-	select_media(dev, 1);
+	tp->cur_index = i;
+	if (dev->if_port == 0  &&  tp->chip_id == DC21142) {
+		tp->csr6 = 0x82420200;
+		outl(0x0003FFFF, ioaddr + CSR14);
+		outl(0x0008, ioaddr + CSR15);
+		outl(0x0001, ioaddr + CSR13);
+		outl(0x1301, ioaddr + CSR12);
+	} else
+		select_media(dev, 1);
 
 	/* Start the chip's Tx to process setup frame. */
 	outl(tp->csr6, ioaddr + CSR6);
 	outl(tp->csr6 | 0x2000, ioaddr + CSR6);
 
 	dev->tbusy = 0;
-	dev->interrupt = 0;
+	tp->interrupt = 0;
 	dev->start = 1;
 
-
 	/* Enable interrupts by setting the interrupt mask. */
-	outl(0x0001fbff, ioaddr + CSR7);
+	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
 	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
 	outl(0, ioaddr + CSR2);		/* Rx poll demand */
 
@@ -1151,9 +1337,9 @@
 	/* Set the timer to switch to check for link beat and perhaps switch
 	   to an alternate media type. */
 	init_timer(&tp->timer);
-	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
+	tp->timer.expires = RUN_AT(5*HZ);
 	tp->timer.data = (unsigned long)dev;
-	tp->timer.function = &tulip_timer;				/* timer handler */
+	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 	add_timer(&tp->timer);
 
 	return 0;
@@ -1174,8 +1360,8 @@
 		switch (mleaf->type) {
 		case 0:					/* 21140 non-MII xcvr. */
 			if (tulip_debug > 1)
-				printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control"
-					   " setting %2.2x.\n",
+				printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+					   " with control setting %2.2x.\n",
 					   dev->name, p[1]);
 			dev->if_port = p[0];
 			if (startup)
@@ -1183,26 +1369,11 @@
 			outl(p[1], ioaddr + CSR12);
 			new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
 			break;
-		case 1:
-			if (startup) {
-				outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
-				dev->if_port = 11;
-				if (tulip_debug > 2)
-					printk(KERN_DEBUG "%s:  Doing a reset sequence of length %d.\n",
-						   dev->name, p[2 + p[1]]);
-				for (i = 0; i < p[2 + p[1]]; i++)
-					outl(p[3 + p[1] + i], ioaddr + CSR12);
-				if (tulip_debug > 2)
-					printk(KERN_DEBUG "%s  Doing a transceiver setup sequence of length %d.\n",
-						   dev->name, p[1]);
-				for (i = 0; i < p[1]; i++)
-					outl(p[2 + i], ioaddr + CSR12);
-			}
-			check_mii = 1;
-			new_csr6 = 0x020C0000;
-			break;
 		case 2: case 4: {
-			u16 *setup = (u16*)&p[1];
+			u16 setup[3];
+			for (i = 0; i < 3; i++)
+				setup[i] = get_u16(&p[i*2 + 1]);
+
 			dev->if_port = p[0] & 15;
 			if (tulip_debug > 1)
 				printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
@@ -1212,56 +1383,74 @@
 				outl(setup[1], ioaddr + CSR14);
 				outl(setup[2], ioaddr + CSR15);
 				outl(setup[0], ioaddr + CSR13);
-				setup += 3;
-			} else {
+				for (i = 0; i < 3; i++)			/* Re-fill setup[]  */
+					setup[i] = get_u16(&p[i*2 + 7]);
+			} else if (dev->if_port <= 4) {
 				outl(0, ioaddr + CSR13);
 				outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
 				outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
 				outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+			} else {
+				outl(0, ioaddr + CSR14);
+				outl(8, ioaddr + CSR15);
+				outl(0, ioaddr + CSR13);
 			}
 			outl(setup[0]<<16, ioaddr + CSR15);	/* Direction */
 			outl(setup[1]<<16, ioaddr + CSR15);	/* Data */
-			new_csr6 = 0x02000000;
+			if (mleaf->type == 4)
+				new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
+			else
+				new_csr6 = 0x82420000;
 			break;
 		}
-		case 3: {
+		case 1: case 3: {
+			int phy_num = p[0];
 			int init_length = p[1];
-			u16 * init_sequence = (u16*)(p + 2);
-			int reset_length = p[2 + init_length*2];
-			u16 * reset_sequence = (u16*)&p[3 + init_length*2];
+			u16 *misc_info;
+			u16 to_advertise;
 
 			dev->if_port = 11;
-			if (startup) {
-				if (tulip_debug > 2)
-					printk(KERN_DEBUG "%s:  Doing a 21142 reset sequence of length %d.\n",
-						   dev->name, reset_length);
-				for (i = 0; i < reset_length; i++)
-					outl(reset_sequence[i] << 16, ioaddr + CSR15);
-			}
-			if (tulip_debug > 2)
-				printk(KERN_DEBUG "%s: Doing a 21142 xcvr setup sequence of length %d.\n",
-					   dev->name, init_length);
-			for (i = 0; i < init_length; i++)
-				outl(init_sequence[i] << 16, ioaddr + CSR15);
 			check_mii = 1;
-			new_csr6 = 0x020C0000;
+			new_csr6 = 0x020E0000;
+			if (mleaf->type == 3) {	/* 21142 */
+				u16 *init_sequence = (u16*)(p+2);
+				u16 *reset_sequence = &((u16*)(p+3))[init_length];
+				int reset_length = p[2 + init_length*2];
+				misc_info = reset_sequence + reset_length;
+				if (startup)
+					for (i = 0; i < reset_length; i++)
+						outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+				for (i = 0; i < init_length; i++)
+					outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+			} else {
+				u8 *init_sequence = p + 2;
+				u8 *reset_sequence = p + 3 + init_length;
+				int reset_length = p[2 + init_length];
+				misc_info = (u16*)(reset_sequence + reset_length);
+				if (startup) {
+					outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+					for (i = 0; i < reset_length; i++)
+						outl(reset_sequence[i], ioaddr + CSR12);
+				}
+				for (i = 0; i < init_length; i++)
+					outl(init_sequence[i], ioaddr + CSR12);
+			}
+			to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+			tp->advertising[phy_num] = to_advertise;
+			if (tulip_debug > 1 || 1)
+				printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d (%d).\n",
+					   dev->name, to_advertise, phy_num, tp->phys[phy_num]);
+			/* Bogus: put in by a committee?  */
+			mdio_write(ioaddr, tp->phys[phy_num], 4, to_advertise);
 			break;
 		}
 		default:
-		  new_csr6 = 0x020C0000;
+		  new_csr6 = 0x020E0000;
 		}
 		if (tulip_debug > 1)
 			printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
 				   dev->name, medianame[dev->if_port],
 				   inl(ioaddr + CSR12) & 0xff);
-	} else if (tp->chip_id == DC21140) {
-		/* Set media type to MII @ 100mbps: 0x020C0000 */
-		new_csr6 = 0x020C0000;
-		dev->if_port = 11;
-		if (tulip_debug > 1) {
-			printk(KERN_DEBUG "%s: Unknown media control, assuming MII, CSR12 %2.2x.\n",
-				   dev->name, inl(ioaddr + CSR12) & 0xff);
-		}
 	} else if (tp->chip_id == DC21041) {
 		if (tulip_debug > 1)
 			printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
@@ -1272,7 +1461,33 @@
 		outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
 		outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
 		new_csr6 = 0x80020000;
-	} else {					/* 21040 */
+	} else if (tp->chip_id == LC82C168) {
+		if (startup)
+			dev->if_port = 0;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: LiteOn PHY status is %3.3x, CSR12 %4.4x,"
+				   " media %s.\n",
+				   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
+				   medianame[dev->if_port]);
+		if (startup) {
+			/* Start with 10mbps to do autonegotiation. */
+			outl(0x32, ioaddr + CSR12);
+			new_csr6 = 0x00420000;
+			outl(0x0001B078, ioaddr + 0xB8);
+			outl(0x0201B078, ioaddr + 0xB8);
+		} else if (dev->if_port == 3  ||  dev->if_port == 5) {
+			outl(0x33, ioaddr + CSR12);
+			new_csr6 = 0x01860000;
+			if (startup)
+				outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */
+			else
+				outl(0x1F868, ioaddr + 0xB8);
+		} else {
+			outl(0x32, ioaddr + CSR12);
+			new_csr6 = 0x00420000;
+			outl(0x1F078, ioaddr + 0xB8);
+		}
+	} else if (tp->chip_id == DC21040) {					/* 21040 */
 		/* Turn on the xcvr interface. */
 		int csr12 = inl(ioaddr + CSR12);
 		if (tulip_debug > 1)
@@ -1283,6 +1498,23 @@
 		outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
 		outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
 		outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+	} else {					/* Unknown chip type with no media table. */
+		if (tp->default_port == 0)
+			if (tp->mii_cnt) {
+				dev->if_port = 11;
+			} else
+				dev->if_port = 3;
+		if (media_cap[dev->if_port] & MediaIsMII) {
+			new_csr6 = 0x020E0000;
+		} else if (media_cap[dev->if_port] & MediaIsFx) {
+			new_csr6 = 0x028600000;
+		} else
+			new_csr6 = 0x038600000;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: No media description table, assuming "
+				   "%s transceiver, CSR12 %2.2x.\n",
+				   dev->name, medianame[dev->if_port],
+				   inl(ioaddr + CSR12));
 	}
 
 	tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
@@ -1357,125 +1589,262 @@
 		  break;
 		}
 		break;
-	case DC21140:  case DC21142: {
+	case DC21140:  case DC21142: case MX98713: default: {
 		struct medialeaf *mleaf;
 		unsigned char *p;
 		if (tp->mtable == NULL) {	/* No EEPROM info, use generic code. */
-			/* Assume this is like a SMC card, and check its link beat bit. */
-			if ((dev->if_port == 0 && (csr12 & 0x0080)) ||
-				(dev->if_port == 1 && (csr12 & 0x0040) == 0)) {
-				dev->if_port ^= 1;
-				/* Stop the transmit process. */
-				tp->csr6 = (dev->if_port ? 0x03860000 : 0x02420000);
-				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-				printk(KERN_INFO "%s: link beat timed out, CSR12 is 0x%2.2x, switching to"
-					   " %s media.\n", dev->name,
-					   csr12 & 0xff,
-					   dev->if_port ? "100baseTx" : "10baseT");
-				outl(tp->csr6 | 0xA002, ioaddr + CSR6);
-				dev->trans_start = jiffies;
-				next_tick = (24*HZ)/10;
-			} else {
-				next_tick = 10*HZ;
-				if (tulip_debug > 2)
-					printk(KERN_DEBUG "%s: network media monitor 0x%2.2x, link"
-						   " beat detected as %s.\n", dev->name,
-						   csr12 & 0xff,
-						   dev->if_port ? "100baseTx" : "10baseT");
+			/* Not much that can be done.
+			   Assume this a generic MII or SYM transceiver. */
+			next_tick = 60*HZ;
+			if (tulip_debug > 2)
+				printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+					   "CSR12 0x%2.2x.\n",
+					   dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+			break;
+		}
+		mleaf = &tp->mtable->mleaf[tp->cur_index];
+		p = mleaf->leafdata;
+		switch (mleaf->type) {
+		case 0: case 4: {
+			/* Type 0 serial or 4 SYM transceiver.  Check the link beat bit. */
+			int offset = mleaf->type == 4 ? 5 : 2;
+			s8 bitnum = p[offset];
+			if (p[offset+1] & 0x80) {
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG"%s: Transceiver monitor tick "
+						   "CSR12=%#2.2x, no media sense.\n",
+						   dev->name, csr12);
+				if (mleaf->type == 4) {
+					if (mleaf->media == 3 && (csr12 & 0x02))
+						goto select_next_media;
+				}
+				break;
+			}
+			if (tulip_debug > 2)
+				printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+					   " bit %d is %d, expecting %d.\n",
+					   dev->name, csr12, (bitnum >> 1) & 7,
+					   (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+					   (bitnum >= 0));
+			/* Check that the specified bit has the proper value. */
+			if ((bitnum < 0) !=
+				((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+						   medianame[mleaf->media]);
+				if ((p[2] & 0x61) == 0x01)	/* Bogus Znyx board. */
+					goto actually_mii;
+				break;
+			}
+			if (tp->medialock)
+				break;
+	  select_next_media:
+			if (--tp->cur_index < 0) {
+				/* We start again, but should instead look for default. */
+				tp->cur_index = tp->mtable->leafcount - 1;
+			}
+			dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+			if (media_cap[dev->if_port] & MediaIsFD)
+				goto select_next_media; /* Skip FD entries. */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: No link beat on media %s,"
+					   " trying transceiver type %s.\n",
+					   dev->name, medianame[mleaf->media & 15],
+					   medianame[tp->mtable->mleaf[tp->cur_index].media]);
+			select_media(dev, 0);
+			/* Restart the transmit process. */
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			next_tick = (24*HZ)/10;
+			break;
+		}
+		case 1:  case 3: {		/* 21140, 21142 MII */
+			int mii_reg1, mii_reg5;
+		actually_mii:
+			mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
+			mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
+			if (tulip_debug > 1)
+				printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+					   "%4.4x, CSR12 %2.2x, %cD.\n",
+					   dev->name, mii_reg1, mii_reg5, csr12,
+					   tp->full_duplex ? 'F' : 'H');
+			if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0) {
+				int new_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
+				if ((new_reg1 & 0x0004) == 0)
+					printk(KERN_INFO "%s: No link beat on the MII interface,"
+						   " status then %4.4x now %4.4x.\n",
+						   dev->name, mii_reg1, new_reg1);
+#ifdef notyet
+				goto select_next_media;
+#endif
 			}
+			if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
+				;				/* No MII device or no link partner report */
+			else if (tp->full_duplex_lock)
+				;
+			else {
+				int negotiated = mii_reg5 & tp->advertising[0];
+				int duplex = ((negotiated & 0x0100) != 0
+							  || (negotiated & 0x00C0) == 0x0040);
+				/* 100baseTx-FD  or  10T-FD, but not 100-HD */
+				if (tp->full_duplex != duplex) {
+					tp->full_duplex = duplex;
+					if (tp->full_duplex)
+						tp->csr6 |= 0x0200;
+					else
+						tp->csr6 &= ~0x0200;
+					outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+					outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+					if (tulip_debug > 0) /* Gurppp, should be >1 */
+						printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+							   " Xcvr #%d parter capability of %4.4x.\n",
+							   dev->name, tp->full_duplex ? "full" : "half",
+							   tp->phys[0], mii_reg5);
+				}
+			}
+			next_tick = 60*HZ;
 			break;
 		}
-	  mleaf = &tp->mtable->mleaf[tp->cur_index];
-	  p = mleaf->leafdata;
-	  switch (mleaf->type) {
-	  case 0: case 4: {
-		/* Type 0 non-MII or #4 SYM transceiver.  Check the link beat bit. */
-		  s8 bitnum = p[mleaf->type == 4 ? 5 : 2];
-		  if (tulip_debug > 2)
-			  printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is"
-					 " %d, expecting %d.\n",
-					 dev->name, csr12, (bitnum >> 1) & 7,
-					 (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
-					 (bitnum >= 0));
-		  /* Check that the specified bit has the proper value. */
-		  if ((bitnum < 0) !=
-			  ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
-			  if (tulip_debug > 1)
-				  printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
-						 medianame[mleaf->media]);
-			  break;
-		  }
-		  if (tp->medialock)
+		case 2:					/* 21142 serial block has no link beat. */
+		default:
 			break;
-	  select_next_media:
-		  if (--tp->cur_index < 0) {
-			/* We start again, but should instead look for default. */
-			tp->cur_index = tp->mtable->leafcount - 1;
-		  }
-		  dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
-		  if (media_fd[dev->if_port])
-			goto select_next_media; /* Skip FD entries. */
-		  if (tulip_debug > 1)
-			  printk(KERN_DEBUG "%s: No link beat on media %s,"
-					 " trying transceiver type %s.\n",
-					 dev->name, medianame[mleaf->media & 15],
-					 medianame[tp->mtable->mleaf[tp->cur_index].media]);
-		  select_media(dev, 0);
-		  /* Restart the transmit process. */
-		  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-		  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-		  next_tick = (24*HZ)/10;
-		  break;
-	  }
-	  case 1:
-		  {
-			  int mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
-			  printk(KERN_INFO "%s: MII monitoring tick: CSR12 %2.2x, "
-					 "Link partner report %4.4x.\n",
-					 dev->name, csr12, mii_reg5);
-			  if (mii_reg5 != 0xffff
-				  && mdio_read(ioaddr, tp->phys[0], 1) & 0x0020) {
-				  int full_duplex = mii_reg5 & 0x0100 ? 1 : 0;
-				  if (full_duplex != tp->full_duplex) {
-					  tp->full_duplex = full_duplex;
-					  tp->csr6 ^= 0x0200;
-					  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-					  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-				  }
-				  if (tulip_debug > 0) /* Gurppp, should be >1 */
-					  printk(KERN_INFO "%s: Setting %s-duplex based on MII"
-							 " Xcvr #%d partner capability of %4.4x.\n",
-							 dev->name, full_duplex ? "full" : "half",
-							 tp->phys[0], mii_reg5);
-			  }
-		  }
+		}
+	}
+	break;
+	}
+	if (next_tick) {
+		tp->timer.expires = RUN_AT(next_tick);
+		add_timer(&tp->timer);
+	}
+}
 
-		  /* Hack for D-Link: Full duplex indication is on bit 3. */
-		  if (dev->dev_addr[0] == 0  &&  dev->dev_addr[1] == 0x80
-			  && dev->dev_addr[2] == 0xC8) {
-			  if (csr12 & 0x08) {
-				  tp->full_duplex = 0;
-				  tp->csr6 &= ~0x0200;
-				  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-				  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-			  } else {
-				  tp->full_duplex = 1;
-				  tp->csr6 |= 0x0200;
-				  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-				  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-			  }
-		  }
-		  break;
-	  case 2:					/* 21142 non-MII */
-	  case 3:					/* 21142 MII */
-		  next_tick = (24*HZ)/10;
-		  break;
-	  default:
-		  break;
-	  }
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+   of available transceivers.  */
+static void t21142_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+	int next_tick = 60*HZ;
+	int new_csr6 = 0;
+
+	if (tulip_debug > 1)
+		printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+			   dev->name, csr12, medianame[dev->if_port]);
+	if (dev->if_port == 3) {
+		if (csr12 & 2) {		/* No 100mbps link beat, revert to 10mbps. */
+			new_csr6 = 0x82420200;
+			outl(new_csr6, ioaddr + CSR6);
+			outl(0x0000, ioaddr + CSR13);
+			outl(0x0003FFFF, ioaddr + CSR14);
+			outl(0x0008, ioaddr + CSR15);
+			outl(0x0001, ioaddr + CSR13);
+			outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+		}
+	} else if ((csr12 & 0x7000) != 0x5000) {
+		/* Negotiation failed.  Search media types. */
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+				   dev->name, csr12);
+		if (!(csr12 & 4)) {		/* 10mbps link beat good. */
+			new_csr6 = 0x82420000;
+			dev->if_port = 0;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FFFF, ioaddr + CSR14);
+			outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+			outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+		} else if (csr12 & 0x100) {
+			new_csr6 = 0x82420200;
+			dev->if_port = 2;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FFFF, ioaddr + CSR14);
+			outl(0x0008, ioaddr + CSR15);
+			outl(0x0001, ioaddr + CSR13);
+		} else {
+			/* Select 100mbps port to check for link beat. */
+			new_csr6 = 0x83860000;
+			dev->if_port = 3;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FF7F, ioaddr + CSR14);
+			outl(8, ioaddr + CSR15);
+			outl(1, ioaddr + CSR13);
+		}
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+				   dev->name, medianame[dev->if_port]);
+		if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+			tp->csr6 &= 0x00D5;
+			tp->csr6 |= new_csr6;
+			outl(0x0301, ioaddr + CSR12);
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		}
 	}
-	default:					/* Invalid chip type. */
-	  break;
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void t21142_lnk_change( struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+
+	if (tulip_debug > 1)
+		printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
+			   dev->name, csr12, inl(ioaddr + CSR5));
+
+	if ((csr12 & 0x7000) == 0x5000) {
+		if (csr12 & 0x01800000) {
+			/* Switch to 100mbps mode. */
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+			if (csr12 & 0x01000000) {
+				dev->if_port = 5;
+				tp->csr6 = 0x83860200;
+			} else {
+				dev->if_port = 3;
+				tp->csr6 = 0x83860000;
+			}
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		} /* Else 10baseT-FD is handled automatically. */
+	} else if (dev->if_port == 3) {
+		if (!(csr12 & 2))
+			printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
+				   dev->name);
+		else
+			dev->if_port = 0;
+	} else if (dev->if_port == 0) {
+		if (!(csr12 & 4))
+			printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+				   dev->name);
+	} else if (!(csr12 & 4)) {		/* 10mbps link beat good. */
+			printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+				   dev->name);
+			dev->if_port = 0;
+	} else  {		/* 100mbps link beat good. */
+		printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
+			   dev->name);
+		dev->if_port = 3;
+		tp->csr6 = 0x83860000;
+		outl(0x0003FF7F, ioaddr + CSR14);
+		outl(0x0301, ioaddr + CSR12);
+		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	}
+}
+	
+
+static void mxic_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+
+	if (tulip_debug > 3) {
+		printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+			   inl(ioaddr + CSR12));
 	}
 	if (next_tick) {
 		tp->timer.expires = RUN_AT(next_tick);
@@ -1483,6 +1852,59 @@
 	}
 }
 
+static void pnic_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+	int phy_reg = inl(ioaddr + 0xB8);
+	int next_tick = 60*HZ;
+	int duplex;
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
+			   dev->name, phy_reg, inl(ioaddr + CSR5));
+	if (tp->full_duplex_lock)
+		return;				/* Do not bother to set timer. */
+	duplex = phy_reg & 0x30000000 ? 1 : 0;
+	if (tp->full_duplex != duplex) {
+		tp->full_duplex = duplex;
+		if (tp->full_duplex)
+			tp->csr6 |= 0x0200;
+		else
+			tp->csr6 &= ~0x0200;
+		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		if (tulip_debug > 0) /* Gurppp, should be >1 */
+			printk(KERN_INFO "%s: Setting %s-duplex based on"
+				   " PNIC PHY report of %8.8x.\n",
+				   dev->name, tp->full_duplex ? "full" : "half", phy_reg);
+	}
+	if (phy_reg & 0x04000000) {	/* Remote link fault */
+		/*outl(0x0201F078, ioaddr + 0xB8);*/
+		next_tick = 3*HZ;
+	}
+	if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+				   "CSR5 %8.8x, PHY %3.3x.\n",
+				   dev->name, medianame[dev->if_port], csr12,
+				   inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+		if (dev->if_port == 0) {
+			dev->if_port = 3;
+		} else
+			dev->if_port = 0;
+		next_tick = 3*HZ;
+		select_media(dev, 0);
+		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		dev->trans_start = jiffies;
+	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
 static void tulip_tx_timeout(struct device *dev)
 {
   struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1502,20 +1924,6 @@
 	  }
 	  dev->trans_start = jiffies;
 	  return;
-  } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142) {
-	/* Stop the transmit process. */
-	outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-	dev->if_port ^= 1;
-	printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
-		   "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
-		   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
-		   inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
-	printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
-		   dev->name, dev->if_port ? "100baseTx" : "10baseT");
-	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-	tp->stats.tx_errors++;
-	dev->trans_start = jiffies;
-	return;
   } else if (tp->chip_id == DC21041) {
 	u32 csr12 = inl(ioaddr + CSR12);
 
@@ -1535,6 +1943,27 @@
 	tp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	return;
+  } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+			 || tp->chip_id == MX98713) {
+	  /* Stop the transmit process. */
+	  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+	  printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+			 "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+			 dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+			 inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+	  if (tp->mtable) {
+		  if (--tp->cur_index < 0) {
+			  /* We start again, but should instead look for default. */
+			  tp->cur_index = tp->mtable->leafcount - 1;
+		  }
+		  select_media(dev, 0);
+		  printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
+				 dev->name, dev->if_port ? "100baseTx" : "10baseT");
+	  }
+	  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	  tp->stats.tx_errors++;
+	  dev->trans_start = jiffies;
+	  return;
   } else
 	printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
 		   " resetting...\n",
@@ -1616,15 +2045,6 @@
 	int entry;
 	u32 flag;
 
-#ifndef final_version
-	if (skb == NULL || skb->len <= 0) {
-		printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n",
-			   dev->name);
-		dev_tint(dev);
-		return 0;
-	}
-#endif
-
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
@@ -1681,20 +2101,31 @@
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
 #endif
 
-	struct tulip_private *lp;
-	int csr5, ioaddr, boguscnt = 12;
+	struct tulip_private *tp;
+	int csr5, ioaddr, work_budget = max_interrupt_work;
 
 	if (dev == NULL) {
-		printk ("tulip_interrupt(): irq %d for unknown device.\n", irq);
+		printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
+				irq);
 		return;
 	}
 
 	ioaddr = dev->base_addr;
-	lp = (struct tulip_private *)dev->priv;
-	if (dev->interrupt)
+	tp = (struct tulip_private *)dev->priv;
+	if (test_and_set_bit(0, (void*)&tp->interrupt)) {
+#ifdef SMP_CHECK
+		printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
+			   " proc %d already handling.\n", dev->name,
+			   tp->smp_proc_id, hard_smp_processor_id());
+#else
 		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-
+		return;
+#endif
+	}
 	dev->interrupt = 1;
+#ifdef SMP_CHECK
+	tp->smp_proc_id = hard_smp_processor_id();
+#endif
 
 	do {
 		csr5 = inl(ioaddr + CSR5);
@@ -1705,23 +2136,24 @@
 			printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
 				   dev->name, csr5, inl(dev->base_addr + CSR5));
 
-		if ((csr5 & 0x00018000) == 0)
+		if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
 			break;
 
-		if (csr5 & 0x0040)			/* Rx interrupt */
-			tulip_rx(dev);
+		if (csr5 & (RxIntr | RxNoBuf))
+			work_budget -= tulip_rx(dev);
 
-		if (csr5 & 0x0007) {		/* Tx-done interrupt */
-			int dirty_tx;
+		if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+			unsigned int dirty_tx;
 
-			for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
+			for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+				 dirty_tx++) {
 				int entry = dirty_tx % TX_RING_SIZE;
-				int status = lp->tx_ring[entry].status;
+				int status = tp->tx_ring[entry].status;
 
 				if (status < 0)
 					break;			/* It still hasn't been Txed */
 				/* Check for Rx filter setup frames. */
-				if (lp->tx_skbuff[entry] == NULL)
+				if (tp->tx_skbuff[entry] == NULL)
 				  continue;
 
 				if (status & 0x8000) {
@@ -1731,74 +2163,96 @@
 						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
 							   dev->name, status);
 #endif
-					lp->stats.tx_errors++;
-					if (status & 0x4104) lp->stats.tx_aborted_errors++;
-					if (status & 0x0C00) lp->stats.tx_carrier_errors++;
-					if (status & 0x0200) lp->stats.tx_window_errors++;
-					if (status & 0x0002) lp->stats.tx_fifo_errors++;
-					if ((status & 0x0080) && lp->full_duplex == 0)
-						lp->stats.tx_heartbeat_errors++;
+					tp->stats.tx_errors++;
+					if (status & 0x4104) tp->stats.tx_aborted_errors++;
+					if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+					if (status & 0x0200) tp->stats.tx_window_errors++;
+					if (status & 0x0002) tp->stats.tx_fifo_errors++;
+					if ((status & 0x0080) && tp->full_duplex == 0)
+						tp->stats.tx_heartbeat_errors++;
 #ifdef ETHER_STATS
-					if (status & 0x0100) lp->stats.collisions16++;
+					if (status & 0x0100) tp->stats.collisions16++;
 #endif
 				} else {
 #ifdef ETHER_STATS
-					if (status & 0x0001) lp->stats.tx_deferred++;
+					if (status & 0x0001) tp->stats.tx_deferred++;
+#endif
+#if LINUX_VERSION_CODE > 0x20127
+					tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
 #endif
-					lp->stats.collisions += (status >> 3) & 15;
-					lp->stats.tx_packets++;
+					tp->stats.collisions += (status >> 3) & 15;
+					tp->stats.tx_packets++;
 				}
 
 				/* Free the original skb. */
-				dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
-				lp->tx_skbuff[entry] = 0;
+#if (LINUX_VERSION_CODE > 0x20155)
+				dev_kfree_skb(tp->tx_skbuff[entry]);
+#else
+				dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+#endif
+				tp->tx_skbuff[entry] = 0;
 			}
 
 #ifndef final_version
-			if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+			if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
 				printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
 				dirty_tx += TX_RING_SIZE;
 			}
 #endif
 
-			if (lp->tx_full && dev->tbusy
-				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+			if (tp->tx_full && dev->tbusy
+				&& tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2) {
 				/* The ring is no longer full, clear tbusy. */
-				lp->tx_full = 0;
+				tp->tx_full = 0;
 				dev->tbusy = 0;
 				mark_bh(NET_BH);
 			}
 
-			lp->dirty_tx = dirty_tx;
+			tp->dirty_tx = dirty_tx;
 		}
 
 		/* Log errors. */
-		if (csr5 & 0x8000) {	/* Abnormal error summary bit. */
-			if (csr5 & 0x0008) lp->stats.tx_errors++; /* Tx babble. */
-			if (csr5 & 0x0020) { /* Tx FIFO underflow. */
-			  lp->csr6 |= 0x00200000;  /* Reconfigure to store-n-forward. */
-			  /* Restart the transmit process. */
-			  outl(lp->csr6 | 0x0002, ioaddr + CSR6);
-			  outl(lp->csr6 | 0x2002, ioaddr + CSR6);
-			}
-			if (csr5 & 0x0100) {		/* Missed a Rx frame. */
-				lp->stats.rx_errors++;
-				lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+		if (csr5 & AbnormalIntr) {	/* Abnormal error summary bit. */
+			if (csr5 & TxJabber) tp->stats.tx_errors++;
+			if (csr5 & TxFIFOUnderflow) {
+				if ((tp->csr6 & 0xC000) != 0xC000)
+					tp->csr6 += 0x4000;	/* Bump up the Tx threshold */
+				else
+					tp->csr6 |= 0x00200000;  /* Store-n-forward. */
+				/* Restart the transmit process. */
+				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			}
+			if (csr5 & RxDied) {		/* Missed a Rx frame. */
+				tp->stats.rx_errors++;
+				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 			}
-			if (csr5 & 0x0800) {
+			if (csr5 & TimerInt) {
 				printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
 					   dev->name, csr5);
 				/* Hmmmmm, it's not clear what to do here. */
 			}
+			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
+				&& tp->chip_id == DC21142) {
+				if (tulip_debug > 1)
+					printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
+						   dev->name, csr5);
+				t21142_lnk_change(dev);
+			}
 			/* Clear all error sources, included undocumented ones! */
-			outl(0x000f7ba, ioaddr + CSR5);
+			outl(0x0800f7ba, ioaddr + CSR5);
 		}
-		if (--boguscnt < 0) {
-			printk(KERN_WARNING "%s: Too much work at interrupt, csr5=0x%8.8x.\n",
-				   dev->name, csr5);
-			/* Clear all interrupt sources. */
-			outl(0x0001ffff, ioaddr + CSR5);
+		if (--work_budget < 0) {
+			if (tulip_debug > 1)
+				printk(KERN_WARNING "%s: Too much work at interrupt, "
+					   "csr5=0x%8.8x.\n", dev->name, csr5);
+			/* Acknowledge all interrupt sources. */
+			outl(0x8001ffff, ioaddr + CSR5);
+#ifdef notdef
+			/* Clear all but standard interrupt sources. */
+			outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#endif
 			break;
 		}
 	} while (1);
@@ -1807,6 +2261,7 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
 			   dev->name, inl(ioaddr + CSR5));
 
+#ifdef notdef
 	/* Code that should never be run!  Perhaps remove after testing.. */
 	{
 		static int stopit = 10;
@@ -1822,95 +2277,84 @@
 #endif
 		}
 	}
+#endif
 
 	dev->interrupt = 0;
+	clear_bit(0, (void*)&tp->interrupt);
 	return;
 }
 
 static int
 tulip_rx(struct device *dev)
 {
-	struct tulip_private *lp = (struct tulip_private *)dev->priv;
-	int entry = lp->cur_rx % RX_RING_SIZE;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int entry = tp->cur_rx % RX_RING_SIZE;
+	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+	int work_done = 0;
 
 	if (tulip_debug > 4)
 		printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
-			   lp->rx_ring[entry].status);
+			   tp->rx_ring[entry].status);
 	/* If we own the next entry, it's a new packet. Send it up. */
-	while (lp->rx_ring[entry].status >= 0) {
-		int status = lp->rx_ring[entry].status;
+	while (tp->rx_ring[entry].status >= 0) {
+		s32 status = tp->rx_ring[entry].status;
 
+		if (--rx_work_limit < 0)
+			break;
 		if ((status & 0x0300) != 0x0300) {
 			if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
-			  printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-					 "multiple buffers, status %8.8x!\n", dev->name, status);
-			  lp->stats.rx_length_errors++;
+				if (tulip_debug > 1)
+					printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
+						   "multiple buffers, status %8.8x!\n",
+						   dev->name, status);
+			  tp->stats.rx_length_errors++;
 			}
 		} else if (status & 0x8000) {
 			/* There was a fatal error. */
-			lp->stats.rx_errors++; /* end of a packet.*/
-			if (status & 0x0890) lp->stats.rx_length_errors++;
-			if (status & 0x0004) lp->stats.rx_frame_errors++;
-			if (status & 0x0002) lp->stats.rx_crc_errors++;
-			if (status & 0x0001) lp->stats.rx_fifo_errors++;
+			tp->stats.rx_errors++; /* end of a packet.*/
+			if (status & 0x0890) tp->stats.rx_length_errors++;
+			if (status & 0x0004) tp->stats.rx_frame_errors++;
+			if (status & 0x0002) tp->stats.rx_crc_errors++;
+			if (status & 0x0001) tp->stats.rx_fifo_errors++;
 		} else {
-			/* Malloc up new buffer, compatible with net-2e. */
 			/* Omit the four octet CRC from the length. */
-			short pkt_len = (lp->rx_ring[entry].status >> 16) - 4;
+			short pkt_len = (status >> 16) - 4;
 			struct sk_buff *skb;
-			int rx_in_place = 0;
 
 			/* Check if the packet is long enough to just accept without
 			   copying to a properly sized skbuff. */
-			if (pkt_len > rx_copybreak) {
-				struct sk_buff *newskb;
-				char *temp;
-
-				/* Get a fresh skbuff to replace the filled one. */
-				newskb = DEV_ALLOC_SKB(PKT_BUF_SZ);
-				if (newskb == NULL) {
-					skb = 0;		/* No memory, drop the packet. */
-					goto memory_squeeze;
-				}
-				/* Pass up the skb already on the Rx ring. */
-				skb = lp->rx_skbuff[entry];
-				temp = skb_put(skb, pkt_len);
-				if (bus_to_virt(lp->rx_ring[entry].buffer1) != temp)
-					printk(KERN_ERR "%s: Internal consistency error -- the "
-						   "skbuff addresses do not match"
-						   " in tulip_rx: %p vs. %p / %p.\n", dev->name,
-						   bus_to_virt(lp->rx_ring[entry].buffer1),
-						   skb->head, temp);
-				rx_in_place = 1;
-				lp->rx_skbuff[entry] = newskb;
-				newskb->dev = dev;
-				/* Longword alignment required: do not skb_reserve(2)! */
-				lp->rx_ring[entry].buffer1 = virt_to_bus(newskb->tail);
-			} else
-				skb = DEV_ALLOC_SKB(pkt_len + 2);
-			memory_squeeze:
-			if (skb == NULL) {
-				int i;
-				printk(KERN_WARNING "%s: Memory squeeze, deferring packet.\n",
-					   dev->name);
-				/* Check that at least two ring entries are free.
-				   If not, free one and mark stats->rx_dropped++. */
-				for (i = 0; i < RX_RING_SIZE; i++)
-					if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
-						break;
-
-				if (i > RX_RING_SIZE -2) {
-					lp->stats.rx_dropped++;
-					lp->rx_ring[entry].status = 0x80000000;
-					lp->cur_rx++;
-				}
-				break;
-			}
-			skb->dev = dev;
-			if (! rx_in_place) {
-				skb_reserve(skb, 2);	/* 16 byte align the data fields */
+			if (pkt_len < rx_copybreak
+				&& (skb = DEV_ALLOC_SKB(pkt_len+2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+#if LINUX_VERSION_CODE < 0x10300
+				memcpy(skb->data, tp->rx_ring[entry].buffer1, pkt_len);
+#elif LINUX_VERSION_CODE < 0x20200  || defined(__alpha__)
 				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(lp->rx_ring[entry].buffer1), pkt_len);
+					   bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
+#else
+#warning Code untested
+				eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+								 pkt_len, 0);
+				skb_put(skb, pkt_len);
+#endif
+				work_done++;
+			} else { 	/* Pass up the skb already on the Rx ring. */
+				skb = tp->rx_skbuff[entry];
+				tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+				{
+					void *temp = skb_put(skb, pkt_len);
+					if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
+						printk(KERN_ERR "%s: Internal consistency error! The "
+						   "skbuff addresses do not match in tulip_rx:"
+							   " %p vs. %p / %p.\n", dev->name,
+							   bus_to_virt(tp->rx_ring[entry].buffer1),
+							   skb->head, temp);
+				}
+#else
+				skb_put(skb, pkt_len);
+#endif
 			}
 #if LINUX_VERSION_CODE > 0x10300
 			skb->protocol = eth_type_trans(skb, dev);
@@ -1918,14 +2362,35 @@
 			skb->len = pkt_len;
 #endif
 			netif_rx(skb);
-			lp->stats.rx_packets++;
+			dev->last_rx = jiffies;
+			tp->stats.rx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+			tp->stats.rx_bytes += pkt_len;
+#endif
 		}
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+	}
 
-		lp->rx_ring[entry].status = 0x80000000;
-		entry = (++lp->cur_rx) % RX_RING_SIZE;
+	/* Refill the Rx ring buffers. */
+	for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+		entry = tp->dirty_rx % RX_RING_SIZE;
+		if (tp->rx_skbuff[entry] == NULL) {
+			struct sk_buff *skb;
+			skb = tp->rx_skbuff[entry] = DEV_ALLOC_SKB(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;
+			skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+#else
+			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
+#endif
+			work_done++;
+		}
+		tp->rx_ring[entry].status = 0x80000000;
 	}
 
-	return 0;
+	return work_done;
 }
 
 static int
@@ -1972,12 +2437,20 @@
 #if LINUX_VERSION_CODE < 0x20100
 			skb->free = 1;
 #endif
+#if (LINUX_VERSION_CODE > 0x20155)
+			dev_kfree_skb(skb);
+#else
 			dev_kfree_skb(skb, FREE_WRITE);
+#endif
 		}
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (tp->tx_skbuff[i])
+#if (LINUX_VERSION_CODE > 0x20155)
+			dev_kfree_skb(tp->tx_skbuff[i]);
+#else
 			dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+#endif
 		tp->tx_skbuff[i] = 0;
 	}
 
@@ -1999,6 +2472,71 @@
 	return &tp->stats;
 }
 
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = tp->phys[0] & 0x1f;
+	long flags;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		if (tp->mtable  &&  tp->mtable->has_mii)
+			data[0] = phy;
+		else if (tp->chip_id == DC21142)
+			data[0] = 32;
+		else
+			return -ENODEV;
+		return 0;
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		if (data[0] == 32) {  /* 21142 pseudo-MII */
+			int csr12 = inl(ioaddr + CSR12);
+			int csr14 = inl(ioaddr + CSR14);
+			switch (data[1]) {
+			case 0: {
+				data[3] = ((csr14<<13)&0x4000) + ((csr14<<5)&0x1000);
+				break; }
+			case 1:
+				data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+					+ (csr12&0x06 ? 0x04 : 0);
+				break;
+			case 4: {
+				int csr14 = inl(ioaddr + CSR14);
+				data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+				break;
+			}
+			case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+			default: data[3] = 0; break;
+			}
+		} else {
+			save_flags(flags);
+			cli();
+			data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+			restore_flags(flags);
+		}
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!suser())
+			return -EPERM;
+		if (data[0] == 32) {  /* 21142 pseudo-MII */
+		} else {
+			save_flags(flags);
+			cli();
+			mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+			restore_flags(flags);
+		}
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+
 /* Set or clear the multicast filter for this adaptor.
    Note that we only use exclusion around actually queueing the
    new frame, not around filling tp->setup_frame.  This is non-deterministic
@@ -2025,12 +2563,10 @@
 	return crc;
 }
 
-
-static void
 #ifdef NEW_MULTICAST
-set_multicast_list(struct device *dev)
+static void set_rx_mode(struct device *dev)
 #else
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
 #endif
 {
 	int ioaddr = dev->base_addr;
@@ -2057,13 +2593,13 @@
 		if (dev->mc_count > 14) { /* Must use a multicast hash table. */
 		  u16 hash_table[32];
 		  memset(hash_table, 0, sizeof(hash_table));
+		  /* This should work on big-endian machines as well. */
 		  for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			   i++, mclist = mclist->next)
-			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
-					hash_table);
+			  set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+					  hash_table);
 		  /* Copy the hash table to the setup frame.
-			 NOTE that only the LOW SHORTWORD of setup_frame[] is valid!
-			 This code may require tweaking for non-x86 architectures!  */
+			 NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */
 		  for (i = 0; i < 32; i++)
 			*setup_frm++ = hash_table[i];
 		  setup_frm += 7;
@@ -2090,9 +2626,9 @@
 		}
 		eaddrs = (u16 *)dev->dev_addr;
 		do {
-		  *setup_frm++ = eaddrs[0];
-		  *setup_frm++ = eaddrs[1];
-		  *setup_frm++ = eaddrs[2];
+			*setup_frm++ = eaddrs[0];
+			*setup_frm++ = eaddrs[1];
+			*setup_frm++ = eaddrs[2];
 		} while (++i < 15);
 		/* Now add this frame to the Tx list. */
 		if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
@@ -2105,19 +2641,19 @@
 			entry = tp->cur_tx++ % TX_RING_SIZE;
 
 			if (entry != 0) {
-			  /* Avoid a chip errata by prefixing a dummy entry. */
-			  tp->tx_skbuff[entry] = 0;
-			  tp->tx_ring[entry].length =
-				(entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
-			  tp->tx_ring[entry].buffer1 = 0;
-			  tp->tx_ring[entry].status = 0x80000000;
-			  entry = tp->cur_tx++ % TX_RING_SIZE;
+				/* Avoid a chip errata by prefixing a dummy entry. */
+				tp->tx_skbuff[entry] = 0;
+				tp->tx_ring[entry].length =
+					(entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+				tp->tx_ring[entry].buffer1 = 0;
+				tp->tx_ring[entry].status = 0x80000000;
+				entry = tp->cur_tx++ % TX_RING_SIZE;
 			}
 
 			tp->tx_skbuff[entry] = 0;
 			/* Put the setup frame on the Tx list. */
 			if (entry == TX_RING_SIZE-1)
-			  tx_flags |= 0x02000000;		/* Wrap ring. */
+				tx_flags |= 0x02000000;		/* Wrap ring. */
 			tp->tx_ring[entry].length = tx_flags;
 			tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
 			tp->tx_ring[entry].status = 0x80000000;
@@ -2133,13 +2669,69 @@
 	}
 }
 
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *tulip_attach(dev_locator_t *loc)
+{
+	u16 dev_id;
+	u32 io;
+	u8 bus, devfn;
+	struct device *dev;
+
+	if (loc->bus != LOC_PCI) return NULL;
+	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+	printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+	io &= ~3;
+	dev = tulip_probe1(bus, devfn, NULL, io, DC21142, -1);
+	if (dev) {
+		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+		strcpy(node->dev_name, dev->name);
+		node->major = node->minor = 0;
+		node->next = NULL;
+		MOD_INC_USE_COUNT;
+		return node;
+	}
+	return NULL;
+}
+
+static void tulip_detach(dev_node_t *node)
+{
+	struct device **devp, **next;
+	printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
+	for (devp = &root_tulip_dev; *devp; devp = next) {
+		next = &((struct tulip_private *)(*devp)->priv)->next_module;
+		if (strcmp((*devp)->name, node->dev_name) == 0) break;
+	}
+	if (*devp) {
+		unregister_netdev(*devp);
+		kfree(*devp);
+		*devp = *next;
+		kfree(node);
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+struct driver_operations tulip_ops = {
+	"tulip_cb", tulip_attach, NULL, NULL, tulip_detach
+};
+
+#endif  /* Cardbus support */
+
+
 #ifdef MODULE
 #if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
 MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(reverse_probe, "i");
 MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 #endif
 
 /* An additional parameter that may be passed in... */
@@ -2151,8 +2743,12 @@
 	if (debug >= 0)
 		tulip_debug = debug;
 
-	root_tulip_dev = NULL;
+#ifdef CARDBUS
+	register_driver(&tulip_ops);
+	return 0;
+#else
 	return tulip_probe(NULL);
+#endif
 }
 
 void
@@ -2160,6 +2756,10 @@
 {
 	struct device *next_dev;
 
+#ifdef CARDBUS
+	unregister_driver(&tulip_ops);
+#endif
+
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_tulip_dev) {
 		next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
@@ -2174,7 +2774,8 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.0.33/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.0.33/linux/drivers/net/yellowfin.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/yellowfin.c	Wed Jun  3 15:17:47 1998
@@ -0,0 +1,1302 @@
+/* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */
+/*
+	Written 1997-1998 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter.
+	It also supports the Symbios Logic version of the same chip core.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html
+*/
+
+static const char *version = "yellowfin.c:v0.99A 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
+
+/* A few user-configurable values. */
+
+static int max_interrupt_work = 20;
+static int min_pci_latency = 64;
+static int mtu = 0;
+#ifdef YF_PROTOTYPE			/* Support for prototype hardware errata. */
+/* System-wide count of bogus-rx frames. */
+static int bogus_rx = 0;
+static int dma_ctrl = 0x004A0263; 			/* Constrained by errata */
+static int fifo_cfg = 0x0020;				/* Bypass external Tx FIFO. */
+#elif YF_NEW					/* A future perfect board :->.  */
+static int dma_ctrl = 0x00CAC277;			/* Override when loading module! */
+static int fifo_cfg = 0x0028;
+#else
+static int dma_ctrl = 0x004A0263; 			/* Constrained by errata */
+static int fifo_cfg = 0x0020;				/* Bypass external Tx FIFO. */
+#endif
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static const rx_copybreak = 100;
+
+/* Keep the ring sizes a power of two for efficiency.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((2000*HZ)/1000)
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+   This is only in the support-all-kernels source code. */
+#include <linux/version.h>		/* Evil, but neccessary */
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr)  ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+
+#else  /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
+#ifdef MODULE
+#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#else
+#undef MOD_INC_USE_COUNT
+#define MOD_INC_USE_COUNT
+#undef MOD_DEC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+#endif /* 1.3.38 */
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#endif
+#if (LINUX_VERSION_CODE >= 0x20100)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#ifdef SA_SHIRQ
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
+static const char *card_name = "Yellowfin G-NIC Gbit Ethernet";
+
+/* The PCI I/O space extent. */
+#define YELLOWFIN_TOTAL_SIZE 0x100
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry yellowfin_drv =
+{card_name, yellowfin_pci_probe, YELLOWFIN_TOTAL_SIZE, NULL};
+#endif
+
+#ifdef YELLOWFIN_DEBUG
+int yellowfin_debug = YELLOWFIN_DEBUG;
+#else
+int yellowfin_debug = 1;
+#endif
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the Packet Engines "Yellowfin" Gigabit
+Ethernet adapter.  The only PCA currently supported is the G-NIC 64-bit
+PCI card.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Yellowfin uses the Descriptor Based DMA Architecture specified by Apple.
+This is a descriptor list scheme similar to that used by the EEPro100 and
+Tulip.  This driver uses two statically allocated fixed-size descriptor lists
+formed into rings by a branch from the final descriptor to the beginning of
+the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
+
+The driver allocates full frame size skbuffs for the Rx ring buffers at
+open() time and passes the skb->data field to the Yellowfin as receive data
+buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
+a fresh skbuff is allocated and the frame is copied to the new skbuff.
+When the incoming frame is larger, the skbuff is passed directly up the
+protocol stack and replaced by a newly allocated skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames.  For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information).  For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data.
+
+IIIC. Synchronization
+
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'yp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'yp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+Thanks to Kim Stearns of Packet Engines for providing a pair of G-NIC boards.
+
+IVb. References
+
+Yellowfin Engineering Design Specification, 4/23/97 Preliminary/Confidential
+http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
+
+IVc. Errata
+
+See Packet Engines confidential appendix.
+
+*/
+
+/* A few values that may be tweaked. */
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+#ifndef PCI_VENDOR_ID_PKT_ENG		/* To be defined in linux/pci.h */
+#define PCI_VENDOR_ID_PKT_ENG			0x1000 /* Hmm, likely number.. */
+#define PCI_DEVICE_ID_YELLOWFIN			0x0702
+#endif
+
+/* The rest of these values should never change. */
+
+static void yellowfin_timer(unsigned long data);
+
+/* Offsets to the Yellowfin registers.  Various sizes and alignments. */
+enum yellowfin_offsets {
+	TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C,
+	TxIntrSel=0x10, TxBranchSel=0x14, TxWaitSel=0x18,
+	RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C,
+	RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58,
+	EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86,
+	ChipRev=0x8C, DMACtrl=0x90, Cnfg=0xA0, RxDepth=0xB8, FlowCtrl=0xBC,
+	AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, FIFOcfg=0xF8,
+};
+
+/* The Yellowfin Rx and Tx buffer descriptors. */
+struct yellowfin_desc {
+	u16 request_cnt;
+	u16 cmd;
+	u32 addr;
+	u32 branch_addr;
+	u16 result_cnt;
+	u16 status;
+};
+
+struct tx_status_words {
+	u16 tx_cnt;
+	u16 tx_errs;
+	u16 total_tx_cnt;
+	u16 paused;
+};
+
+/* Bits in yellowfin_desc.cmd */
+enum desc_cmd_bits {
+	CMD_TX_PKT=0x1000, CMD_RX_BUF=0x2000, CMD_TXSTATUS=0x3000,
+	CMD_NOP=0x6000, CMD_STOP=0x7000,
+	BRANCH_ALWAYS=0x0C, INTR_ALWAYS=0x30, WAIT_ALWAYS=0x03,
+	BRANCH_IFTRUE=0x04,
+};
+
+/* Bits in yellowfin_desc.status */
+enum desc_status_bits { RX_EOP=0x0040, };
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+	IntrRxDone=0x01, IntrRxInvalid=0x02, IntrRxPCIFault=0x04,IntrRxPCIErr=0x08,
+	IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80,
+	IntrEarlyRx=0x100, IntrWakeup=0x200, };
+
+struct yellowfin_private {
+	/* Descriptor rings first for alignment.  Tx requires a second descriptor
+	   for status. */
+	struct yellowfin_desc rx_ring[RX_RING_SIZE];
+	struct yellowfin_desc tx_ring[TX_RING_SIZE*2];
+	const char *product_name;
+	struct device *next_module;
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	struct tx_status_words tx_status[TX_RING_SIZE];
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	int chip_id;
+	struct enet_statistics stats;
+	struct timer_list timer;	/* Media selection timer. */
+	int in_interrupt;
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int medialock:1;			/* Do not sense media. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	u32 pad[4];							/* Used for 32-byte alignment */
+};
+
+#ifdef MODULE
+/* Used to pass the media type, etc. */
+#define MAX_UNITS 8				/* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+#if LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(min_pci_latency, "i");
+MODULE_PARM(mtu, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+#endif
+
+#endif
+
+static struct device *yellowfin_probe1(struct device *dev, int ioaddr, int irq,
+								   int chip_id, int options);
+static int yellowfin_open(struct device *dev);
+static void yellowfin_timer(unsigned long data);
+static void yellowfin_tx_timeout(struct device *dev);
+static void yellowfin_init_ring(struct device *dev);
+static int yellowfin_start_xmit(struct sk_buff *skb, struct device *dev);
+static int yellowfin_rx(struct device *dev);
+static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
+static int yellowfin_close(struct device *dev);
+static struct enet_statistics *yellowfin_get_stats(struct device *dev);
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev);
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+
+#ifdef MODULE
+/* A list of all installed Yellowfin devices, for removing the driver module. */
+static struct device *root_yellowfin_dev = NULL;
+#endif
+
+int yellowfin_probe(struct device *dev)
+{
+	int cards_found = 0;
+	static int pci_index = 0;	/* Static, for multiple probe calls. */
+
+	/* Ideally we would detect all network cards in slot order.  That would
+	   be best done a central PCI probe dispatch, which wouldn't work
+	   well with the current structure.  So instead we detect just the
+	   Yellowfin cards in slot order. */
+
+	if (pcibios_present()) {
+		unsigned char pci_bus, pci_device_fn;
+
+		for (;pci_index < 0xff; pci_index++) {
+			u8 pci_irq_line, pci_latency;
+			u16 pci_command, vendor, device;
+			u32 pci_ioaddr, chip_idx = 0;
+
+#ifdef REVERSE_PROBE_ORDER
+			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+									0xfe - pci_index,
+									&pci_bus, &pci_device_fn)
+				!= PCIBIOS_SUCCESSFUL)
+				continue;
+#else
+			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+									pci_index,
+									&pci_bus, &pci_device_fn)
+				!= PCIBIOS_SUCCESSFUL)
+				break;
+#endif
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_VENDOR_ID, &vendor);
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_DEVICE_ID, &device);
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			/* Remove I/O space marker in bit 0. */
+			pci_ioaddr &= ~3;
+
+			if (vendor != PCI_VENDOR_ID_PKT_ENG)
+				continue;
+
+			if (device != PCI_DEVICE_ID_YELLOWFIN)
+				continue;
+
+			if (yellowfin_debug > 2)
+				printk("Found Packet Engines Yellowfin G-NIC at I/O %#x, IRQ %d.\n",
+					   pci_ioaddr, pci_irq_line);
+
+			if (check_region(pci_ioaddr, YELLOWFIN_TOTAL_SIZE))
+				continue;
+
+#ifdef MODULE
+			dev = yellowfin_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
+						 cards_found < MAX_UNITS ? options[cards_found] : 0);
+#else
+			dev = yellowfin_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
+						 dev ? dev->mem_start : 0);
+#endif
+
+			if (dev) {
+			  /* Get and check the bus-master and latency values. */
+			  pcibios_read_config_word(pci_bus, pci_device_fn,
+									   PCI_COMMAND, &pci_command);
+			  if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+				printk("  PCI Master Bit has not been set! Setting...\n");
+				pci_command |= PCI_COMMAND_MASTER;
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, pci_command);
+			  }
+			  pcibios_read_config_byte(pci_bus, pci_device_fn,
+									   PCI_LATENCY_TIMER, &pci_latency);
+			  if (pci_latency < min_pci_latency) {
+				printk("  PCI latency timer (CFLT) is unreasonably low at %d."
+					   "  Setting to %d clocks.\n",
+					   pci_latency, min_pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, min_pci_latency);
+			  } else if (yellowfin_debug > 1)
+				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
+			  dev = 0;
+			  cards_found++;
+			}
+		}
+	}
+
+#if defined (MODULE)
+	return cards_found;
+#else
+	return 0;
+#endif
+}
+
+static struct device *yellowfin_probe1(struct device *dev, int ioaddr, int irq,
+								   int chip_id, int options)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct yellowfin_private *yp;
+	int i;
+
+	if (yellowfin_debug > 0  &&  did_version++ == 0)
+		printk(version);
+
+	dev = init_etherdev(dev, sizeof(struct yellowfin_private));
+
+	printk("%s: P-E Yellowfin type %8x at %#3x, ",
+		   dev->name, inl(ioaddr + ChipRev), ioaddr);
+
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", inb(ioaddr + StnAddr + i));
+	printk("%2.2x, IRQ %d.\n", inb(ioaddr + StnAddr + i), irq);
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
+
+	/* Reset the chip. */
+	outl(0x80000000, ioaddr + DMACtrl);
+
+
+	/* We do a request_region() only to register /proc/ioports info. */
+	request_region(ioaddr, YELLOWFIN_TOTAL_SIZE, card_name);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* Make certain the descriptor lists are aligned. */
+	yp = (void *)(((long)kmalloc(sizeof(*yp), GFP_KERNEL) + 31) & ~31);
+	memset(yp, 0, sizeof(*yp));
+	dev->priv = yp;
+
+#ifdef MODULE
+	yp->next_module = root_yellowfin_dev;
+	root_yellowfin_dev = dev;
+#endif
+
+	yp->chip_id = chip_id;
+
+	yp->full_duplex = 1;
+#ifdef YELLOWFIN_DEFAULT_MEDIA
+	yp->default_port = YELLOWFIN_DEFAULT_MEDIA;
+#endif
+#ifdef YELLOWFIN_NO_MEDIA_SWITCH
+	yp->medialock = 1;
+#endif
+
+	/* The lower four bits are the media type. */
+	if (options > 0) {
+		yp->full_duplex = (options & 16) ? 1 : 0;
+		yp->default_port = options & 15;
+		if (yp->default_port)
+			yp->medialock = 1;
+	}
+
+	/* The Yellowfin-specific entries in the device structure. */
+	dev->open = &yellowfin_open;
+	dev->hard_start_xmit = &yellowfin_start_xmit;
+	dev->stop = &yellowfin_close;
+	dev->get_stats = &yellowfin_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	if (mtu)
+		dev->mtu = mtu;
+
+	/* todo: Reset the xcvr interface and turn on heartbeat. */
+
+	return dev;
+}
+
+
+static int
+yellowfin_open(struct device *dev)
+{
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	/* Reset the chip. */
+	outl(0x80000000, ioaddr + DMACtrl);
+
+#ifdef SA_SHIRQ
+	if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ,
+					card_name, dev)) {
+		return -EAGAIN;
+	}
+#else
+	if (irq2dev_map[dev->irq] != NULL
+		|| (irq2dev_map[dev->irq] = dev) == NULL
+		|| dev->irq == 0
+		|| request_irq(dev->irq, &yellowfin_interrupt, 0, card_name)) {
+		return -EAGAIN;
+	}
+#endif
+
+	if (yellowfin_debug > 1)
+		printk("%s: yellowfin_open() irq %d.\n", dev->name, dev->irq);
+
+	MOD_INC_USE_COUNT;
+
+	yellowfin_init_ring(dev);
+
+	outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr);
+	outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr);
+
+	/* Set up various condition 'select' registers.
+	   There are no options here. */
+	outl(0x00800080, ioaddr + TxIntrSel); 	/* Interrupt on Tx abort */
+	outl(0x00800080, ioaddr + TxBranchSel);	/* Branch on Tx abort */
+	outl(0x00400040, ioaddr + TxWaitSel); 	/* Wait on Tx status */
+	outl(0x00400040, ioaddr + RxIntrSel);	/* Interrupt on Rx done */
+	outl(0x00400040, ioaddr + RxBranchSel);	/* Branch on Rx error */
+	outl(0x00400040, ioaddr + RxWaitSel);	/* Wait on Rx done */
+
+	/* Initialize other registers: with so many this eventually this will
+	   converted to an offset/value list. */
+	outl(dma_ctrl, ioaddr + DMACtrl);
+	outw(fifo_cfg, ioaddr + FIFOcfg);
+	/* Enable automatic generation of flow control frames, period 0xffff. */
+	outl(0x0030FFFF, ioaddr + FlowCtrl);
+
+	if (dev->if_port == 0)
+		dev->if_port = yp->default_port;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	yp->in_interrupt = 0;
+
+	/* We are always in full-duplex mode with the current chip! */
+	yp->full_duplex = 1;
+
+	/* Setting the Rx mode will start the Rx process. */
+	outw(0x01CD | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
+#ifdef NEW_MULTICAST
+	set_rx_mode(dev);
+#else
+	set_rx_mode(dev, 0, 0);
+#endif
+
+	dev->start = 1;
+
+	/* Enable interrupts by setting the interrupt mask. */
+	outw(0x81ff, ioaddr + IntrEnb);			/* See enum intr_status_bits */
+	outw(0x0000, ioaddr + EventStatus);		/* Clear non-interrupting events */
+	outl(0x80008000, ioaddr + RxCtrl);		/* Start Rx and Tx channels. */
+	outl(0x80008000, ioaddr + TxCtrl);
+
+	if (yellowfin_debug > 2) {
+		printk("%s: Done yellowfin_open().\n",
+			   dev->name);
+	}
+	/* Set the timer to check for link beat. */
+	init_timer(&yp->timer);
+	yp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
+	yp->timer.data = (unsigned long)dev;
+	yp->timer.function = &yellowfin_timer;				/* timer handler */
+	add_timer(&yp->timer);
+
+	return 0;
+}
+
+static void yellowfin_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int next_tick = 0;
+
+	if (yellowfin_debug > 3) {
+		printk("%s: Yellowfin timer tick, status %8.8x.\n",
+			   dev->name, inl(ioaddr + IntrStatus));
+	}
+	if (next_tick) {
+		yp->timer.expires = RUN_AT(next_tick);
+		add_timer(&yp->timer);
+	}
+}
+
+static void yellowfin_tx_timeout(struct device *dev)
+{
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	printk("%s: Yellowfin transmit timed out, status %8.8x, resetting...\n",
+		   dev->name, inl(ioaddr));
+
+#ifndef __alpha__
+	{
+		int i;
+		printk("  Rx ring %8.8x: ", (int)yp->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)yp->rx_ring[i].status);
+		printk("\n  Tx ring %8.8x: ", (int)yp->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %4.4x /%4.4x", yp->tx_status[i].tx_errs, yp->tx_ring[i].status);
+		printk("\n");
+	}
+#endif
+
+  /* Perhaps we should reinitialize the hardware here. */
+  dev->if_port = 0;
+  /* Stop and restart the chip's Tx processes . */
+
+  /* Trigger an immediate transmit demand. */
+
+  dev->trans_start = jiffies;
+  yp->stats.tx_errors++;
+  return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+yellowfin_init_ring(struct device *dev)
+{
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	int i;
+
+	yp->tx_full = 0;
+	yp->cur_rx = yp->cur_tx = 0;
+	yp->dirty_rx = yp->dirty_tx = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb;
+		int pkt_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+		yp->rx_ring[i].request_cnt = pkt_buf_sz;
+		yp->rx_ring[i].cmd = CMD_RX_BUF | INTR_ALWAYS;
+
+		skb = DEV_ALLOC_SKB(pkt_buf_sz);
+		skb_reserve(skb, 2);	/* 16 byte align the IP header. */
+		yp->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;			/* Bad news!  */
+		skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+		yp->rx_ring[i].addr = virt_to_bus(skb->tail);
+#else
+		yp->rx_ring[i].addr = virt_to_bus(skb->data);
+#endif
+		yp->rx_ring[i].branch_addr = virt_to_bus(&yp->rx_ring[i+1]);
+	}
+	/* Mark the last entry as wrapping the ring. */
+	yp->rx_ring[i-1].cmd = CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
+	yp->rx_ring[i-1].branch_addr = virt_to_bus(&yp->rx_ring[0]);
+
+/*#define NO_TXSTATS*/
+#ifdef NO_TXSTATS
+	/* In this mode the Tx ring needs only a single descriptor. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		yp->tx_skbuff[i] = 0;
+		yp->tx_ring[i].cmd = CMD_STOP;
+		yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+	}
+	yp->tx_ring[--i].cmd = CMD_STOP | BRANCH_ALWAYS; /* Wrap ring */
+	yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+#else
+	/* Tx ring needs a pair of descriptors, the second for the status. */
+	for (i = 0; i < TX_RING_SIZE*2; i++) {
+		yp->tx_skbuff[i/2] = 0;
+		yp->tx_ring[i].cmd = CMD_STOP; /* Branch on Tx error. */
+		yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+		i++;
+		yp->tx_ring[i].cmd = CMD_TXSTATUS; /* Interrupt, no wait. */
+		yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]);
+		yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2]);
+		yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+	}
+	/* Wrap ring */
+	yp->tx_ring[--i].cmd = CMD_TXSTATUS | BRANCH_ALWAYS | INTR_ALWAYS;
+	yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+#endif
+}
+
+static int
+yellowfin_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	unsigned entry;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start < TX_TIMEOUT)
+			return 1;
+		yellowfin_tx_timeout(dev);
+		return 1;
+	}
+
+	/* Caution: the write order is important here, set the base address
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = yp->cur_tx % TX_RING_SIZE;
+
+	yp->tx_skbuff[entry] = skb;
+
+#ifdef NO_TXSTATS
+	yp->tx_ring[entry].request_cnt = skb->len;
+	yp->tx_ring[entry].addr = virt_to_bus(skb->data);
+	yp->tx_ring[entry].status = 0;
+	if (entry >= TX_RING_SIZE-1) {
+		yp->tx_ring[0].cmd = CMD_STOP; /* New stop command. */
+		yp->tx_ring[TX_RING_SIZE-1].cmd = CMD_TX_PKT | BRANCH_ALWAYS;
+	} else {
+		yp->tx_ring[entry+1].cmd = CMD_STOP; /* New stop command. */
+		yp->tx_ring[entry].cmd = CMD_TX_PKT | BRANCH_IFTRUE;
+	}
+	yp->cur_tx++;
+#else
+	yp->tx_ring[entry<<1].request_cnt = skb->len;
+	yp->tx_ring[entry<<1].addr = virt_to_bus(skb->data);
+	/* The input_last (status-write) command is constant, but we must rewrite
+	   the subsequent 'stop' command. */
+
+	yp->cur_tx++;
+	{
+		unsigned next_entry = yp->cur_tx % TX_RING_SIZE;
+		yp->tx_ring[next_entry<<1].cmd = CMD_STOP;
+	}
+	/* Final step -- overwrite the old 'stop' command. */
+
+	yp->tx_ring[entry<<1].cmd =
+		(entry % 6) == 0 ? CMD_TX_PKT | INTR_ALWAYS | BRANCH_IFTRUE :
+		CMD_TX_PKT | BRANCH_IFTRUE;
+#endif
+
+	/* Todo: explicitly flush cache lines here. */
+
+	/* Wake the potentially-idle transmit channel. */
+	outl(0x10001000, dev->base_addr + TxCtrl);
+
+	if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1)
+		clear_bit(0, (void*)&dev->tbusy);		/* Typical path */
+	else
+		yp->tx_full = 1;
+	dev->trans_start = jiffies;
+
+	if (yellowfin_debug > 4) {
+		printk("%s: Yellowfin transmit frame #%d queued in slot %d.\n",
+			   dev->name, yp->cur_tx, entry);
+	}
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+{
+#ifdef SA_SHIRQ		/* Use the now-standard shared IRQ implementation. */
+	struct device *dev = (struct device *)dev_instance;
+#else
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
+
+	struct yellowfin_private *lp;
+	int ioaddr, boguscnt = max_interrupt_work;
+
+	if (dev == NULL) {
+		printk ("yellowfin_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	lp = (struct yellowfin_private *)dev->priv;
+	if (test_and_set_bit(0, (void*)&lp->in_interrupt)) {
+		dev->interrupt = 1;
+		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+		return;
+	}
+
+	do {
+		u16 intr_status = inw(ioaddr + IntrClear);
+		unsigned dirty_tx = lp->dirty_tx;
+
+		if (yellowfin_debug > 4)
+			printk("%s: Yellowfin interrupt, status %4.4x.\n",
+				   dev->name, intr_status);
+
+		if (intr_status == 0)
+			break;
+
+		if (intr_status & (IntrRxDone | IntrEarlyRx))
+			yellowfin_rx(dev);
+
+#ifdef NO_TXSTATS
+		for (; lp->cur_tx - dirty_tx > 0; dirty_tx++) {
+			int entry = dirty_tx % TX_RING_SIZE;
+			if (lp->tx_ring[entry].status == 0)
+				break;
+			/* Free the original skb. */
+			dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+			lp->tx_skbuff[entry] = 0;
+			lp->stats.tx_packets++;
+		}
+		if (lp->tx_full && dev->tbusy
+			&& lp->cur_tx - dirty_tx < TX_RING_SIZE - 4) {
+			/* The ring is no longer full, clear tbusy. */
+			lp->tx_full = 0;
+			clear_bit(0, (void*)&dev->tbusy);
+			mark_bh(NET_BH);
+		}
+		lp->dirty_tx = dirty_tx;
+#else
+		if (intr_status & IntrTxDone
+			|| lp->tx_status[dirty_tx % TX_RING_SIZE].tx_errs) {
+
+			for (dirty_tx = lp->dirty_tx; lp->cur_tx - dirty_tx > 0;
+				 dirty_tx++) {
+				/* Todo: optimize this. */
+				int entry = dirty_tx % TX_RING_SIZE;
+				u16 tx_errs = lp->tx_status[entry].tx_errs;
+
+				if (tx_errs == 0)
+					break;			/* It still hasn't been Txed */
+				if (tx_errs & 0xF8100000) {
+					/* There was an major error, log it. */
+#ifndef final_version
+					if (yellowfin_debug > 1)
+						printk("%s: Transmit error, Tx status %4.4x.\n",
+							   dev->name, tx_errs);
+#endif
+					lp->stats.tx_errors++;
+					if (tx_errs & 0xF800) lp->stats.tx_aborted_errors++;
+					if (tx_errs & 0x0800) lp->stats.tx_carrier_errors++;
+					if (tx_errs & 0x2000) lp->stats.tx_window_errors++;
+					if (tx_errs & 0x8000) lp->stats.tx_fifo_errors++;
+#ifdef ETHER_STATS
+					if (tx_errs & 0x1000) lp->stats.collisions16++;
+#endif
+				} else {
+#ifdef ETHER_STATS
+					if (status & 0x0400) lp->stats.tx_deferred++;
+#endif
+					lp->stats.collisions += tx_errs & 15;
+					lp->stats.tx_packets++;
+				}
+
+				/* Free the original skb. */
+				dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+				lp->tx_skbuff[entry] = 0;
+				/* Mark status as empty. */
+				lp->tx_status[entry].tx_errs = 0;
+			}
+
+#ifndef final_version
+			if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (lp->tx_full && dev->tbusy
+				&& lp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
+				/* The ring is no longer full, clear tbusy. */
+				lp->tx_full = 0;
+				clear_bit(0, (void*)&dev->tbusy);
+				mark_bh(NET_BH);
+			}
+
+			lp->dirty_tx = dirty_tx;
+		}
+#endif
+
+		/* Log errors and other events. */
+		if (intr_status & 0x2ee) {	/* Abnormal error summary. */
+			printk("%s: Something Wicked happened! %4.4x.\n",
+				   dev->name, intr_status);
+			/* Hmmmmm, it's not clear what to do here. */
+			if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
+				lp->stats.tx_errors++;
+			if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
+				lp->stats.rx_errors++;
+		}
+		if (--boguscnt < 0) {
+			printk("%s: Too much work at interrupt, status=0x%4.4x.\n",
+				   dev->name, intr_status);
+			break;
+		}
+	} while (1);
+
+	if (yellowfin_debug > 3)
+		printk("%s: exiting interrupt, status=%#4.4x.\n",
+			   dev->name, inw(ioaddr + IntrStatus));
+
+	/* Code that should never be run!  Perhaps remove after testing.. */
+	{
+		static int stopit = 10;
+		if (dev->start == 0  &&  --stopit < 0) {
+			printk("%s: Emergency stop, looping startup interrupt.\n",
+				   dev->name);
+#ifdef SA_SHIRQ
+			free_irq(irq, dev);
+#else
+			free_irq(irq);
+#endif
+		}
+	}
+
+	dev->interrupt = 0;
+	clear_bit(0, (void*)&lp->in_interrupt);
+	return;
+}
+
+/* This routine is logically part of the interrupt handler, but seperated
+   for clarity and better register allocation. */
+static int
+yellowfin_rx(struct device *dev)
+{
+	struct yellowfin_private *lp = (struct yellowfin_private *)dev->priv;
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	int entry = lp->cur_rx % RX_RING_SIZE;
+	int boguscnt = 20;
+
+	if (yellowfin_debug > 4) {
+		printk(" In yellowfin_rx(), entry %d status %4.4x.\n", entry,
+			   yp->rx_ring[entry].status);
+		printk("   #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x.\n",
+			   entry, yp->rx_ring[entry].cmd,
+			   yp->rx_ring[entry].request_cnt, yp->rx_ring[entry].addr,
+			   yp->rx_ring[entry].result_cnt, yp->rx_ring[entry].status);
+	}
+
+
+	/* If EOP is set on the next entry, it's a new packet. Send it up. */
+	while (yp->rx_ring[entry].status) {
+		/* Todo: optimize this mess. */
+		u16 desc_status = yp->rx_ring[entry].status;
+		struct yellowfin_desc *desc = &lp->rx_ring[entry];
+		int frm_size = desc->request_cnt - desc->result_cnt;
+		u8 *buf_addr = bus_to_virt(lp->rx_ring[entry].addr);
+		s16 frame_status = *(s16*)&(buf_addr[frm_size - 2]);
+
+		if (yellowfin_debug > 4)
+			printk("  yellowfin_rx() status was %4.4x.\n", frame_status);
+		if (--boguscnt < 0)
+			break;
+		if ( ! (desc_status & RX_EOP)) {
+			printk("%s: Oversized Ethernet frame spanned multiple buffers,"
+				   " status %4.4x!\n", dev->name, desc_status);
+			  lp->stats.rx_length_errors++;
+		} else if (frame_status & 0x0038) {
+			/* There was a error. */
+			if (yellowfin_debug > 3)
+				printk("  yellowfin_rx() Rx error was %4.4x.\n", frame_status);
+			lp->stats.rx_errors++;
+			if (frame_status & 0x0060) lp->stats.rx_length_errors++;
+			if (frame_status & 0x0008) lp->stats.rx_frame_errors++;
+			if (frame_status & 0x0010) lp->stats.rx_crc_errors++;
+			if (frame_status < 0) lp->stats.rx_dropped++;
+#ifdef YF_PROTOTYPE			/* Support for prototype hardware errata. */
+		} else if (memcmp(bus_to_virt(lp->rx_ring[entry].addr),
+						  dev->dev_addr, 6) != 0
+				   && memcmp(bus_to_virt(lp->rx_ring[entry].addr),
+							 "\377\377\377\377\377\377", 6) != 0) {
+			printk("%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+				   dev->name,
+				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[0],
+				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[1],
+				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[2],
+				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[3],
+				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[4],
+				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[5]);
+			bogus_rx++;
+#endif
+		} else {
+			u8 bogus_cnt = buf_addr[frm_size - 8];
+			int pkt_len = frm_size - 8 - bogus_cnt;
+			struct sk_buff *skb;
+			int rx_in_place = 0;
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len > rx_copybreak) {
+				struct sk_buff *newskb;
+				char *temp;
+
+				/* Get a fresh skbuff to replace the filled one. */
+				newskb = DEV_ALLOC_SKB(dev->mtu <= 1500 ? PKT_BUF_SZ
+									   : dev->mtu + 32);
+				if (newskb == NULL) {
+					skb = 0;		/* No memory, drop the packet. */
+					goto memory_squeeze;
+				}
+				/* Pass up the skb already on the Rx ring. */
+				skb = lp->rx_skbuff[entry];
+				temp = skb_put(skb, pkt_len);
+				if (bus_to_virt(lp->rx_ring[entry].addr) != temp)
+					printk("%s: Warning -- the skbuff addresses do not match"
+						   " in yellowfin_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(lp->rx_ring[entry].addr),
+						   skb->head, temp);
+				rx_in_place = 1;
+				lp->rx_skbuff[entry] = newskb;
+				newskb->dev = dev;
+				skb_reserve(newskb, 2);	/* 16 byte align IP header */
+				lp->rx_ring[entry].addr = virt_to_bus(newskb->tail);
+			} else
+				skb = DEV_ALLOC_SKB(pkt_len + 2);
+			memory_squeeze:
+			if (skb == NULL) {
+				printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+				/* todo: Check that at least two ring entries are free.
+				   If not, free one and mark stats->rx_dropped++. */
+				break;
+			}
+			skb->dev = dev;
+			if (! rx_in_place) {
+				skb_reserve(skb, 2);	/* 16 byte align the data fields */
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(lp->rx_ring[entry].addr), pkt_len);
+			}
+#if LINUX_VERSION_CODE > 0x10300
+			skb->protocol = eth_type_trans(skb, dev);
+#else
+			skb->len = pkt_len;
+#endif
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		}
+
+		/* Mark this entry as being the end-of-list, and the prior entry
+		   as now valid. */
+		lp->rx_ring[entry].cmd = CMD_STOP;
+		yp->rx_ring[entry].status = 0;
+		{
+			int prev_entry = entry - 1;
+			if (prev_entry < 0)
+				lp->rx_ring[RX_RING_SIZE - 1].cmd =
+					CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
+			else
+				lp->rx_ring[prev_entry].cmd = CMD_RX_BUF | INTR_ALWAYS;
+		}
+		entry = (++lp->cur_rx) % RX_RING_SIZE;
+	}
+	/* todo: restart Rx engine if stopped.  For now we just make the Rx ring
+	   large enough to avoid this. */
+
+	return 0;
+}
+
+static int
+yellowfin_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (yellowfin_debug > 1) {
+		printk("%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n",
+			   dev->name, inw(ioaddr + TxStatus),
+			   inw(ioaddr + RxStatus), inl(ioaddr + IntrStatus));
+		printk("%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+			   dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx);
+	}
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outw(0x0000, ioaddr + IntrEnb);
+
+	/* Stop the chip's Tx and Rx processes. */
+	outl(0x80000000, ioaddr + RxCtrl);
+	outl(0x80000000, ioaddr + TxCtrl);
+
+	del_timer(&yp->timer);
+
+#ifdef __i386__
+	if (yellowfin_debug > 2) {
+		printk("\n  Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));
+		for (i = 0; i < TX_RING_SIZE*2; i++)
+			printk(" %c #%d desc. %4.4x %4.4x %8.8x %8.8x %4.4x %4.4x.\n",
+				   inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
+				   i, yp->tx_ring[i].cmd,
+				   yp->tx_ring[i].request_cnt, yp->tx_ring[i].addr,
+				   yp->tx_ring[i].branch_addr,
+				   yp->tx_ring[i].result_cnt, yp->tx_ring[i].status);
+		printk("  Tx status %p:\n", yp->tx_status);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk("   #%d status %4.4x %4.4x %4.4x %4.4x.\n",
+				   i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
+				   yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
+
+		printk("\n  Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring));
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			printk(" %c #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x\n",
+				   inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
+				   i, yp->rx_ring[i].cmd,
+				   yp->rx_ring[i].request_cnt, yp->rx_ring[i].addr,
+				   yp->rx_ring[i].result_cnt, yp->rx_ring[i].status);
+			if (yellowfin_debug > 5) {
+				if (*(u8*)yp->rx_ring[i].addr != 0x69) {
+					int j;
+					for (j = 0; j < 0x50; j++)
+						printk(" %4.4x", ((u16*)yp->rx_ring[i].addr)[j]);
+					printk("\n");
+				}
+			}
+		}
+	}
+#endif /* __i386__ debugging only */
+
+#ifdef SA_SHIRQ
+	free_irq(dev->irq, dev);
+#else
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = 0;
+#endif
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		yp->rx_ring[i].cmd = CMD_STOP;
+		yp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+		if (yp->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+			yp->rx_skbuff[i]->free = 1;
+#endif
+			dev_kfree_skb(yp->rx_skbuff[i], FREE_WRITE);
+		}
+		yp->rx_skbuff[i] = 0;
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (yp->tx_skbuff[i])
+			dev_kfree_skb(yp->tx_skbuff[i], FREE_WRITE);
+		yp->tx_skbuff[i] = 0;
+	}
+
+#ifdef YF_PROTOTYPE			/* Support for prototype hardware errata. */
+	if (yellowfin_debug > 0) {
+		printk("%s: Received %d frames that we should not have.\n",
+			   dev->name, bogus_rx);
+	}
+#endif
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics *
+yellowfin_get_stats(struct device *dev)
+{
+	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+	return &yp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor. */
+
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev)
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+{
+	int ioaddr = dev->base_addr;
+	u16 cfg_value = inw(ioaddr + Cnfg);
+
+	/* Stop the Rx process to change any value. */
+	outw(cfg_value & ~0x1000, ioaddr + Cnfg);
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		outw(0x000F, ioaddr + AddrMode);
+	} else if ((dev->mc_count > 64)  ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter well, or accept all multicasts. */
+		outw(0x000B, ioaddr + AddrMode);
+	} else if (dev->mc_count > 0) { /* Must use the multicast hash table. */
+		struct dev_mc_list *mclist;
+		u16 hash_table[4];
+		int i;
+		memset(hash_table, 0, sizeof(hash_table));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next) {
+			/* Due to a bug in the early chip versions, multiple filter
+			   slots must be set for each address. */
+			set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,
+					hash_table);
+			set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,
+					hash_table);
+			set_bit((ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f,
+					hash_table);
+			set_bit((ether_crc_le(6, mclist->dmi_addr) >> 3) & 0x3f,
+					hash_table);
+		}
+		/* Copy the hash table to the chip. */
+		for (i = 0; i < 4; i++)
+			outw(hash_table[i], ioaddr + HashTbl + i*2);
+		outw(0x0003, ioaddr + AddrMode);
+	} else {					/* Normal, unicast/broadcast-only mode. */
+		outw(0x0001, ioaddr + AddrMode);
+	}
+	/* Restart the Rx process. */
+	outw(cfg_value | 0x1000, ioaddr + Cnfg);
+}
+
+#ifdef MODULE
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+	int cards_found;
+
+	if (debug >= 0)
+		yellowfin_debug = debug;
+
+	root_yellowfin_dev = NULL;
+	cards_found = yellowfin_probe(0);
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_yellowfin_dev) {
+		next_dev = ((struct yellowfin_private *)root_yellowfin_dev->priv)->next_module;
+		unregister_netdev(root_yellowfin_dev);
+		release_region(root_yellowfin_dev->base_addr, YELLOWFIN_TOTAL_SIZE);
+		kfree(root_yellowfin_dev);
+		root_yellowfin_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.0.33/linux/drivers/pci/pci.c	Tue Dec  2 13:52:31 1997
+++ linux/drivers/pci/pci.c	Wed Jun  3 15:17:48 1998
@@ -5,7 +5,10 @@
  *
  * Copyright 1993, 1994, 1995 Drew Eckhardt, Frederic Potter,
  *	David Mosberger-Tang
+ *
+ * Apr 12, 1998 : Fixed handling of alien header types. [mj]
  */
+
 #include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/types.h>
@@ -42,10 +45,15 @@
  */
 struct pci_dev_info dev_info[] = {
 	DEVICE( COMPAQ,		COMPAQ_1280,	"QVision 1280/p"),
-	DEVICE( COMPAQ,		COMPAQ_NETELL100,"Netelligent 10/100"),
-	DEVICE( COMPAQ,		COMPAQ_NETELL10,"Netelligent 10"),
-	DEVICE( COMPAQ,		COMPAQ_NETFLEX3,"NetFlex 3"),
+	DEVICE( COMPAQ,		COMPAQ_SMART2P,	"Smart-2/P RAID Controller"),
+	DEVICE( COMPAQ,		COMPAQ_NETEL100,"Netelligent 10/100"),
+	DEVICE( COMPAQ,		COMPAQ_NETEL10,	"Netelligent 10"),
+	DEVICE( COMPAQ,		COMPAQ_NETFLEX3I,"NetFlex 3"),
+	DEVICE( COMPAQ,		COMPAQ_NETEL100D,"Netelligent 10/100 Dual"),
+	DEVICE( COMPAQ,		COMPAQ_NETEL100PI,"Netelligent 10/100 ProLiant"),
+	DEVICE( COMPAQ,		COMPAQ_NETEL100I,"Netelligent 10/100 Integrated"),
 	DEVICE( COMPAQ,		COMPAQ_THUNDER,	"ThunderLAN"),
+	DEVICE( COMPAQ,		COMPAQ_NETFLEX3B,"NetFlex 3 BNC"),
 	DEVICE( NCR,		NCR_53C810,	"53c810"),
 	DEVICE( NCR,		NCR_53C820,	"53c820"),
 	DEVICE( NCR,		NCR_53C825,	"53c825"),
@@ -55,18 +63,34 @@
 	DEVICE( NCR,		NCR_53C895,	"53c895"),
 	DEVICE( NCR,		NCR_53C885,	"53c885"),
 	DEVICE( NCR,		NCR_53C875,	"53c875"),
+	DEVICE( NCR,		NCR_53C875J,	"53c875J"),
 	DEVICE( ATI,		ATI_68800,      "68800AX"),
 	DEVICE( ATI,		ATI_215CT222,   "215CT222"),
 	DEVICE( ATI,		ATI_210888CX,   "210888CX"),
+	DEVICE( ATI,		ATI_215GB,	"Mach64 GB"),
+	DEVICE( ATI,		ATI_215GD,	"Mach64 GD (Rage Pro)"),
+	DEVICE( ATI,		ATI_215GI,	"Mach64 GI (Rage Pro)"),
+	DEVICE( ATI,		ATI_215GP,	"Mach64 GP (Rage Pro)"),
+	DEVICE( ATI,		ATI_215GQ,	"Mach64 GQ (Rage Pro)"),
 	DEVICE( ATI,		ATI_215GT,	"Mach64 GT (Rage II)"),
+	DEVICE( ATI,		ATI_215GTB,	"Mach64 GT (Rage II)"),
 	DEVICE( ATI,		ATI_210888GX,   "210888GX"),
+	DEVICE( ATI,		ATI_215LG,	"Mach64 LG (3D Rage LT)"),
+	DEVICE( ATI,		ATI_264LT,	"Mach64 LT"),
 	DEVICE( ATI,		ATI_264VT,	"Mach64 VT"),
 	DEVICE( VLSI,		VLSI_82C592,	"82C592-FC1"),
 	DEVICE( VLSI,		VLSI_82C593,	"82C593-FC1"),
 	DEVICE( VLSI,		VLSI_82C594,	"82C594-AFC2"),
 	DEVICE( VLSI,		VLSI_82C597,	"82C597-AFC2"),
-	DEVICE( VLSI,		VLSI_VAS96011,	"VAS96011 PowerPC"),
+	DEVICE( VLSI,		VLSI_82C541,	"82C541 Lynx"),
+	DEVICE( VLSI,		VLSI_82C543,	"82C543 Lynx ISA"),
+	DEVICE( VLSI,		VLSI_82C532,	"82C532"),
+	DEVICE( VLSI,		VLSI_82C534,	"82C534"),
+	DEVICE( VLSI,		VLSI_82C535,	"82C535"),
+	DEVICE( VLSI,		VLSI_82C147,	"82C147"),
+	DEVICE( VLSI,		VLSI_VAS96011,	"VAS96011 (Golden Gate II)"),
 	DEVICE( ADL,		ADL_2301,	"2301"),
+	DEVICE( NS,		NS_87415,	"87415"),
 	DEVICE( NS,		NS_87410,	"87410"),
 	DEVICE( TSENG,		TSENG_W32P_2,	"ET4000W32P"),
 	DEVICE( TSENG,		TSENG_W32P_b,	"ET4000W32P rev B"),
@@ -77,12 +101,14 @@
 	DEVICE( WEITEK,		WEITEK_P9100,	"P9100"),
 	BRIDGE( DEC,		DEC_BRD,	"DC21050", 		0x00),
 	DEVICE( DEC,		DEC_TULIP,	"DC21040"),
-	DEVICE( DEC,		DEC_TGA,	"DC21030"),
+	DEVICE( DEC,		DEC_TGA,	"DC21030 (TGA)"),
 	DEVICE( DEC,		DEC_TULIP_FAST,	"DC21140"),
+	DEVICE( DEC,		DEC_TGA2,	"TGA2"),
 	DEVICE( DEC,		DEC_FDDI,	"DEFPA"),
 	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041"),
 	DEVICE( DEC,		DEC_21142,	"DC21142"),
 	DEVICE( DEC,		DEC_21052,	"DC21052"),
+	DEVICE( DEC,		DEC_21150,	"DC21150"),
 	DEVICE( DEC,		DEC_21152,	"DC21152"),
 	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548"),
 	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
@@ -99,29 +125,41 @@
 	DEVICE( CIRRUS,		CIRRUS_7543,	"CL 7543"),
 	DEVICE( CIRRUS,		CIRRUS_7541,	"CL 7541"),
 	DEVICE( IBM,		IBM_FIRE_CORAL,	"Fire Coral"),
+	DEVICE( IBM,		IBM_TR,		"Token Ring"),
 	DEVICE( IBM,		IBM_82G2675,	"82G2675"),
+	DEVICE( IBM,		IBM_MCA,	"MicroChannel"),
 	DEVICE( IBM,		IBM_82351,	"82351"),
+	DEVICE( IBM,		IBM_SERVERAID,	"ServeRAID"),
+	DEVICE( IBM,		IBM_TR_WAKE,	"Wake On LAN Token Ring"),
+	DEVICE( IBM,		IBM_3780IDSP,	"MWave DSP"),
 	DEVICE( WD,		WD_7197,	"WD 7197"),
 	DEVICE( AMD,		AMD_LANCE,	"79C970"),
 	DEVICE( AMD,		AMD_SCSI,	"53C974"),
+	DEVICE( TRIDENT,	TRIDENT_9397,	"Cyber9397"),
 	DEVICE( TRIDENT,	TRIDENT_9420,	"TG 9420"),
 	DEVICE( TRIDENT,	TRIDENT_9440,	"TG 9440"),
-	DEVICE( TRIDENT,	TRIDENT_9660,	"TG 9660"),
+	DEVICE( TRIDENT,	TRIDENT_9660,	"TG 9660 / Cyber9385"),
+	DEVICE( TRIDENT,	TRIDENT_9750,	"Image 975"),
 	DEVICE( AI,		AI_M1435,	"M1435"),
 	DEVICE( MATROX,		MATROX_MGA_2,	"Atlas PX2085"),
 	DEVICE( MATROX,		MATROX_MIL,	"Millennium"),
 	DEVICE( MATROX,		MATROX_MYS,	"Mystique"),
 	DEVICE( MATROX,		MATROX_MIL_2,	"Millennium II"),
+	DEVICE( MATROX,		MATROX_MIL_2_AGP,"Millennium II AGP"),
 	DEVICE( MATROX,		MATROX_MGA_IMP,	"MGA Impression"),
 	DEVICE( CT,		CT_65545,	"65545"),
 	DEVICE( CT,		CT_65548,	"65548"),
 	DEVICE(	CT,		CT_65550,	"65550"),
 	DEVICE( CT,		CT_65554,	"65554"),
+	DEVICE( CT,		CT_65555,	"65555"),
 	DEVICE( MIRO,		MIRO_36050,	"ZR36050"),
+	DEVICE( NEC,		NEC_PCX2,	"PowerVR PCX2"),
 	DEVICE( FD,		FD_36C70,	"TMC-18C30"),
-	DEVICE( SI,		SI_6201,	"6201"),
+	DEVICE( SI,		SI_5591_AGP,	"5591/5592 AGP"),
 	DEVICE( SI,		SI_6202,	"6202"),
 	DEVICE( SI,		SI_503,		"85C503"),
+	DEVICE( SI,		SI_ACPI,	"ACPI"),
+	DEVICE( SI,		SI_5597_VGA,	"5597/5598 VGA"),
 	DEVICE( SI,		SI_6205,	"6205"),
 	DEVICE( SI,		SI_501,		"85C501"),
 	DEVICE( SI,		SI_496,		"85C496"),
@@ -130,29 +168,42 @@
 	DEVICE( SI,		SI_5511,		"85C5511"),
 	DEVICE( SI,		SI_5513,		"85C5513"),
 	DEVICE( SI,		SI_5571,	"5571"),
-	DEVICE( SI,		SI_7001,	"7001"),
+	DEVICE( SI,		SI_5591,	"5591/5592 Host"),
+	DEVICE( SI,		SI_5597,	"5597/5598 Host"),
+	DEVICE( SI,		SI_7001,	"7001 USB"),
 	DEVICE( HP,		HP_J2585A,	"J2585A"),
 	DEVICE( HP,		HP_J2585B,	"J2585B (Lassen)"),
 	DEVICE( PCTECH,		PCTECH_RZ1000,  "RZ1000 (buggy)"),
 	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1001 (buggy?)"),
+	DEVICE( PCTECH,		PCTECH_SAMURAI_0,"Samurai 0"),
+	DEVICE( PCTECH,		PCTECH_SAMURAI_1,"Samurai 1"),
+	DEVICE( PCTECH,		PCTECH_SAMURAI_IDE,"Samurai IDE"),
 	DEVICE( DPT,		DPT,		"SmartCache/Raid"),
 	DEVICE( OPTI,		OPTI_92C178,	"92C178"),
-	DEVICE( OPTI,		OPTI_82C557,	"82C557"),
-	DEVICE( OPTI,		OPTI_82C558,	"82C558"),
+	DEVICE( OPTI,		OPTI_82C557,	"82C557 Viper-M"),
+	DEVICE( OPTI,		OPTI_82C558,	"82C558 Viper-M ISA+IDE"),
 	DEVICE( OPTI,		OPTI_82C621,	"82C621"),
+	DEVICE( OPTI,		OPTI_82C700,	"82C700"),
+	DEVICE( OPTI,		OPTI_82C701,	"82C701 FireStar Plus"),
+	DEVICE( OPTI,		OPTI_82C814,	"82C814 Firebridge 1"),
 	DEVICE( OPTI,		OPTI_82C822,	"82C822"),
+	DEVICE( OPTI,		OPTI_82C825,	"82C825 Firebridge 2"),
 	DEVICE( SGS,		SGS_2000,	"STG 2000X"),
 	DEVICE( SGS,		SGS_1764,	"STG 1764X"),
 	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"),
 	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER,    "MultiMaster"),
 	DEVICE( BUSLOGIC,	BUSLOGIC_FLASHPOINT,     "FlashPoint"),
+	DEVICE( TI,		TI_TVP4010,	"TVP4010 Permedia"),
+	DEVICE( TI,		TI_TVP4020,	"TVP4020 Permedia 2"),
 	DEVICE( TI,		TI_PCI1130,	"PCI1130"),
 	DEVICE( TI,		TI_PCI1131,	"PCI1131"),
+	DEVICE( TI,		TI_PCI1250,	"PCI1250"),
 	DEVICE( OAK,		OAK_OTI107,	"OTI107"),
 	DEVICE( WINBOND2,	WINBOND2_89C940,"NE2000-PCI"),
 	DEVICE( MOTOROLA,	MOTOROLA_MPC105,"MPC105 Eagle"),
 	DEVICE( MOTOROLA,	MOTOROLA_MPC106,"MPC106 Grackle"),
 	DEVICE( MOTOROLA,	MOTOROLA_RAVEN,	"Raven"),
+	DEVICE( PROMISE,	PROMISE_20246,	"IDE UltraDMA/33"),
 	DEVICE( PROMISE,	PROMISE_5300,	"DC5030"),
 	DEVICE( N9,		N9_I128,	"Imagine 128"),
 	DEVICE( N9,		N9_I128_2,	"Imagine 128v2"),
@@ -166,20 +217,36 @@
 	DEVICE( UMC,		UMC_UM8886N,	"UM8886N"),
 	DEVICE( UMC,		UMC_UM8891N,	"UM8891N"),
 	DEVICE( X,		X_AGX016,	"ITT AGX016"),
+	DEVICE( PICOP,		PICOP_PT86C52X,	"PT86C52x Vesuvius"),
+	DEVICE( PICOP,		PICOP_PT80C524,	"PT80C524 Nile"),
 	DEVICE( APPLE,		APPLE_BANDIT,	"Bandit"),
 	DEVICE( APPLE,		APPLE_GC,	"Grand Central"),
 	DEVICE( APPLE,		APPLE_HYDRA,	"Hydra"),
 	DEVICE( NEXGEN,		NEXGEN_82C501,	"82C501"),
 	DEVICE( QLOGIC,		QLOGIC_ISP1020,	"ISP1020"),
 	DEVICE( QLOGIC,		QLOGIC_ISP1022,	"ISP1022"),
+	DEVICE( CYRIX,		CYRIX_5510,	"5510"),
+	DEVICE( CYRIX,		CYRIX_PCI_MASTER,"PCI Master"),
+	DEVICE( CYRIX,		CYRIX_5520,	"5520"),
+	DEVICE( CYRIX,		CYRIX_5530_LEGACY,"5530 Kahlua Legacy"),
+	DEVICE( CYRIX,		CYRIX_5530_SMI,	"5530 Kahlua SMI"),
+	DEVICE( CYRIX,		CYRIX_5530_IDE,	"5530 Kahlua IDE"),
+	DEVICE( CYRIX,		CYRIX_5530_AUDIO,"5530 Kahlua Audio"),
+	DEVICE( CYRIX,		CYRIX_5530_VIDEO,"5530 Kahlua Video"),
 	DEVICE( LEADTEK,	LEADTEK_805,	"S3 805"),
 	DEVICE( CONTAQ,		CONTAQ_82C599,	"82C599"),
+	DEVICE( CONTAQ,		CONTAQ_82C693,	"82C693"),
 	DEVICE( OLICOM,		OLICOM_OC3136,	"OC-3136/3137"),
 	DEVICE( OLICOM,		OLICOM_OC2315,	"OC-2315"),
 	DEVICE( OLICOM,		OLICOM_OC2325,	"OC-2325"),
 	DEVICE( OLICOM,		OLICOM_OC2183,	"OC-2183/2185"),
 	DEVICE( OLICOM,		OLICOM_OC2326,	"OC-2326"),
 	DEVICE( OLICOM,		OLICOM_OC6151,	"OC-6151/6152"),
+	DEVICE( SUN,		SUN_EBUS,	"EBUS"),
+	DEVICE( SUN,		SUN_HAPPYMEAL,	"Happy Meal Ethernet"),
+	DEVICE( SUN,		SUN_SIMBA,	"Advanced PCI Bridge"),
+	DEVICE( SUN,		SUN_PBM,	"PCI Bus Module"),
+	DEVICE( SUN,		SUN_SABRE,	"Ultra IIi PCI"),
 	DEVICE( CMD,		CMD_640,	"640 (buggy)"),
 	DEVICE( CMD,		CMD_643,	"643"),
 	DEVICE( CMD,		CMD_646,	"646"),
@@ -187,12 +254,17 @@
 	DEVICE( VISION,		VISION_QD8500,	"QD-8500"),
 	DEVICE( VISION,		VISION_QD8580,	"QD-8580"),
 	DEVICE( BROOKTREE,	BROOKTREE_848,	"Bt848"),
+	DEVICE( BROOKTREE,	BROOKTREE_849A,	"Bt849"),
+	DEVICE( BROOKTREE,	BROOKTREE_8474,	"Bt8474"),
 	DEVICE( SIERRA,		SIERRA_STB,	"STB Horizon 64"),
 	DEVICE( ACC,		ACC_2056,	"2056"),
 	DEVICE( WINBOND,	WINBOND_83769,	"W83769F"),
 	DEVICE( WINBOND,	WINBOND_82C105,	"SL82C105"),
 	DEVICE( WINBOND,	WINBOND_83C553,	"W83C553"),
 	DEVICE( DATABOOK,      	DATABOOK_87144,	"DB87144"),
+	DEVICE( PLX,		PLX_9080,	"PCI9080 I2O"),
+	DEVICE( MADGE,		MADGE_MK2,	"Smart 16/4 BM Mk2 Ringnode"),
+	DEVICE( 3COM,		3COM_3C339,	"3C339 TokenRing"),
 	DEVICE( 3COM,		3COM_3C590,	"3C590 10bT"),
 	DEVICE( 3COM,		3COM_3C595TX,	"3C595 100bTX"),
 	DEVICE( 3COM,		3COM_3C595T4,	"3C595 100bT4"),
@@ -200,6 +272,9 @@
 	DEVICE( 3COM,		3COM_3C900TPO,	"3C900 10bTPO"),
 	DEVICE( 3COM,		3COM_3C900COMBO,"3C900 10b Combo"),
 	DEVICE( 3COM,		3COM_3C905TX,	"3C905 100bTX"),
+	DEVICE( 3COM,		3COM_3C905T4,	"3C905 100bT4"),
+	DEVICE( 3COM,		3COM_3C905B_TX,	"3C905B 100bTX"),
+	DEVICE( SMC,		SMC_EPIC100,	"9432 TX"),
 	DEVICE( AL,		AL_M1445,	"M1445"),
 	DEVICE( AL,		AL_M1449,	"M1449"),
 	DEVICE( AL,		AL_M1451,	"M1451"),
@@ -207,32 +282,58 @@
 	DEVICE( AL,		AL_M1489,	"M1489"),
 	DEVICE( AL,		AL_M1511,	"M1511"),
 	DEVICE( AL,		AL_M1513,	"M1513"),
+	DEVICE( AL,		AL_M1521,	"M1521"),
+	DEVICE( AL,		AL_M1523,	"M1523"),
+	DEVICE( AL,		AL_M1531,	"M1531 Aladdin IV"),
+	DEVICE( AL,		AL_M1533,	"M1533 Aladdin IV"),
+	DEVICE( AL,		AL_M3307,	"M3307 MPEG-1 decoder"),
 	DEVICE( AL,		AL_M4803,	"M4803"),
+	DEVICE( AL,		AL_M5219,	"M5219"),
+	DEVICE( AL,		AL_M5229,	"M5229 TXpro"),
+	DEVICE( AL,		AL_M5237,	"M5237 USB"),
+	DEVICE( SURECOM,	SURECOM_NE34,	"NE-34PCI LAN"),
 	DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_NM2070,     "Magicgraph NM2070"),
 	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"),
+	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"),
+	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"),
 	DEVICE( ASP,		ASP_ABP940,	"ABP940"),
 	DEVICE( ASP,		ASP_ABP940U,	"ABP940U"),
+	DEVICE( ASP,		ASP_ABP940UW,	"ABP940UW"),
+	DEVICE( MACRONIX,	MACRONIX_MX98713,"MX98713"),
+	DEVICE( MACRONIX,	MACRONIX_MX987x5,"MX98715 / MX98725"),
 	DEVICE( CERN,		CERN_SPSB_PMC,	"STAR/RD24 SCI-PCI (PMC)"),
 	DEVICE( CERN,		CERN_SPSB_PCI,	"STAR/RD24 SCI-PCI (PMC)"),
+	DEVICE( CERN,		CERN_HIPPI_DST,	"HIPPI destination"),
+	DEVICE( CERN,		CERN_HIPPI_SRC,	"HIPPI source"),
 	DEVICE( IMS,		IMS_8849,	"8849"),
 	DEVICE( TEKRAM2,	TEKRAM2_690c,	"DC690c"),
 	DEVICE( TUNDRA,		TUNDRA_CA91C042,"CA91C042 Universe"),
 	DEVICE( AMCC,		AMCC_MYRINET,	"Myrinet PCI (M2-PCI-32)"),
 	DEVICE( AMCC,		AMCC_S5933,	"S5933"),
+	DEVICE( AMCC,		AMCC_S5933_HEPC3,"S5933 Traquair HEPC3"),
 	DEVICE( INTERG,		INTERG_1680,	"IGA-1680"),
 	DEVICE( INTERG,         INTERG_1682,    "IGA-1682"),
 	DEVICE( REALTEK,	REALTEK_8029,	"8029"),
 	DEVICE( REALTEK,	REALTEK_8129,	"8129"),
+	DEVICE( REALTEK,	REALTEK_8139,	"8139"),
 	DEVICE( TRUEVISION,	TRUEVISION_T1000,"TARGA 1000"),
 	DEVICE( INIT,		INIT_320P,	"320 P"),
+	DEVICE( INIT,		INIT_360P,	"360 P"),
 	DEVICE( VIA,		VIA_82C505,	"VT 82C505"),
 	DEVICE( VIA,		VIA_82C561,	"VT 82C561"),
-	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo VP-1"),
+	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo IDE"),
 	DEVICE( VIA,		VIA_82C576,	"VT 82C576 3V"),
-	DEVICE( VIA,		VIA_82C585,	"VT 82C585VP Apollo VP-1"),
-	DEVICE( VIA,		VIA_82C586_0,	"VT 82C586 Apollo VP-1"),
+	DEVICE( VIA,		VIA_82C585,	"VT 82C585 Apollo VP1/VPX"),
+	DEVICE( VIA,		VIA_82C586_0,	"VT 82C586 Apollo ISA"),
+	DEVICE( VIA,		VIA_82C595,	"VT 82C595 Apollo VP2"),
+	DEVICE( VIA,		VIA_82C597_0,	"VT 82C597 Apollo VP3"),
 	DEVICE( VIA,		VIA_82C926,	"VT 82C926 Amazon"),
 	DEVICE( VIA,		VIA_82C416,	"VT 82C416MV"),
+	DEVICE( VIA,		VIA_82C595_97,	"VT 82C595 Apollo VP2/97"),
+	DEVICE( VIA,		VIA_82C586_2,	"VT 82C586 Apollo USB"),
+	DEVICE( VIA,		VIA_82C586_3,	"VT 82C586B Apollo ACPI"),
+	DEVICE( VIA,		VIA_86C100A,	"VT 86C100A"),
+	DEVICE( VIA,		VIA_82C597_1,	"VT 82C597 Apollo VP3 AGP"),
 	DEVICE( VORTEX,		VORTEX_GDT60x0,	"GDT 60x0"),
 	DEVICE( VORTEX,		VORTEX_GDT6000B,"GDT 6000b"),
 	DEVICE( VORTEX,		VORTEX_GDT6x10,	"GDT 6110/6510"),
@@ -247,31 +348,66 @@
 	DEVICE( VORTEX,		VORTEX_GDT6x25,	"GDT 6125/6525"),
 	DEVICE( VORTEX,		VORTEX_GDT6535,	"GDT 6535"),
 	DEVICE( VORTEX,		VORTEX_GDT6555,	"GDT 6555"),
+	DEVICE( VORTEX,		VORTEX_GDT6x17RP,"GDT 6117RP/6517RP"),
+	DEVICE( VORTEX,		VORTEX_GDT6x27RP,"GDT 6127RP/6527RP"),
+	DEVICE( VORTEX,		VORTEX_GDT6537RP,"GDT 6537RP"),
+	DEVICE( VORTEX,		VORTEX_GDT6557RP,"GDT 6557RP"),
+	DEVICE( VORTEX,		VORTEX_GDT6x11RP,"GDT 6111RP/6511RP"),
+	DEVICE( VORTEX,		VORTEX_GDT6x21RP,"GDT 6121RP/6521RP"),
+	DEVICE( VORTEX,		VORTEX_GDT6x17RP1,"GDT 6117RP1/6517RP1"),
+	DEVICE( VORTEX,		VORTEX_GDT6x27RP1,"GDT 6127RP1/6527RP1"),
+	DEVICE( VORTEX,		VORTEX_GDT6537RP1,"GDT 6537RP1"),
+	DEVICE( VORTEX,		VORTEX_GDT6557RP1,"GDT 6557RP1"),
+	DEVICE( VORTEX,		VORTEX_GDT6x11RP1,"GDT 6111RP1/6511RP1"),
+	DEVICE( VORTEX,		VORTEX_GDT6x21RP1,"GDT 6121RP1/6521RP1"),
+	DEVICE( VORTEX,		VORTEX_GDT6x17RP2,"GDT 6117RP2/6517RP2"),
+	DEVICE( VORTEX,		VORTEX_GDT6x27RP2,"GDT 6127RP2/6527RP2"),
+	DEVICE( VORTEX,		VORTEX_GDT6537RP2,"GDT 6537RP2"),
+	DEVICE( VORTEX,		VORTEX_GDT6557RP2,"GDT 6557RP2"),
+	DEVICE( VORTEX,		VORTEX_GDT6x11RP2,"GDT 6111RP2/6511RP2"),
+	DEVICE( VORTEX,		VORTEX_GDT6x21RP2,"GDT 6121RP2/6521RP2"),
 	DEVICE( EF,		EF_ATM_FPGA,		"155P-MF1 (FPGA)"),
 	DEVICE( EF,		EF_ATM_ASIC,	"155P-MF1 (ASIC)"),
 	DEVICE( FORE,		FORE_PCA200PC, "PCA-200PC"),
 	DEVICE( FORE,		FORE_PCA200E,	 "PCA-200E"),
 	DEVICE( IMAGINGTECH,	IMAGINGTECH_ICPCI, "MVC IC-PCI"),
 	DEVICE( PHILIPS,	PHILIPS_SAA7146,"SAA7146"),
-	DEVICE( PLX,		PLX_9060,	"PCI9060 i960 bridge"),
+	DEVICE( CYCLONE,	CYCLONE_SDK,	"SDK"),
 	DEVICE( ALLIANCE,	ALLIANCE_PROMOTIO, "Promotion-6410"),
 	DEVICE( ALLIANCE,	ALLIANCE_PROVIDEO, "Provideo"),
+	DEVICE( ALLIANCE,	ALLIANCE_AT24,	"AT24"),
+	DEVICE( ALLIANCE,	ALLIANCE_AT3D,	"AT3D"),
 	DEVICE( VMIC,		VMIC_VME,	"VMIVME-7587"),
+	DEVICE( DIGI,		DIGI_EPC,	"AccelPort EPC"),
  	DEVICE( DIGI,		DIGI_RIGHTSWITCH, "RightSwitch SE-6"),
+	DEVICE( DIGI,		DIGI_XEM,	"AccelPort Xem"),
+	DEVICE( DIGI,		DIGI_XR,	"AccelPort Xr"),
+	DEVICE( DIGI,		DIGI_CX,	"AccelPort C/X"),
+	DEVICE( DIGI,		DIGI_XRJ,	"AccelPort Xr/J"),
+	DEVICE( DIGI,		DIGI_EPCJ,	"AccelPort EPC/J"),
+	DEVICE( DIGI,		DIGI_XR_920,	"AccelPort Xr 920"),
 	DEVICE( MUTECH,		MUTECH_MV1000,	"MV-1000"),
 	DEVICE( RENDITION,	RENDITION_VERITE,"Verite 1000"),
+	DEVICE( RENDITION,	RENDITION_VERITE2100,"Verite 2100"),
 	DEVICE( TOSHIBA,	TOSHIBA_601,	"Laptop"),
+	DEVICE( TOSHIBA,	TOSHIBA_TOPIC95,"ToPIC95"),
+	DEVICE( TOSHIBA,	TOSHIBA_TOPIC97,"ToPIC97"),
 	DEVICE( RICOH,		RICOH_RL5C466,	"RL5C466"),
+	DEVICE( ARTOP,		ARTOP_ATP850UF,	"ATP850UF"),
 	DEVICE( ZEITNET,	ZEITNET_1221,	"1221"),
 	DEVICE( ZEITNET,	ZEITNET_1225,	"1225"),
 	DEVICE( OMEGA,		OMEGA_82C092G,	"82C092G"),
+	DEVICE( LITEON,		LITEON_LNE100TX,"LNE100TX"),
 	DEVICE( NP,		NP_PCI_FDDI,	"NP-PCI"),       
+	DEVICE( ATT,		ATT_L56XMF,	"L56xMF"),
 	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host"),
 	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host"),
+	DEVICE( AURAVISION,	AURAVISION_VXP524,"VXP524"),
 	DEVICE( IKON,		IKON_10115,	"10115 Greensheet"),
 	DEVICE( IKON,		IKON_10117,	"10117 Greensheet"),
 	DEVICE( ZORAN,		ZORAN_36057,	"ZR36057"),
 	DEVICE( ZORAN,		ZORAN_36120,	"ZR36120"),
+	DEVICE( KINETIC,	KINETIC_2915,	"2915 CAMAC"),
 	DEVICE( COMPEX,		COMPEX_ENET100VG4, "Readylink ENET100-VG4"),
 	DEVICE( COMPEX,		COMPEX_RL2000,	"ReadyLink 2000"),
 	DEVICE( RP,             RP8OCTA,        "RocketPort 8 Oct"),
@@ -282,19 +418,32 @@
 	DEVICE( CYCLADES,	CYCLOM_Y_Hi,	"Cyclom-Y above 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Lo,	"Cyclom-Z below 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Hi,	"Cyclom-Z above 1Mbyte"),
+	DEVICE( ESSENTIAL,	ESSENTIAL_ROADRUNNER,"Roadrunner serial HIPPI"),
+	DEVICE( O2,		O2_6832,	"6832"),
 	DEVICE( 3DFX,		3DFX_VOODOO,	"Voodoo"),
+	DEVICE( 3DFX,		3DFX_VOODOO2,	"Voodoo2"),
 	DEVICE( SIGMADES,	SIGMADES_6425,	"REALmagic64/GX"),
+	DEVICE( STALLION,	STALLION_ECHPCI832,"EasyConnection 8/32"),
+	DEVICE( STALLION,	STALLION_ECHPCI864,"EasyConnection 8/64"),
+	DEVICE( STALLION,	STALLION_EIOPCI,"EasyIO"),
 	DEVICE( OPTIBASE,	OPTIBASE_FORGE,	"MPEG Forge"),
 	DEVICE( OPTIBASE,	OPTIBASE_FUSION,"MPEG Fusion"),
 	DEVICE( OPTIBASE,	OPTIBASE_VPLEX,	"VideoPlex"),
 	DEVICE( OPTIBASE,	OPTIBASE_VPLEXCC,"VideoPlex CC"),
 	DEVICE( OPTIBASE,	OPTIBASE_VQUEST,"VideoQuest"),
+	DEVICE( SATSAGEM,	SATSAGEM_PCR2101,"PCR2101 DVB receiver"),
+	DEVICE( SATSAGEM,	SATSAGEM_TELSATTURBO,"Telsat Turbo DVB"),
+	DEVICE( ENSONIQ,	ENSONIQ_AUDIOPCI,"AudioPCI"),
+	DEVICE( PICTUREL,	PICTUREL_PCIVST,"PCIVST"),
+	DEVICE( NVIDIA_SGS,	NVIDIA_SGS_RIVA128,	"Riva 128"),
+	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16"),
 	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
 	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
 	DEVICE( 3DLABS,		3DLABS_500TX,	"GLINT 500TX"),
 	DEVICE( 3DLABS,		3DLABS_DELTA,	"GLINT Delta"),
 	DEVICE( 3DLABS,		3DLABS_PERMEDIA,"PERMEDIA"),
+	DEVICE( 3DLABS,		3DLABS_MX,	"GLINT MX"),
 	DEVICE( AVANCE,		AVANCE_ALG2064,	"ALG2064i"),
 	DEVICE( AVANCE,		AVANCE_2302,	"ALG-2302"),
 	DEVICE( NETVIN,		NETVIN_NV5000SC,"NV5000"),
@@ -315,6 +464,10 @@
 	DEVICE( S3,		S3_PLATO_PXG,	"PLATO/PX (graphics)"),
 	DEVICE( S3,		S3_ViRGE_DXGX,	"ViRGE/DX or /GX"),
 	DEVICE( S3,		S3_ViRGE_GX2,	"ViRGE/GX2"),
+	DEVICE( S3,		S3_ViRGE_MX,	"ViRGE/MX"),
+	DEVICE( S3,		S3_ViRGE_MXP,	"ViRGE/MX+"),
+	DEVICE( S3,		S3_ViRGE_MXPMV,	"ViRGE/MX+MV"),
+	DEVICE( S3,		S3_SONICVIBES,	"SonicVibes"),
 	DEVICE( INTEL,		INTEL_82375,	"82375EB"),
 	BRIDGE( INTEL,		INTEL_82424,	"82424ZX Saturn",	0x00),
 	DEVICE( INTEL,		INTEL_82378,	"82378IB"),
@@ -332,21 +485,29 @@
 	DEVICE( INTEL,		INTEL_82371MX,	"430MX - 82371MX MPIIX"),
 	DEVICE( INTEL,		INTEL_82437MX,	"430MX - 82437MX MTSC"),
 	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
+	DEVICE( INTEL,		INTEL_82380FB,	"82380FB Mobile"),
 	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
-	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"),
-	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX3"),
-	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"),
+	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB PIIX3 ISA"),
+	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB PIIX3 IDE"),
+	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB PIIX3 USB"),
 	DEVICE( INTEL,		INTEL_82437VX,	"82437VX Triton II"),
 	DEVICE( INTEL,		INTEL_82439TX,	"82439TX"),
-	DEVICE( INTEL,		INTEL_82371AB_0,"82371AB PIIX4"),
-	DEVICE( INTEL,		INTEL_82371AB,	"82371AB 430TX PIIX4"),
-	DEVICE( INTEL,		INTEL_82371AB_2,"82371AB PIIX4"),
-	DEVICE( INTEL,		INTEL_82371AB_3,"82371AB PIIX4 Power Management"),
+	DEVICE( INTEL,		INTEL_82371AB_0,"82371AB PIIX4 ISA"),
+	DEVICE( INTEL,		INTEL_82371AB,	"82371AB PIIX4 IDE"),
+	DEVICE( INTEL,		INTEL_82371AB_2,"82371AB PIIX4 USB"),
+	DEVICE( INTEL,		INTEL_82371AB_3,"82371AB PIIX4 ACPI"),
+	DEVICE( INTEL,		INTEL_82443LX_0,"440LX - 82443LX PAC Host"),
+	DEVICE( INTEL,		INTEL_82443LX_1,"440LX - 82443LX PAC AGP"),
+	DEVICE( INTEL,		INTEL_82443BX_0,"440BX - 82443BX Host"),
+	DEVICE( INTEL,		INTEL_82443BX_1,"440BX - 82443BX AGP"),
+	DEVICE( INTEL,		INTEL_82443BX_2,"440BX - 82443BX Host (no AGP)"),
 	DEVICE( INTEL,		INTEL_P6,	"Orion P6"),
  	DEVICE( INTEL,		INTEL_82450GX,	"82450GX Orion P6"),
 	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2"),
+	DEVICE( ADAPTEC,	ADAPTEC_7810,	"AIC-7810 RAID"),
 	DEVICE( ADAPTEC,	ADAPTEC_7850,	"AIC-7850"),
 	DEVICE( ADAPTEC,	ADAPTEC_7855,	"AIC-7855"),
+	DEVICE( ADAPTEC,	ADAPTEC_5800,	"AIC-5800"),
 	DEVICE( ADAPTEC,	ADAPTEC_7860,	"AIC-7860"),
 	DEVICE( ADAPTEC,	ADAPTEC_7861,	"AIC-7861"),
 	DEVICE( ADAPTEC,	ADAPTEC_7870,	"AIC-7870"),
@@ -354,12 +515,15 @@
 	DEVICE( ADAPTEC,	ADAPTEC_7872,	"AIC-7872"),
 	DEVICE( ADAPTEC,	ADAPTEC_7873,	"AIC-7873"),
 	DEVICE( ADAPTEC,	ADAPTEC_7874,	"AIC-7874"),
+	DEVICE( ADAPTEC,	ADAPTEC_7895,	"AIC-7895U"),
 	DEVICE( ADAPTEC,	ADAPTEC_7880,	"AIC-7880U"),
 	DEVICE( ADAPTEC,	ADAPTEC_7881,	"AIC-7881U"),
 	DEVICE( ADAPTEC,	ADAPTEC_7882,	"AIC-7882U"),
 	DEVICE( ADAPTEC,	ADAPTEC_7883,	"AIC-7883U"),
 	DEVICE( ADAPTEC,	ADAPTEC_7884,	"AIC-7884U"),
+	DEVICE( ADAPTEC,	ADAPTEC_1030,	"ABA-1030 DVB receiver"),
   	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL"),
+	DEVICE( TIGERJET,	TIGERJET_300,	"Tiger300 ISDN"),
 	DEVICE( ARK,		ARK_STING,	"Stingray"),
 	DEVICE( ARK,		ARK_STINGARK,	"Stingray ARK 2000PV"),
 	DEVICE( ARK,		ARK_2000MT,	"2000MT")
@@ -576,6 +740,7 @@
 	      case PCI_VENDOR_ID_MATROX:	return "Matrox";
 	      case PCI_VENDOR_ID_CT:		return "Chips & Technologies";
 	      case PCI_VENDOR_ID_MIRO:		return "Miro";
+	      case PCI_VENDOR_ID_NEC:		return "NEC";
 	      case PCI_VENDOR_ID_FD:		return "Future Domain";
 	      case PCI_VENDOR_ID_SI:		return "Silicon Integrated Systems";
 	      case PCI_VENDOR_ID_HP:		return "Hewlett Packard";
@@ -728,15 +893,16 @@
 static int sprint_dev_config(struct pci_dev *dev, char *buf, int size)
 {
 	unsigned long base;
-	unsigned int l, class_rev, bus, devfn;
+	unsigned int l, class_rev, bus, devfn, last_reg;
 	unsigned short vendor, device, status;
-	unsigned char bist, latency, min_gnt, max_lat;
+	unsigned char bist, latency, min_gnt, max_lat, hdr_type;
 	int reg, len = 0;
 	const char *str;
 
 	bus   = dev->bus->number;
 	devfn = dev->devfn;
 
+	pcibios_read_config_byte (bus, devfn, PCI_HEADER_TYPE, &hdr_type);
 	pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev);
 	pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor);
 	pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device);
@@ -815,7 +981,17 @@
 		  len += sprintf(buf + len, "Max Lat=%d.", max_lat);
 	}
 
-	for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+	switch (hdr_type & 0x7f) {
+		case 0:
+			last_reg = PCI_BASE_ADDRESS_5;
+			break;
+		case 1:
+			last_reg = PCI_BASE_ADDRESS_1;
+			break;
+		default:
+			last_reg = 0;
+	}
+	for (reg = PCI_BASE_ADDRESS_0; reg <= last_reg; reg += 4) {
 		if (len + 40 > size) {
 			return -1;
 		}
@@ -908,7 +1084,7 @@
 static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
 {
 	unsigned int devfn, l, max;
-	unsigned char cmd, tmp, hdr_type = 0;
+	unsigned char cmd, tmp, hdr_type, ht, is_multi = 0;
 	struct pci_dev_info *info;
 	struct pci_dev *dev;
 	struct pci_bus *child;
@@ -919,32 +1095,23 @@
 
 	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);
-		} else if (!(hdr_type & 0x80)) {
-			/* not a multi-function device */
+		if (PCI_FUNC(devfn) && !is_multi) {
+			/* Not a multi-function device */
 			continue;
 		}
+		pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type);
+		if (!PCI_FUNC(devfn))
+			is_multi = hdr_type & 0x80;
 
-		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;
+			is_multi = 0;
 			continue;
 		}
 
 		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;
@@ -956,8 +1123,10 @@
 		 */
 		info = pci_lookup_dev(dev->vendor, dev->device);
 		if (!info) {
-			printk("Warning : Unknown PCI device (%x:%x).  Please read include/linux/pci.h \n",
+#if 0
+			printk("Warning : Unknown PCI device (%x:%x).  Please read include/linux/pci.h\n",
 				dev->vendor, dev->device);
+#endif
 		} else {
 			/* Some BIOS' are lazy. Let's do their job: */
 			if (info->bridge_type != 0xff) {
@@ -986,6 +1155,35 @@
 					  PCI_CLASS_REVISION, &l);
 		l = l >> 8;			/* upper 3 bytes */
 		dev->class = l;
+
+		/*
+		 * Check if the header type is known and consistent with
+		 * device type. PCI-to-PCI Bridges should have hdr_type 1,
+		 * CardBus Bridges 2, all other devices 0.
+		 */
+		switch (dev->class >> 8) {
+			case PCI_CLASS_BRIDGE_PCI:
+				ht = 1;
+				break;
+			case PCI_CLASS_BRIDGE_CARDBUS:
+				ht = 2;
+				break;
+			default:
+				ht = 0;
+		}
+		if (ht != (hdr_type & 0x7f)) {
+			printk(KERN_WARNING "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
+				bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type);
+			continue;
+		}
+
+		/*
+		 * Put it into the simple chain of all PCI devices.
+		 * It is used to find devices once everything is set up.
+		 */
+		dev->next = pci_devices;
+		pci_devices = dev;
+
 		/*
 		 * Now insert it into the list of devices held
 		 * by the parent bus.
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.0.33/linux/drivers/scsi/BusLogic.c	Mon Aug 11 00:10:00 1997
+++ linux/drivers/scsi/BusLogic.c	Wed Jun  3 15:17:48 1998
@@ -2,12 +2,11 @@
 
   Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
 
-  Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
-  Free Software Foundation, provided that none of the source code or runtime
-  copyright notices are removed or modified.
+  Free Software Foundation.
 
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
@@ -27,17 +26,17 @@
 */
 
 
-#define BusLogic_DriverVersion		"2.0.10"
-#define BusLogic_DriverDate		"11 August 1997"
+#define BusLogic_DriverVersion		"2.0.14"
+#define BusLogic_DriverDate		"29 April 1998"
 
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
-#include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
@@ -45,30 +44,43 @@
 #include <linux/bios32.h>
 #include <asm/dma.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/system.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
 #include "BusLogic.h"
+#include "FlashPoint.c"
 
 
 /*
-  BusLogic_CommandLineEntryCount is a count of the number of "BusLogic="
-  entries provided on the Linux Kernel Command Line.
+  BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver
+  Options specifications provided via the Linux Kernel Command Line or via
+  the Loadable Kernel Module Installation Facility.
 */
 
 static int
-  BusLogic_CommandLineEntryCount =	0;
+  BusLogic_DriverOptionsCount =			0;
 
 
 /*
-  BusLogic_CommandLineEntries is an array of Command Line Entry structures
-  representing the "BusLogic=" entries provided on the Linux Kernel Command
-  Line.
+  BusLogic_DriverOptions is an array of Driver Options structures representing
+  BusLogic Driver Options specifications provided via the Linux Kernel Command
+  Line or via the Loadable Kernel Module Installation Facility.
 */
 
-static BusLogic_CommandLineEntry_T
-  BusLogic_CommandLineEntries[BusLogic_MaxHostAdapters];
+static BusLogic_DriverOptions_T
+  BusLogic_DriverOptions[BusLogic_MaxHostAdapters];
+
+
+/*
+  BusLogic_Options can be assigned a string by the Loadable Kernel Module
+  Installation Facility to be parsed for BusLogic Driver Options
+  specifications.
+*/
+
+static char
+  *BusLogic_Options =				NULL;
 
 
 /*
@@ -77,7 +89,7 @@
 */
 
 static BusLogic_ProbeOptions_T
-  BusLogic_ProbeOptions =		{ 0 };
+  BusLogic_ProbeOptions =			{ 0 };
 
 
 /*
@@ -86,24 +98,25 @@
 */
 
 static BusLogic_GlobalOptions_T
-  BusLogic_GlobalOptions =		{ 0 };
+  BusLogic_GlobalOptions =			{ 0 };
 
 
 /*
-  BusLogic_RegisteredHostAdapters is an array of linked lists of all the
-  registered BusLogic Host Adapters, indexed by IRQ Channel.
+  BusLogic_FirstRegisteredHostAdapter and BusLogic_LastRegisteredHostAdapter
+  are pointers to the first and last registered BusLogic Host Adapters.
 */
 
 static BusLogic_HostAdapter_T
-  *BusLogic_RegisteredHostAdapters[NR_IRQS] =	{ NULL };
+  *BusLogic_FirstRegisteredHostAdapter =	NULL,
+  *BusLogic_LastRegisteredHostAdapter =		NULL;
 
 
 /*
-  BusLogic_ProbeInfoCount is the numbers of entries in BusLogic_ProbeInfoList.
+  BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.
 */
 
 static int
-  BusLogic_ProbeInfoCount =		0;
+  BusLogic_ProbeInfoCount =			0;
 
 
 /*
@@ -114,7 +127,7 @@
 */
 
 static BusLogic_ProbeInfo_T
-  BusLogic_ProbeInfoList[BusLogic_MaxHostAdapters] =	{ { 0 } };
+  *BusLogic_ProbeInfoList =			NULL;
 
 
 /*
@@ -128,16 +141,6 @@
 
 
 /*
-  BusLogic_FirstCompletedCCB and BusLogic_LastCompletedCCB are pointers
-  to the first and last CCBs that are queued for completion processing.
-*/
-
-static BusLogic_CCB_T
-  *BusLogic_FirstCompletedCCB =		NULL,
-  *BusLogic_LastCompletedCCB =		NULL;
-
-
-/*
   BusLogic_ProcDirectoryEntry is the BusLogic /proc/scsi directory entry.
 */
 
@@ -156,7 +159,7 @@
   BusLogic_Announce("***** BusLogic SCSI Driver Version "
 		    BusLogic_DriverVersion " of "
 		    BusLogic_DriverDate " *****\n", HostAdapter);
-  BusLogic_Announce("Copyright 1995 by Leonard N. Zubkoff "
+  BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff "
 		    "<lnz@dandelion.com>\n", HostAdapter);
 }
 
@@ -182,16 +185,16 @@
 static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 {
   HostAdapter->Next = NULL;
-  if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL)
+  if (BusLogic_FirstRegisteredHostAdapter == NULL)
+    {
+      BusLogic_FirstRegisteredHostAdapter = HostAdapter;
+      BusLogic_LastRegisteredHostAdapter = HostAdapter;
+    }
+  else
     {
-      BusLogic_HostAdapter_T *LastHostAdapter =
-	BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
-      BusLogic_HostAdapter_T *NextHostAdapter;
-      while ((NextHostAdapter = LastHostAdapter->Next) != NULL)
-	LastHostAdapter = NextHostAdapter;
-      LastHostAdapter->Next = HostAdapter;
+      BusLogic_LastRegisteredHostAdapter->Next = HostAdapter;
+      BusLogic_LastRegisteredHostAdapter = HostAdapter;
     }
-  else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] = HostAdapter;
 }
 
 
@@ -202,101 +205,55 @@
 
 static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 {
-  if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter)
+  if (HostAdapter == BusLogic_FirstRegisteredHostAdapter)
     {
-      BusLogic_HostAdapter_T *LastHostAdapter =
-	BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
-      while (LastHostAdapter != NULL && LastHostAdapter->Next != HostAdapter)
-	LastHostAdapter = LastHostAdapter->Next;
-      if (LastHostAdapter != NULL)
-	LastHostAdapter->Next = HostAdapter->Next;
+      BusLogic_FirstRegisteredHostAdapter =
+	BusLogic_FirstRegisteredHostAdapter->Next;
+      if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
+	BusLogic_LastRegisteredHostAdapter = NULL;
     }
-  else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] =
-	 HostAdapter->Next;
-  HostAdapter->Next = NULL;
-}
-
-
-/*
-  BusLogic_CreateMailboxes allocates the Outgoing and Incoming Mailboxes for
-  Host Adapter.
-*/
-
-static boolean BusLogic_CreateMailboxes(BusLogic_HostAdapter_T *HostAdapter)
-{
-  /*
-    FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
-  */
-  if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
-  /*
-    Allocate space for the Outgoing and Incoming Mailboxes.
-  */
-  HostAdapter->FirstOutgoingMailbox =
-    (BusLogic_OutgoingMailbox_T *)
-      scsi_init_malloc(HostAdapter->MailboxCount
-		       * (sizeof(BusLogic_OutgoingMailbox_T)
-			  + sizeof(BusLogic_IncomingMailbox_T)),
-		       (HostAdapter->BounceBuffersRequired
-			? GFP_ATOMIC | GFP_DMA
-			: GFP_ATOMIC));
-  if (HostAdapter->FirstOutgoingMailbox == NULL)
+  else
     {
-      BusLogic_Error("UNABLE TO ALLOCATE MAILBOXES - DETACHING\n",
-		     HostAdapter, HostAdapter->HostNumber);
-      return false;
+      BusLogic_HostAdapter_T *PreviousHostAdapter =
+	BusLogic_FirstRegisteredHostAdapter;
+      while (PreviousHostAdapter != NULL &&
+	     PreviousHostAdapter->Next != HostAdapter)
+	PreviousHostAdapter = PreviousHostAdapter->Next;
+      if (PreviousHostAdapter != NULL)
+	PreviousHostAdapter->Next = HostAdapter->Next;
     }
-  HostAdapter->LastOutgoingMailbox =
-    HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
-  HostAdapter->FirstIncomingMailbox =
-    (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
-  HostAdapter->LastIncomingMailbox =
-    HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
-  return true;
-}
-
-
-/*
-  BusLogic_DestroyMailboxes deallocates the Outgoing and Incoming Mailboxes
-  for Host Adapter.
-*/
-
-static void BusLogic_DestroyMailboxes(BusLogic_HostAdapter_T *HostAdapter)
-{
-  if (HostAdapter->FirstOutgoingMailbox == NULL) return;
-  scsi_init_free((char *) HostAdapter->FirstOutgoingMailbox,
-		 HostAdapter->MailboxCount
-		 * (sizeof(BusLogic_OutgoingMailbox_T)
-		    + sizeof(BusLogic_IncomingMailbox_T)));
+  HostAdapter->Next = NULL;
 }
 
 
 /*
-  BusLogic_CreateCCB allocates and initializes a single Command Control
-  Block (CCB) for Host Adapter, and adds it to Host Adapter's free list.
-*/
-
-static boolean BusLogic_CreateCCB(BusLogic_HostAdapter_T *HostAdapter)
-{
-  BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
-    scsi_init_malloc(sizeof(BusLogic_CCB_T),
-		     (HostAdapter->BounceBuffersRequired
-		      ? GFP_ATOMIC | GFP_DMA
-		      : GFP_ATOMIC));
-  if (CCB == NULL) return false;
-  memset(CCB, 0, sizeof(BusLogic_CCB_T));
-  CCB->HostAdapter = HostAdapter;
-  CCB->Status = BusLogic_CCB_Free;
-  if (BusLogic_FlashPointHostAdapterP(HostAdapter))
-    {
-      CCB->CallbackFunction = BusLogic_QueueCompletedCCB;
-      CCB->BaseAddress = HostAdapter->IO_Address;
+  BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs)
+  for Host Adapter from the BlockSize bytes located at BlockPointer.  The newly
+  created CCBs are added to Host Adapter's free list.
+*/
+
+static void BusLogic_InitializeCCBs(BusLogic_HostAdapter_T *HostAdapter,
+				    void *BlockPointer, int BlockSize)
+{
+  BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) BlockPointer;
+  memset(BlockPointer, 0, BlockSize);
+  CCB->AllocationGroupHead = true;
+  while ((BlockSize -= sizeof(BusLogic_CCB_T)) >= 0)
+    {
+      CCB->Status = BusLogic_CCB_Free;
+      CCB->HostAdapter = HostAdapter;
+      if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+	{
+	  CCB->CallbackFunction = BusLogic_QueueCompletedCCB;
+	  CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress;
+	}
+      CCB->Next = HostAdapter->Free_CCBs;
+      CCB->NextAll = HostAdapter->All_CCBs;
+      HostAdapter->Free_CCBs = CCB;
+      HostAdapter->All_CCBs = CCB;
+      HostAdapter->AllocatedCCBs++;
+      CCB++;
     }
-  CCB->Next = HostAdapter->Free_CCBs;
-  CCB->NextAll = HostAdapter->All_CCBs;
-  HostAdapter->Free_CCBs = CCB;
-  HostAdapter->All_CCBs = CCB;
-  HostAdapter->AllocatedCCBs++;
-  return true;
 }
 
 
@@ -306,14 +263,21 @@
 
 static boolean BusLogic_CreateInitialCCBs(BusLogic_HostAdapter_T *HostAdapter)
 {
-  int Allocated;
-  for (Allocated = 0; Allocated < HostAdapter->InitialCCBs; Allocated++)
-    if (!BusLogic_CreateCCB(HostAdapter))
-      {
-	BusLogic_Error("UNABLE TO ALLOCATE CCB %d - DETACHING\n",
-		       HostAdapter, Allocated);
-	return false;
-      }
+  int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T);
+  while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs)
+    {
+      void *BlockPointer = kmalloc(BlockSize,
+				   (HostAdapter->BounceBuffersRequired
+				    ? GFP_ATOMIC | GFP_DMA
+				    : GFP_ATOMIC));
+      if (BlockPointer == NULL)
+	{
+	  BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n",
+			 HostAdapter);
+	  return false;
+	}
+      BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize);
+    }
   return true;
 }
 
@@ -330,7 +294,8 @@
   while ((CCB = NextCCB) != NULL)
     {
       NextCCB = CCB->NextAll;
-      scsi_init_free((char *) CCB, sizeof(BusLogic_CCB_T));
+      if (CCB->AllocationGroupHead)
+	kfree(CCB);
     }
 }
 
@@ -346,18 +311,35 @@
 					  int AdditionalCCBs,
 					  boolean SuccessMessageP)
 {
-  int Allocated;
+  int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T);
+  int PreviouslyAllocated = HostAdapter->AllocatedCCBs;
   if (AdditionalCCBs <= 0) return;
-  for (Allocated = 0; Allocated < AdditionalCCBs; Allocated++)
-    if (!BusLogic_CreateCCB(HostAdapter)) break;
-  if (Allocated > 0 && SuccessMessageP)
-    BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n",
-		    HostAdapter, Allocated, HostAdapter->AllocatedCCBs);
-  if (Allocated > 0) return;
+  while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs)
+    {
+      void *BlockPointer = kmalloc(BlockSize,
+				   (HostAdapter->BounceBuffersRequired
+				    ? GFP_ATOMIC | GFP_DMA
+				    : GFP_ATOMIC));
+      if (BlockPointer == NULL) break;
+      BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize);
+    }
+  if (HostAdapter->AllocatedCCBs > PreviouslyAllocated)
+    {
+      if (SuccessMessageP)
+	BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n",
+			HostAdapter,
+			HostAdapter->AllocatedCCBs - PreviouslyAllocated,
+			HostAdapter->AllocatedCCBs);
+      return;
+    }
   BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter);
-  HostAdapter->DriverQueueDepth =
-    HostAdapter->AllocatedCCBs - (HostAdapter->MaxTargetDevices - 1);
-  HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth;
+  if (HostAdapter->DriverQueueDepth >
+      HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount)
+    {
+      HostAdapter->DriverQueueDepth =
+	HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount;
+      HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth;
+    }
 }
 
 
@@ -413,47 +395,6 @@
 
 
 /*
-  BusLogic_CreateTargetDeviceStatistics creates the Target Device Statistics
-  structure for Host Adapter.
-*/
-
-static boolean BusLogic_CreateTargetDeviceStatistics(BusLogic_HostAdapter_T
-						     *HostAdapter)
-{
-  HostAdapter->TargetDeviceStatistics =
-    (BusLogic_TargetDeviceStatistics_T *)
-      scsi_init_malloc(HostAdapter->MaxTargetDevices
-		       * sizeof(BusLogic_TargetDeviceStatistics_T),
-		       GFP_ATOMIC);
-  if (HostAdapter->TargetDeviceStatistics == NULL)
-    {
-      BusLogic_Error("UNABLE TO ALLOCATE TARGET DEVICE STATISTICS - "
-		     "DETACHING\n", HostAdapter, HostAdapter->HostNumber);
-      return false;
-    }
-  memset(HostAdapter->TargetDeviceStatistics, 0,
-	 HostAdapter->MaxTargetDevices
-	 * sizeof(BusLogic_TargetDeviceStatistics_T));
-  return true;
-}
-
-
-/*
-  BusLogic_DestroyTargetDeviceStatistics destroys the Target Device Statistics
-  structure for Host Adapter.
-*/
-
-static void BusLogic_DestroyTargetDeviceStatistics(BusLogic_HostAdapter_T
-						   *HostAdapter)
-{
-  if (HostAdapter->TargetDeviceStatistics == NULL) return;
-  scsi_init_free((char *) HostAdapter->TargetDeviceStatistics,
-		 HostAdapter->MaxTargetDevices
-		 * sizeof(BusLogic_TargetDeviceStatistics_T));
-}
-
-
-/*
   BusLogic_Command sends the command OperationCode to HostAdapter, optionally
   providing ParameterLength bytes of ParameterData and receiving at most
   ReplyLength bytes of ReplyData; any excess reply data is received but
@@ -482,7 +423,7 @@
   unsigned char *ReplyPointer = (unsigned char *) ReplyData;
   BusLogic_StatusRegister_T StatusRegister;
   BusLogic_InterruptRegister_T InterruptRegister;
-  unsigned long ProcessorFlags = 0;
+  ProcessorFlags_T ProcessorFlags = 0;
   int ReplyBytes = 0, Result;
   long TimeoutCounter;
   /*
@@ -494,7 +435,7 @@
     If the IRQ Channel has not yet been acquired, then interrupts must be
     disabled while issuing host adapter commands since a Command Complete
     interrupt could occur if the IRQ Channel was previously enabled by another
-    BusLogic Host Adapter or other driver sharing the same IRQ Channel.
+    BusLogic Host Adapter or another driver sharing the same IRQ Channel.
   */
   if (!HostAdapter->IRQ_ChannelAcquired)
     {
@@ -572,7 +513,7 @@
 	  Result = -1;
 	  goto Done;
 	}
-      if (BusLogic_GlobalOptions.Bits.TraceConfiguration)
+      if (BusLogic_GlobalOptions.TraceConfiguration)
 	BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: "
 			"(Modify I/O Address)\n", HostAdapter,
 			OperationCode, StatusRegister.All);
@@ -607,9 +548,11 @@
       if (InterruptRegister.Bits.CommandComplete) break;
       if (HostAdapter->HostAdapterCommandCompleted) break;
       if (StatusRegister.Bits.DataInRegisterReady)
-	if (++ReplyBytes <= ReplyLength)
-	  *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
-	else BusLogic_ReadDataInRegister(HostAdapter);
+	{
+	  if (++ReplyBytes <= ReplyLength)
+	    *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
+	  else BusLogic_ReadDataInRegister(HostAdapter);
+	}
       if (OperationCode == BusLogic_FetchHostAdapterLocalRAM &&
 	  StatusRegister.Bits.HostAdapterReady) break;
       udelay(100);
@@ -621,34 +564,24 @@
       goto Done;
     }
   /*
-    If testing Command Complete Interrupts, wait a short while in case the
-    loop immediately above terminated due to the Command Complete bit being
-    set in the Interrupt Register, but the interrupt hasn't actually been
-    processed yet.  Otherwise, acknowledging the interrupt here could prevent
-    the interrupt test from succeeding.
-  */
-  if (OperationCode == BusLogic_TestCommandCompleteInterrupt)
-    udelay(10000);
-  /*
     Clear any pending Command Complete Interrupt.
   */
   BusLogic_InterruptReset(HostAdapter);
   /*
     Provide tracing information if requested.
   */
-  if (BusLogic_GlobalOptions.Bits.TraceConfiguration)
-    if (OperationCode != BusLogic_TestCommandCompleteInterrupt)
-      {
-	int i;
-	BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:",
-			HostAdapter, OperationCode,
-			StatusRegister.All, ReplyLength, ReplyBytes);
-	if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes;
-	for (i = 0; i < ReplyLength; i++)
-	  BusLogic_Notice(" %02X", HostAdapter,
-			  ((unsigned char *) ReplyData)[i]);
-	BusLogic_Notice("\n", HostAdapter);
-      }
+  if (BusLogic_GlobalOptions.TraceConfiguration)
+    {
+      int i;
+      BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:",
+		      HostAdapter, OperationCode,
+		      StatusRegister.All, ReplyLength, ReplyBytes);
+      if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes;
+      for (i = 0; i < ReplyLength; i++)
+	BusLogic_Notice(" %02X", HostAdapter,
+			((unsigned char *) ReplyData)[i]);
+      BusLogic_Notice("\n", HostAdapter);
+    }
   /*
     Process Command Invalid conditions.
   */
@@ -705,38 +638,63 @@
 
 
 /*
+  BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list
+  of I/O Address and Bus Probe Information to be checked for potential BusLogic
+  Host Adapters.
+*/
+
+static void BusLogic_AppendProbeAddressISA(BusLogic_IO_Address_T IO_Address)
+{
+  BusLogic_ProbeInfo_T *ProbeInfo;
+  if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return;
+  ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+  ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+  ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+  ProbeInfo->IO_Address = IO_Address;
+}
+
+
+/*
   BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and
   Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters
   only from the list of standard BusLogic MultiMaster ISA I/O Addresses.
 */
 
-static void BusLogic_InitializeProbeInfoListISA(void)
+static void BusLogic_InitializeProbeInfoListISA(BusLogic_HostAdapter_T
+						*PrototypeHostAdapter)
 {
-  int StandardAddressIndex;
-  /*
-    If BusLogic_Setup has provided an I/O Address probe list, do not override
-    the Kernel Command Line specifications.
-  */
-  if (BusLogic_ProbeInfoCount > 0) return;
   /*
-    If a Kernel Command Line specification has requested that ISA Bus Probes
+    If BusLogic Driver Options specifications requested that ISA Bus Probes
     be inhibited, do not proceed further.
   */
-  if (BusLogic_ProbeOptions.Bits.NoProbeISA) return;
+  if (BusLogic_ProbeOptions.NoProbeISA) return;
   /*
     Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
   */
-  StandardAddressIndex = 0;
-  while (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters &&
-	 StandardAddressIndex < BusLogic_ISA_StandardAddressesCount)
-    {
-      BusLogic_ProbeInfo_T *ProbeInfo =
-	&BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-      ProbeInfo->IO_Address =
-	BusLogic_ISA_StandardAddresses[StandardAddressIndex++];
-      ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-      ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-    }
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe330
+      : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x330);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe334
+      : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x334);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe230
+      : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x230);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe234
+      : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x234);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe130
+      : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x130);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe134
+      : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x134);
 }
 
 
@@ -783,25 +741,26 @@
   I/O Addresses.  It returns the number of PCI MultiMaster Host Adapters found.
 */
 
-static int BusLogic_InitializeMultiMasterProbeInfo(void)
+static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
+						   *PrototypeHostAdapter)
 {
-  boolean StandardAddressSeen[BusLogic_ISA_StandardAddressesCount];
   BusLogic_ProbeInfo_T *PrimaryProbeInfo =
     &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount];
   int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1;
   int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0;
   boolean ForceBusDeviceScanningOrder = false;
   boolean ForceBusDeviceScanningOrderChecked = false;
-  unsigned char Bus, DeviceFunction, IRQ_Channel;
+  boolean StandardAddressSeen[6];
+  unsigned char Bus, DeviceFunction;
   unsigned int BaseAddress0, BaseAddress1;
+  unsigned char IRQ_Channel;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
   unsigned short Index = 0;
-  int StandardAddressIndex, i;
-  if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters)
-    return 0;
+  int i;
+  if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0;
   BusLogic_ProbeInfoCount++;
-  for (i = 0; i < BusLogic_ISA_StandardAddressesCount; i++)
+  for (i = 0; i < 6; i++)
     StandardAddressSeen[i] = false;
   /*
     Iterate over the MultiMaster PCI Host Adapters.  For each enumerated host
@@ -826,8 +785,7 @@
 	pcibios_read_config_byte(Bus, DeviceFunction,
 				 PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
       {
-	BusLogic_HostAdapter_T HostAdapterPrototype;
-	BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+	BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
 	BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation;
 	BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
 	unsigned char Device = DeviceFunction >> 3;
@@ -859,7 +817,7 @@
 			   NULL, Bus, Device, IO_Address);
 	    continue;
 	  }
-	if (BusLogic_GlobalOptions.Bits.TraceProbe)
+	if (BusLogic_GlobalOptions.TraceProbe)
 	  {
 	    BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter "
 			    "detected at\n", NULL);
@@ -871,17 +829,17 @@
 	  Issue the Inquire PCI Host Adapter Information command to determine
 	  the ISA Compatible I/O Port.  If the ISA Compatible I/O Port is
 	  known and enabled, note that the particular Standard ISA I/O
-	  Address need not be probed.
+	  Address should not be probed.
 	*/
 	HostAdapter->IO_Address = IO_Address;
+	BusLogic_InterruptReset(HostAdapter);
 	if (BusLogic_Command(HostAdapter,
 			     BusLogic_InquirePCIHostAdapterInformation,
 			     NULL, 0, &PCIHostAdapterInformation,
 			     sizeof(PCIHostAdapterInformation))
 	    == sizeof(PCIHostAdapterInformation))
 	  {
-	    if (PCIHostAdapterInformation.ISACompatibleIOPort <
-		BusLogic_ISA_StandardAddressesCount)
+	    if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
 	      StandardAddressSeen[PCIHostAdapterInformation
 				  .ISACompatibleIOPort] = true;
 	  }
@@ -933,10 +891,10 @@
 	*/
 	if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330)
 	  {
-	    PrimaryProbeInfo->IO_Address = IO_Address;
-	    PrimaryProbeInfo->PCI_Address = PCI_Address;
 	    PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
 	    PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+	    PrimaryProbeInfo->IO_Address = IO_Address;
+	    PrimaryProbeInfo->PCI_Address = PCI_Address;
 	    PrimaryProbeInfo->Bus = Bus;
 	    PrimaryProbeInfo->Device = Device;
 	    PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -946,10 +904,10 @@
 	  {
 	    BusLogic_ProbeInfo_T *ProbeInfo =
 	      &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	    ProbeInfo->IO_Address = IO_Address;
-	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
 	    ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+	    ProbeInfo->IO_Address = IO_Address;
+	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->Bus = Bus;
 	    ProbeInfo->Device = Device;
 	    ProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -978,31 +936,80 @@
     then the Primary I/O Address must be probed explicitly before any PCI
     host adapters are probed.
   */
-  if (PrimaryProbeInfo->IO_Address == 0 &&
-      !BusLogic_ProbeOptions.Bits.NoProbeISA)
-    {
-      PrimaryProbeInfo->IO_Address = BusLogic_ISA_StandardAddresses[0];
-      PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-      PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-    }
+  if (!BusLogic_ProbeOptions.NoProbeISA)
+    if (PrimaryProbeInfo->IO_Address == 0 &&
+	(BusLogic_ProbeOptions.LimitedProbeISA
+	 ? BusLogic_ProbeOptions.Probe330
+	 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0))
+      {
+	PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+	PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+	PrimaryProbeInfo->IO_Address = 0x330;
+      }
   /*
     Append the list of standard BusLogic MultiMaster ISA I/O Addresses,
     omitting the Primary I/O Address which has already been handled.
   */
-  if (!BusLogic_ProbeOptions.Bits.NoProbeISA)
-    for (StandardAddressIndex = 1;
-	 StandardAddressIndex < BusLogic_ISA_StandardAddressesCount;
-	 StandardAddressIndex++)
-      if (!StandardAddressSeen[StandardAddressIndex] &&
-	  BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
-	{
-	  BusLogic_ProbeInfo_T *ProbeInfo =
-	    &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	  ProbeInfo->IO_Address =
-	    BusLogic_ISA_StandardAddresses[StandardAddressIndex];
-	  ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-	  ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-	}
+  if (!BusLogic_ProbeOptions.NoProbeISA)
+    {
+      if (!StandardAddressSeen[1] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe334
+	   : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x334);
+      if (!StandardAddressSeen[2] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe230
+	   : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x230);
+      if (!StandardAddressSeen[3] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe234
+	   : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x234);
+      if (!StandardAddressSeen[4] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe130
+	   : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x130);
+      if (!StandardAddressSeen[5] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe134
+	   : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x134);
+    }
+  /*
+    Iterate over the older non-compliant MultiMaster PCI Host Adapters,
+    noting the PCI bus location and assigned IRQ Channel.
+  */
+  Index = 0;
+  while (pcibios_find_device(PCI_VENDOR_ID_BUSLOGIC,
+			     PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
+			     Index++, &Bus, &DeviceFunction) == 0)
+    if (pcibios_read_config_dword(Bus, DeviceFunction,
+				  PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
+	pcibios_read_config_byte(Bus, DeviceFunction,
+				 PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
+      {
+	unsigned char Device = DeviceFunction >> 3;
+	IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+	if (IO_Address == 0 || IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
+	  continue;
+	for (i = 0; i < BusLogic_ProbeInfoCount; i++)
+	  {
+	    BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[i];
+	    if (ProbeInfo->IO_Address == IO_Address &&
+		ProbeInfo->HostAdapterType == BusLogic_MultiMaster)
+	      {
+		ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+		ProbeInfo->PCI_Address = 0;
+		ProbeInfo->Bus = Bus;
+		ProbeInfo->Device = Device;
+		ProbeInfo->IRQ_Channel = IRQ_Channel;
+		break;
+	      }
+	  }
+      }
   return PCIMultiMasterCount;
 }
 
@@ -1014,11 +1021,13 @@
   number of FlashPoint Host Adapters found.
 */
 
-static int BusLogic_InitializeFlashPointProbeInfo(void)
+static int BusLogic_InitializeFlashPointProbeInfo(BusLogic_HostAdapter_T
+						  *PrototypeHostAdapter)
 {
   int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0;
-  unsigned char Bus, DeviceFunction, IRQ_Channel;
+  unsigned char Bus, DeviceFunction;
   unsigned int BaseAddress0, BaseAddress1;
+  unsigned char IRQ_Channel;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
   unsigned short Index = 0;
@@ -1065,7 +1074,7 @@
 			   NULL, Bus, Device, IO_Address);
 	    continue;
 	  }
-	if (BusLogic_GlobalOptions.Bits.TraceProbe)
+	if (BusLogic_GlobalOptions.TraceProbe)
 	  {
 	    BusLogic_Notice("BusLogic: FlashPoint Host Adapter "
 			    "detected at\n", NULL);
@@ -1077,10 +1086,10 @@
 	  {
 	    BusLogic_ProbeInfo_T *ProbeInfo =
 	      &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	    ProbeInfo->IO_Address = IO_Address;
-	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
 	    ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+	    ProbeInfo->IO_Address = IO_Address;
+	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->Bus = Bus;
 	    ProbeInfo->Device = Device;
 	    ProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -1116,44 +1125,41 @@
   FlashPoint and PCI MultiMaster Host Adapters are present, this driver will
   probe for FlashPoint Host Adapters first unless the BIOS primary disk is
   controlled by the first PCI MultiMaster Host Adapter, in which case
-  MultiMaster Host Adapters will be probed first.  The Kernel Command Line
-  options "MultiMasterFirst" and "FlashPointFirst" can be used to force a
-  particular probe order.
+  MultiMaster Host Adapters will be probed first.  The BusLogic Driver Options
+  specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force
+  a particular probe order.
 */
 
-static void BusLogic_InitializeProbeInfoList(void)
+static void BusLogic_InitializeProbeInfoList(BusLogic_HostAdapter_T
+					     *PrototypeHostAdapter)
 {
   /*
-    If BusLogic_Setup has provided an I/O Address probe list, do not override
-    the Kernel Command Line specifications.
-  */
-  if (BusLogic_ProbeInfoCount > 0) return;
-  /*
     If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint
     Host Adapters; otherwise, default to the standard ISA MultiMaster probe.
   */
-  if (!BusLogic_ProbeOptions.Bits.NoProbePCI && pcibios_present())
+  if (!BusLogic_ProbeOptions.NoProbePCI && pcibios_present())
     {
-      if (BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst)
+      if (BusLogic_ProbeOptions.MultiMasterFirst)
 	{
-	  BusLogic_InitializeMultiMasterProbeInfo();
-	  BusLogic_InitializeFlashPointProbeInfo();
+	  BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
+	  BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
 	}
-      else if (BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst)
+      else if (BusLogic_ProbeOptions.FlashPointFirst)
 	{
-	  BusLogic_InitializeFlashPointProbeInfo();
-	  BusLogic_InitializeMultiMasterProbeInfo();
+	  BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+	  BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
 	}
       else
 	{
-	  int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo();
-	  int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo();
+	  int FlashPointCount =
+	    BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+	  int PCIMultiMasterCount =
+	    BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
 	  if (FlashPointCount > 0 && PCIMultiMasterCount > 0)
 	    {
 	      BusLogic_ProbeInfo_T *ProbeInfo =
 		&BusLogic_ProbeInfoList[FlashPointCount];
-	      BusLogic_HostAdapter_T HostAdapterPrototype;
-	      BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+	      BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
 	      BusLogic_FetchHostAdapterLocalRAMRequest_T
 		FetchHostAdapterLocalRAMRequest;
 	      BusLogic_BIOSDriveMapByte_T Drive0MapByte;
@@ -1195,7 +1201,7 @@
 	    }
 	}
     }
-  else BusLogic_InitializeProbeInfoListISA();
+  else BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter);
 }
 
 
@@ -1211,10 +1217,13 @@
 {
   BusLogic_AnnounceDriver(HostAdapter);
   if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus)
-    BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n"
-		   "Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n",
-		   HostAdapter, HostAdapter->Bus, HostAdapter->Device,
-		   HostAdapter->IO_Address, HostAdapter->PCI_Address);
+    {
+      BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n",
+		     HostAdapter);
+      BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n",
+		     HostAdapter, HostAdapter->Bus, HostAdapter->Device,
+		     HostAdapter->IO_Address, HostAdapter->PCI_Address);
+    }
   else BusLogic_Error("While configuring BusLogic Host Adapter at "
 		      "I/O Address 0x%X:\n", HostAdapter,
 		      HostAdapter->IO_Address);
@@ -1240,20 +1249,14 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     {
-      FlashPoint_Info_T *FlashPointInfo = (FlashPoint_Info_T *)
-	scsi_init_malloc(sizeof(FlashPoint_Info_T), GFP_ATOMIC);
-      int Retries = 10;
-      if (FlashPointInfo == NULL)
-	return BusLogic_Failure(HostAdapter, "ALLOCATING FLASHPOINT INFO");
-      FlashPointInfo->BaseAddress = HostAdapter->IO_Address;
+      FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
+      FlashPointInfo->BaseAddress =
+	(BusLogic_Base_Address_T) HostAdapter->IO_Address;
       FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel;
       FlashPointInfo->Present = false;
-      while (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 &&
-	       FlashPointInfo->Present) &&
-	     --Retries >= 0) ;
-      if (!FlashPointInfo->Present)
+      if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 &&
+	    FlashPointInfo->Present))
 	{
-	  scsi_init_free((char *) FlashPointInfo, sizeof(FlashPoint_Info_T));
 	  BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
 			 "PCI Bus %d Device %d\n", HostAdapter,
 			 HostAdapter->Bus, HostAdapter->Device);
@@ -1264,8 +1267,7 @@
 			 HostAdapter);
 	  return false;
 	}
-      HostAdapter->FlashPointInfo = FlashPointInfo;
-      if (BusLogic_GlobalOptions.Bits.TraceProbe)
+      if (BusLogic_GlobalOptions.TraceProbe)
 	BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n",
 			HostAdapter, HostAdapter->IO_Address);
       /*
@@ -1283,7 +1285,7 @@
   StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
   InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
   GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter);
-  if (BusLogic_GlobalOptions.Bits.TraceProbe)
+  if (BusLogic_GlobalOptions.TraceProbe)
     BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, "
 		    "Geometry 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All,
@@ -1318,12 +1320,16 @@
 
 
 /*
-  BusLogic_HardResetHostAdapter issues a Hard Reset to the Host Adapter,
-  and waits for Host Adapter Diagnostics to complete.
+  BusLogic_HardwareResetHostAdapter issues a Hardware Reset to the Host Adapter
+  and waits for Host Adapter Diagnostics to complete.  If HardReset is true, a
+  Hard Reset is performed which also initiates a SCSI Bus Reset.  Otherwise, a
+  Soft Reset is performed which only resets the Host Adapter without forcing a
+  SCSI Bus Reset.
 */
 
-static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
-					     *HostAdapter)
+static boolean BusLogic_HardwareResetHostAdapter(BusLogic_HostAdapter_T
+						   *HostAdapter,
+						 boolean HardReset)
 {
   BusLogic_StatusRegister_T StatusRegister;
   int TimeoutCounter;
@@ -1332,9 +1338,11 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     {
-      HostAdapter->FlashPointInfo->ReportDataUnderrun = true;
+      FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
+      FlashPointInfo->HostSoftReset = !HardReset;
+      FlashPointInfo->ReportDataUnderrun = true;
       HostAdapter->CardHandle =
-	FlashPoint_HardResetHostAdapter(HostAdapter->FlashPointInfo);
+	FlashPoint_HardwareResetHostAdapter(FlashPointInfo);
       if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) return false;
       /*
 	Indicate the Host Adapter Hard Reset completed successfully.
@@ -1342,10 +1350,12 @@
       return true;
     }
   /*
-    Issue a Hard Reset Command to the Host Adapter.  The Host Adapter should
-    respond by setting Diagnostic Active in the Status Register.
+    Issue a Hard Reset or Soft Reset Command to the Host Adapter.  The Host
+    Adapter should respond by setting Diagnostic Active in the Status Register.
   */
-  BusLogic_HardReset(HostAdapter);
+  if (HardReset)
+    BusLogic_HardReset(HostAdapter);
+  else BusLogic_SoftReset(HostAdapter);
   /*
     Wait until Diagnostic Active is set in the Status Register.
   */
@@ -1356,8 +1366,8 @@
       if (StatusRegister.Bits.DiagnosticActive) break;
       udelay(100);
     }
-  if (BusLogic_GlobalOptions.Bits.TraceHardReset)
-    BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Active, "
+  if (BusLogic_GlobalOptions.TraceHardwareReset)
+    BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, "
 		    "Status 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All);
   if (TimeoutCounter < 0) return false;
@@ -1377,8 +1387,8 @@
       if (!StatusRegister.Bits.DiagnosticActive) break;
       udelay(100);
     }
-  if (BusLogic_GlobalOptions.Bits.TraceHardReset)
-    BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Completed, "
+  if (BusLogic_GlobalOptions.TraceHardwareReset)
+    BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, "
 		    "Status 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All);
   if (TimeoutCounter < 0) return false;
@@ -1396,8 +1406,8 @@
 	break;
       udelay(100);
     }
-  if (BusLogic_GlobalOptions.Bits.TraceHardReset)
-    BusLogic_Notice("BusLogic_HardReset(0x%X): Host Adapter Ready, "
+  if (BusLogic_GlobalOptions.TraceHardwareReset)
+    BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, "
 		    "Status 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All);
   if (TimeoutCounter < 0) return false;
@@ -1430,12 +1440,11 @@
 
 /*
   BusLogic_CheckHostAdapter checks to be sure this really is a BusLogic
-  Host Adapter.  It also determines the IRQ Channel for non-PCI Host Adapters.
+  Host Adapter.
 */
 
 static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 {
-  BusLogic_Configuration_T Configuration;
   BusLogic_ExtendedSetupInformation_T ExtendedSetupInformation;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
   boolean Result = true;
@@ -1444,29 +1453,6 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
   /*
-    Issue the Inquire Configuration command if the IRQ Channel is unknown.
-  */
-  if (HostAdapter->IRQ_Channel == 0)
-    if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
-			 NULL, 0, &Configuration, sizeof(Configuration))
-	== sizeof(Configuration))
-      {
-	if (Configuration.IRQ_Channel9)
-	  HostAdapter->IRQ_Channel = 9;
-	else if (Configuration.IRQ_Channel10)
-	  HostAdapter->IRQ_Channel = 10;
-	else if (Configuration.IRQ_Channel11)
-	  HostAdapter->IRQ_Channel = 11;
-	else if (Configuration.IRQ_Channel12)
-	  HostAdapter->IRQ_Channel = 12;
-	else if (Configuration.IRQ_Channel14)
-	  HostAdapter->IRQ_Channel = 14;
-	else if (Configuration.IRQ_Channel15)
-	  HostAdapter->IRQ_Channel = 15;
-	else Result = false;
-      }
-    else Result = false;
-  /*
     Issue the Inquire Extended Setup Information command.  Only genuine
     BusLogic Host Adapters and true clones support this command.  Adaptec 1542C
     series Host Adapters that respond to the Geometry Register I/O port will
@@ -1484,7 +1470,7 @@
   /*
     Provide tracing information if requested and return.
   */
-  if (BusLogic_GlobalOptions.Bits.TraceProbe)
+  if (BusLogic_GlobalOptions.TraceProbe)
     BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter,
 		    HostAdapter->IO_Address, (Result ? "Found" : "Not Found"));
   return Result;
@@ -1512,7 +1498,7 @@
   BusLogic_GeometryRegister_T GeometryRegister;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
   unsigned char *TargetPointer, Character;
-  int i;
+  int TargetID, i;
   /*
     Configuration Information for FlashPoint Host Adapters is provided in the
     FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function.
@@ -1521,7 +1507,7 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     {
-      FlashPoint_Info_T *FlashPointInfo = HostAdapter->FlashPointInfo;
+      FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
       TargetPointer = HostAdapter->ModelName;
       *TargetPointer++ = 'B';
       *TargetPointer++ = 'T';
@@ -1550,8 +1536,8 @@
       HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit;
       HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
       HostAdapter->MaxLogicalUnits = 32;
-      HostAdapter->InitialCCBs = 64;
-      HostAdapter->IncrementalCCBs = 16;
+      HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+      HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
       HostAdapter->DriverQueueDepth = 255;
       HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth;
       HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted;
@@ -1692,18 +1678,36 @@
   */
   HostAdapter->SCSI_ID = Configuration.HostAdapterID;
   /*
-    Determine the Bus Type and save it in the Host Adapter structure,
-    and determine and save the DMA Channel for ISA Host Adapters.
+    Determine the Bus Type and save it in the Host Adapter structure, determine
+    and save the IRQ Channel if necessary, and determine and save the DMA
+    Channel for ISA Host Adapters.
   */
   HostAdapter->HostAdapterBusType =
     BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4'];
+  if (HostAdapter->IRQ_Channel == 0)
+    {
+      if (Configuration.IRQ_Channel9)
+	HostAdapter->IRQ_Channel = 9;
+      else if (Configuration.IRQ_Channel10)
+	HostAdapter->IRQ_Channel = 10;
+      else if (Configuration.IRQ_Channel11)
+	HostAdapter->IRQ_Channel = 11;
+      else if (Configuration.IRQ_Channel12)
+	HostAdapter->IRQ_Channel = 12;
+      else if (Configuration.IRQ_Channel14)
+	HostAdapter->IRQ_Channel = 14;
+      else if (Configuration.IRQ_Channel15)
+	HostAdapter->IRQ_Channel = 15;
+    }
   if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus)
-    if (Configuration.DMA_Channel5)
-      HostAdapter->DMA_Channel = 5;
-    else if (Configuration.DMA_Channel6)
-      HostAdapter->DMA_Channel = 6;
-    else if (Configuration.DMA_Channel7)
-      HostAdapter->DMA_Channel = 7;
+    {
+      if (Configuration.DMA_Channel5)
+	HostAdapter->DMA_Channel = 5;
+      else if (Configuration.DMA_Channel6)
+	HostAdapter->DMA_Channel = 6;
+      else if (Configuration.DMA_Channel7)
+	HostAdapter->DMA_Channel = 7;
+    }
   /*
     Determine whether Extended Translation is enabled and save it in
     the Host Adapter structure.
@@ -1837,7 +1841,7 @@
   HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
   HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8);
   /*
-    Select appropriate values for the Driver Queue Depth, Mailbox Count,
+    Select appropriate values for the Mailbox Count, Driver Queue Depth,
     Initial CCBs, and Incremental CCBs variables based on whether or not Strict
     Round Robin Mode is supported.  If Strict Round Robin Mode is supported,
     then there is no performance degradation in using the maximum possible
@@ -1868,18 +1872,16 @@
   if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0)
     {
       HostAdapter->StrictRoundRobinModeSupport = true;
-      HostAdapter->MailboxCount = 255;
-      HostAdapter->InitialCCBs = 64;
-      HostAdapter->IncrementalCCBs = 16;
+      HostAdapter->MailboxCount = BusLogic_MaxMailboxes;
     }
   else
     {
       HostAdapter->StrictRoundRobinModeSupport = false;
       HostAdapter->MailboxCount = 32;
-      HostAdapter->InitialCCBs = 32;
-      HostAdapter->IncrementalCCBs = 8;
     }
   HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount;
+  HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+  HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
   /*
     Tagged Queuing support is available and operates properly on all "W" series
     MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with
@@ -1931,57 +1933,36 @@
   */
 Common:
   /*
-    Initialize the Host Adapter Name and Interrupt Label fields from the
-    Model Name.
+    Initialize the Host Adapter Full Model Name from the Model Name.
   */
   strcpy(HostAdapter->FullModelName, "BusLogic ");
   strcat(HostAdapter->FullModelName, HostAdapter->ModelName);
-  strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName);
   /*
     Select an appropriate value for the Tagged Queue Depth either from a
-    Command Line Entry, or based on whether this Host Adapter requires that ISA
-    Bounce Buffers be used.  The Tagged Queue Depth is left at 0 for automatic
-    determination in BusLogic_SelectQueueDepths.  Initialize the Untagged Queue
-    Depth.  Tagged Queuing is disabled by default when the Tagged Queue Depth
-    is 1 since queuing multiple commands is not possible.
-  */
-  if (HostAdapter->CommandLineEntry != NULL &&
-      HostAdapter->CommandLineEntry->TaggedQueueDepth > 0)
-    HostAdapter->TaggedQueueDepth =
-      HostAdapter->CommandLineEntry->TaggedQueueDepth;
-  else if (HostAdapter->BounceBuffersRequired)
-    HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthBounceBuffers;
-  else HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthAutomatic;
-  HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
-  if (HostAdapter->UntaggedQueueDepth > HostAdapter->TaggedQueueDepth &&
-      HostAdapter->TaggedQueueDepth > 0)
-    HostAdapter->UntaggedQueueDepth = HostAdapter->TaggedQueueDepth;
-  if (HostAdapter->TaggedQueueDepth == 1)
-    HostAdapter->TaggedQueuingPermitted = 0;
-  /*
-    Select an appropriate value for Bus Settle Time either from a Command
-    Line Entry, or from BusLogic_DefaultBusSettleTime.
-  */
-  if (HostAdapter->CommandLineEntry != NULL &&
-      HostAdapter->CommandLineEntry->BusSettleTime > 0)
-    HostAdapter->BusSettleTime = HostAdapter->CommandLineEntry->BusSettleTime;
-  else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime;
-  /*
-    Select an appropriate value for Local Options from a Command Line Entry.
-  */
-  if (HostAdapter->CommandLineEntry != NULL)
-    HostAdapter->LocalOptions = HostAdapter->CommandLineEntry->LocalOptions;
-  /*
-    Select appropriate values for the Error Recovery Strategy array either from
-    a Command Line Entry, or using BusLogic_ErrorRecovery_Default.
-  */
-  if (HostAdapter->CommandLineEntry != NULL)
-    memcpy(HostAdapter->ErrorRecoveryStrategy,
-	   HostAdapter->CommandLineEntry->ErrorRecoveryStrategy,
-	   sizeof(HostAdapter->ErrorRecoveryStrategy));
-  else memset(HostAdapter->ErrorRecoveryStrategy,
-	      BusLogic_ErrorRecovery_Default,
-	      sizeof(HostAdapter->ErrorRecoveryStrategy));
+    BusLogic Driver Options specification, or based on whether this Host
+    Adapter requires that ISA Bounce Buffers be used.  The Tagged Queue Depth
+    is left at 0 for automatic determination in BusLogic_SelectQueueDepths.
+    Initialize the Untagged Queue Depth.
+  */
+  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+    {
+      unsigned char QueueDepth = 0;
+      if (HostAdapter->DriverOptions != NULL &&
+	  HostAdapter->DriverOptions->QueueDepth[TargetID] > 0)
+	QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID];
+      else if (HostAdapter->BounceBuffersRequired)
+	QueueDepth = BusLogic_TaggedQueueDepthBB;
+      HostAdapter->QueueDepth[TargetID] = QueueDepth;
+    }
+  if (HostAdapter->BounceBuffersRequired)
+    HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB;
+  else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
+  if (HostAdapter->DriverOptions != NULL)
+    HostAdapter->CommonQueueDepth =
+      HostAdapter->DriverOptions->CommonQueueDepth;
+  if (HostAdapter->CommonQueueDepth > 0 &&
+      HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth)
+    HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth;
   /*
     Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
     Therefore, mask the Tagged Queuing Permitted Default bits with the
@@ -1989,15 +1970,34 @@
   */
   HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted;
   /*
-    Combine the default Tagged Queuing Permitted bits with any Command
-    Line Entry Tagged Queuing specification.
+    Combine the default Tagged Queuing Permitted bits with any BusLogic Driver
+    Options Tagged Queuing specification.
   */
-  if (HostAdapter->CommandLineEntry != NULL)
+  if (HostAdapter->DriverOptions != NULL)
     HostAdapter->TaggedQueuingPermitted =
-      (HostAdapter->CommandLineEntry->TaggedQueuingPermitted &
-       HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask) |
+      (HostAdapter->DriverOptions->TaggedQueuingPermitted &
+       HostAdapter->DriverOptions->TaggedQueuingPermittedMask) |
       (HostAdapter->TaggedQueuingPermitted &
-       ~HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask);
+       ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask);
+  /*
+    Select appropriate values for the Error Recovery Strategy array
+    either from a BusLogic Driver Options specification, or using
+    BusLogic_ErrorRecovery_Default.
+  */
+  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+    if (HostAdapter->DriverOptions != NULL)
+      HostAdapter->ErrorRecoveryStrategy[TargetID] =
+	HostAdapter->DriverOptions->ErrorRecoveryStrategy[TargetID];
+    else HostAdapter->ErrorRecoveryStrategy[TargetID] =
+	   BusLogic_ErrorRecovery_Default;
+  /*
+    Select an appropriate value for Bus Settle Time either from a BusLogic
+    Driver Options specification, or from BusLogic_DefaultBusSettleTime.
+  */
+  if (HostAdapter->DriverOptions != NULL &&
+      HostAdapter->DriverOptions->BusSettleTime > 0)
+    HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime;
+  else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime;
   /*
     Indicate reading the Host Adapter Configuration completed successfully.
   */
@@ -2017,7 +2017,8 @@
   unsigned short SynchronousPermitted, FastPermitted;
   unsigned short UltraPermitted, WidePermitted;
   unsigned short DisconnectPermitted, TaggedQueuingPermitted;
-  boolean CommonSynchronousNegotiation, CommonErrorRecovery;
+  boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth;
+  boolean CommonErrorRecovery;
   char SynchronousString[BusLogic_MaxTargetDevices+1];
   char WideString[BusLogic_MaxTargetDevices+1];
   char DisconnectString[BusLogic_MaxTargetDevices+1];
@@ -2083,22 +2084,26 @@
 	  CommonSynchronousNegotiation = true;
 	}
       else if (SynchronousPermitted == AllTargetsMask)
-	if (FastPermitted == 0)
-	  {
-	    SynchronousMessage = "Slow";
-	    CommonSynchronousNegotiation = true;
-	  }
-	else if (FastPermitted == AllTargetsMask)
-	  if (UltraPermitted == 0)
+	{
+	  if (FastPermitted == 0)
 	    {
-	      SynchronousMessage = "Fast";
+	      SynchronousMessage = "Slow";
 	      CommonSynchronousNegotiation = true;
 	    }
-	  else if (UltraPermitted == AllTargetsMask)
+	  else if (FastPermitted == AllTargetsMask)
 	    {
-	      SynchronousMessage = "Ultra";
-	      CommonSynchronousNegotiation = true;
+	      if (UltraPermitted == 0)
+		{
+		  SynchronousMessage = "Fast";
+		  CommonSynchronousNegotiation = true;
+		}
+	      else if (UltraPermitted == AllTargetsMask)
+		{
+		  SynchronousMessage = "Ultra";
+		  CommonSynchronousNegotiation = true;
+		}
 	    }
+	}
       if (!CommonSynchronousNegotiation)
 	{
 	  for (TargetID = 0;
@@ -2175,9 +2180,20 @@
 		     HostAdapter, HostAdapter->DriverQueueDepth,
 		     HostAdapter->DriverScatterGatherLimit);
   BusLogic_Info("  Tagged Queue Depth: ", HostAdapter);
-  if (HostAdapter->TaggedQueueDepth > 0)
-    BusLogic_Info("%d", HostAdapter, HostAdapter->TaggedQueueDepth);
-  else BusLogic_Info("Automatic", HostAdapter);
+  CommonTaggedQueueDepth = true;
+  for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0])
+      {
+	CommonTaggedQueueDepth = false;
+	break;
+      }
+  if (CommonTaggedQueueDepth)
+    {
+      if (HostAdapter->QueueDepth[0] > 0)
+	BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]);
+      else BusLogic_Info("Automatic", HostAdapter);
+    }
+  else BusLogic_Info("Individual", HostAdapter);
   BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter,
 		HostAdapter->UntaggedQueueDepth);
   CommonErrorRecovery = true;
@@ -2238,8 +2254,6 @@
 
 static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
 {
-  BusLogic_HostAdapter_T *FirstHostAdapter =
-    BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
   if (HostAdapter->IRQ_Channel == 0)
     {
       BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n",
@@ -2247,24 +2261,15 @@
       return false;
     }
   /*
-    Acquire exclusive or shared access to the IRQ Channel if necessary.
+    Acquire shared access to the IRQ Channel.
   */
-  if (FirstHostAdapter->Next == NULL)
-    {
-      if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
-		      SA_INTERRUPT | SA_SHIRQ,
-		      HostAdapter->InterruptLabel, NULL) < 0)
-	{
-	  BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
-			 HostAdapter, HostAdapter->IRQ_Channel);
-	  return false;
-	}
-    }
-  else if (strlen(FirstHostAdapter->InterruptLabel) + 11
-	   < sizeof(FirstHostAdapter->InterruptLabel))
+  if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
+		  SA_INTERRUPT | SA_SHIRQ,
+		  HostAdapter->FullModelName, HostAdapter) < 0)
     {
-      strcat(FirstHostAdapter->InterruptLabel, " + ");
-      strcat(FirstHostAdapter->InterruptLabel, HostAdapter->ModelName);
+      BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
+		     HostAdapter, HostAdapter->IRQ_Channel);
+      return false;
     }
   HostAdapter->IRQ_ChannelAcquired = true;
   /*
@@ -2297,14 +2302,11 @@
 
 static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter)
 {
-  BusLogic_HostAdapter_T *FirstHostAdapter =
-    BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
   /*
-    Release exclusive or shared access to the IRQ Channel.
+    Release shared access to the IRQ Channel.
   */
   if (HostAdapter->IRQ_ChannelAcquired)
-    if (FirstHostAdapter->Next == NULL)
-      free_irq(HostAdapter->IRQ_Channel, NULL);
+    free_irq(HostAdapter->IRQ_Channel, HostAdapter);
   /*
     Release exclusive access to the DMA Channel.
   */
@@ -2314,50 +2316,6 @@
 
 
 /*
-  BusLogic_TestInterrupts tests for proper functioning of the Host Adapter
-  Interrupt Register and that interrupts generated by the Host Adapter are
-  getting through to the Interrupt Handler.  A large proportion of initial
-  problems with installing PCI Host Adapters are due to configuration problems
-  where either the Host Adapter or Motherboard is configured incorrectly, and
-  interrupts do not get through as a result.
-*/
-
-static boolean BusLogic_TestInterrupts(BusLogic_HostAdapter_T *HostAdapter)
-{
-  unsigned int InitialInterruptCount, FinalInterruptCount;
-  int TestCount = 5, i;
-  /*
-    FlashPoint Host Adapters do not provide for an interrupt test.
-  */
-  if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
-  /*
-    Inhibit the Interrupt Test if requested.
-  */
-  if (HostAdapter->LocalOptions.Bits.InhibitInterruptTest) return true;
-  /*
-    Issue the Test Command Complete Interrupt commands.
-  */
-  InitialInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel];
-  for (i = 0; i < TestCount; i++)
-    BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt,
-		     NULL, 0, NULL, 0);
-  FinalInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel];
-  /*
-    Verify that BusLogic_InterruptHandler was called at least TestCount
-    times.  Shared IRQ Channels could cause more than TestCount interrupts to
-    occur, but there should never be fewer than TestCount, unless one or more
-    interrupts were lost.
-  */
-  if (FinalInterruptCount < InitialInterruptCount + TestCount)
-    return BusLogic_Failure(HostAdapter, "HOST ADAPTER INTERRUPT TEST");
-  /*
-    Indicate the Host Adapter Interrupt Test completed successfully.
-  */
-  return true;
-}
-
-
-/*
   BusLogic_InitializeHostAdapter initializes Host Adapter.  This is the only
   function called during SCSI Host Adapter detection which modifies the state
   of the Host Adapter from its initial power on or hard reset state.
@@ -2371,25 +2329,42 @@
   BusLogic_SetCCBFormatRequest_T SetCCBFormatRequest;
   int TargetID;
   /*
+    Initialize the pointers to the first and last CCBs that are queued for
+    completion processing.
+  */
+  HostAdapter->FirstCompletedCCB = NULL;
+  HostAdapter->LastCompletedCCB = NULL;
+  /*
     Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
     Command Successful Flag, Active Commands, and Commands Since Reset
     for each Target Device.
   */
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
-  memset(HostAdapter->TaggedQueuingActive, false,
-	 sizeof(HostAdapter->TaggedQueuingActive));
-  memset(HostAdapter->CommandSuccessfulFlag, false,
-	 sizeof(HostAdapter->CommandSuccessfulFlag));
-  memset(HostAdapter->ActiveCommands, 0,
-	 sizeof(HostAdapter->ActiveCommands));
-  memset(HostAdapter->CommandsSinceReset, 0,
-	 sizeof(HostAdapter->CommandsSinceReset));
+    {
+      HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
+      HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
+      HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false;
+      HostAdapter->ActiveCommands[TargetID] = 0;
+      HostAdapter->CommandsSinceReset[TargetID] = 0;
+    }
   /*
     FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter)) goto Done;
   /*
+    Initialize the Outgoing and Incoming Mailbox pointers.
+  */
+  HostAdapter->FirstOutgoingMailbox =
+    (BusLogic_OutgoingMailbox_T *) HostAdapter->MailboxSpace;
+  HostAdapter->LastOutgoingMailbox =
+    HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
+  HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
+  HostAdapter->FirstIncomingMailbox =
+    (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
+  HostAdapter->LastIncomingMailbox =
+    HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
+  HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
+  /*
     Initialize the Outgoing and Incoming Mailbox structures.
   */
   memset(HostAdapter->FirstOutgoingMailbox, 0,
@@ -2397,11 +2372,6 @@
   memset(HostAdapter->FirstIncomingMailbox, 0,
 	 HostAdapter->MailboxCount * sizeof(BusLogic_IncomingMailbox_T));
   /*
-    Initialize the pointers to the Next Mailboxes.
-  */
-  HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
-  HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
-  /*
     Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes.
   */
   ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount;
@@ -2442,11 +2412,14 @@
     Announce Successful Initialization.
   */
 Done:
-  if (HostAdapter->HostAdapterInitialized)
-    BusLogic_Warning("*** %s Initialized Successfully ***\n",
-		     HostAdapter, HostAdapter->FullModelName);
-  else BusLogic_Info("*** %s Initialized Successfully ***\n",
-		     HostAdapter, HostAdapter->FullModelName);
+  if (!HostAdapter->HostAdapterInitialized)
+    {
+      BusLogic_Info("*** %s Initialized Successfully ***\n",
+		    HostAdapter, HostAdapter->FullModelName);
+      BusLogic_Info("\n", HostAdapter);
+    }
+  else BusLogic_Warning("*** %s Initialized Successfully ***\n",
+			HostAdapter, HostAdapter->FullModelName);
   HostAdapter->HostAdapterInitialized = true;
   /*
     Indicate the Host Adapter Initialization completed successfully.
@@ -2457,7 +2430,7 @@
 
 /*
   BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible
-  through Host Adapter and reports on the results.
+  through Host Adapter.
 */
 
 static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
@@ -2468,7 +2441,7 @@
   BusLogic_SetupInformation_T SetupInformation;
   BusLogic_SynchronousPeriod_T SynchronousPeriod;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
-  int TargetDevicesFound = 0, TargetID;
+  int TargetID;
   /*
     Wait a few seconds between the Host Adapter Hard Reset which initiates
     a SCSI Bus Reset and issuing any SCSI Commands.  Some SCSI devices get
@@ -2480,13 +2453,11 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
   /*
-    Inhibit the Target Devices Inquiry if requested.
+    Inhibit the Target Device Inquiry if requested.
   */
-  if (HostAdapter->LocalOptions.Bits.InhibitTargetInquiry)
-    {
-      BusLogic_Info("  Target Device Inquiry Inhibited\n", HostAdapter);
-      return true;
-    }
+  if (HostAdapter->DriverOptions != NULL &&
+      HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
+    return true;
   /*
     Issue the Inquire Target Devices command for host adapters with firmware
     version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command
@@ -2502,6 +2473,9 @@
 			   &InstalledDevices, sizeof(InstalledDevices))
 	  != sizeof(InstalledDevices))
 	return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES");
+      for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+	HostAdapter->TargetFlags[TargetID].TargetExists =
+	  (InstalledDevices & (1 << TargetID) ? true : false);
     }
   else
     {
@@ -2511,10 +2485,9 @@
 	  != sizeof(InstalledDevicesID0to7))
 	return BusLogic_Failure(HostAdapter,
 				"INQUIRE INSTALLED DEVICES ID 0 TO 7");
-      InstalledDevices = 0;
       for (TargetID = 0; TargetID < 8; TargetID++)
-	if (InstalledDevicesID0to7[TargetID] != 0)
-	  InstalledDevices |= (1 << TargetID);
+	HostAdapter->TargetFlags[TargetID].TargetExists =
+	  (InstalledDevicesID0to7[TargetID] != 0 ? true : false);
     }
   /*
     Issue the Inquire Setup Information command.
@@ -2525,6 +2498,19 @@
 		       &SetupInformation, sizeof(SetupInformation))
       != sizeof(SetupInformation))
     return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION");
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+      HostAdapter->SynchronousOffset[TargetID] =
+	(TargetID < 8
+	 ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset
+	 : SetupInformation.SynchronousValuesID8to15[TargetID-8].Offset);
+  if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0)
+    for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+      HostAdapter->TargetFlags[TargetID].WideTransfersActive =
+	(TargetID < 8
+	 ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID)
+	    ? true : false)
+	 : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID-8))
+	    ? true : false));
   /*
     Issue the Inquire Synchronous Period command.
   */
@@ -2536,65 +2522,15 @@
 			   &SynchronousPeriod, sizeof(SynchronousPeriod))
 	  != sizeof(SynchronousPeriod))
 	return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD");
+      for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+	HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID];
     }
   else
     for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
       if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0)
-	SynchronousPeriod[TargetID] =
+	HostAdapter->SynchronousPeriod[TargetID] =
 	  20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID]
 				   .TransferPeriod;
-      else SynchronousPeriod[TargetID] = 0;
-  /*
-    Save the Installed Devices, Synchronous Values, and Synchronous Period
-    information in the Host Adapter structure.
-  */
-  HostAdapter->InstalledDevices = InstalledDevices;
-  memcpy(HostAdapter->SynchronousValues,
-	 SetupInformation.SynchronousValuesID0to7,
-	 sizeof(BusLogic_SynchronousValues8_T));
-  if (HostAdapter->HostWideSCSI)
-    memcpy(&HostAdapter->SynchronousValues[8],
-	   SetupInformation.SynchronousValuesID8to15,
-	   sizeof(BusLogic_SynchronousValues8_T));
-  memcpy(HostAdapter->SynchronousPeriod, SynchronousPeriod,
-	 sizeof(BusLogic_SynchronousPeriod_T));
-  /*
-    Report on the Target Devices found.
-  */
-  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (HostAdapter->InstalledDevices & (1 << TargetID))
-      {
-	int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID];
-	if (SynchronousPeriod > 10)
-	  {
-	    int SynchronousTransferRate = 100000000 / SynchronousPeriod;
-	    int RoundedSynchronousTransferRate =
-	      (SynchronousTransferRate + 5000) / 10000;
-	    BusLogic_Info("  Target %d: Synchronous at "
-			  "%d.%02d mega-transfers/second, offset %d\n",
-			  HostAdapter, TargetID,
-			  RoundedSynchronousTransferRate / 100,
-			  RoundedSynchronousTransferRate % 100,
-			  HostAdapter->SynchronousValues[TargetID].Offset);
-	  }
-	else if (SynchronousPeriod > 0)
-	  {
-	    int SynchronousTransferRate = 100000000 / SynchronousPeriod;
-	    int RoundedSynchronousTransferRate =
-	      (SynchronousTransferRate + 50000) / 100000;
-	    BusLogic_Info("  Target %d: Synchronous at "
-			  "%d.%01d mega-transfers/second, offset %d\n",
-			  HostAdapter, TargetID,
-			  RoundedSynchronousTransferRate / 10,
-			  RoundedSynchronousTransferRate % 10,
-			  HostAdapter->SynchronousValues[TargetID].Offset);
-	  }
-	else BusLogic_Info("  Target %d: Asynchronous\n",
-			   HostAdapter, TargetID);
-	TargetDevicesFound++;
-      }
-  if (TargetDevicesFound == 0)
-    BusLogic_Info("  No Target Devices Found\n", HostAdapter);
   /*
     Indicate the Target Device Inquiry completed successfully.
   */
@@ -2603,10 +2539,87 @@
 
 
 /*
-  BusLogic_InitializeHostStructure initializes the fields in the SCSI Host
-  structure.  The base, io_port, n_io_ports, irq, and dma_channel fields in the
-  SCSI Host structure are intentionally left uninitialized, as this driver
-  handles acquisition and release of these resources explicitly, as well as
+  BusLogic_ReportTargetDeviceInfo reports about the Target Devices accessible
+  through Host Adapter.
+*/
+
+static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
+					    *HostAdapter)
+{
+  int TargetID;
+  /*
+    Inhibit the Target Device Inquiry and Reporting if requested.
+  */
+  if (BusLogic_MultiMasterHostAdapterP(HostAdapter) &&
+      HostAdapter->DriverOptions != NULL &&
+      HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
+    return;
+  /*
+    Report on the Target Devices found.
+  */
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported)
+	{
+	  int SynchronousTransferRate = 0;
+	  if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+	    {
+	      boolean WideTransfersActive;
+	      FlashPoint_InquireTargetInfo(
+		HostAdapter->CardHandle, TargetID,
+		&HostAdapter->SynchronousPeriod[TargetID],
+		&HostAdapter->SynchronousOffset[TargetID],
+		&WideTransfersActive);
+	      TargetFlags->WideTransfersActive = WideTransfersActive;
+	    }
+	  else if (TargetFlags->WideTransfersSupported &&
+		   (HostAdapter->WidePermitted & (1 << TargetID)) &&
+		   strcmp(HostAdapter->FirmwareVersion, "5.06L") < 0)
+	    TargetFlags->WideTransfersActive = true;
+	  if (HostAdapter->SynchronousPeriod[TargetID] > 0)
+	    SynchronousTransferRate =
+	      100000 / HostAdapter->SynchronousPeriod[TargetID];
+	  if (TargetFlags->WideTransfersActive)
+	    SynchronousTransferRate <<= 1;
+	  if (SynchronousTransferRate >= 9950)
+	    {
+	      SynchronousTransferRate = (SynchronousTransferRate + 50) / 100;
+	      BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at "
+			    "%d.%01d MB/sec, offset %d\n",
+			    HostAdapter, TargetID,
+			    HostAdapter->QueueDepth[TargetID],
+			    (TargetFlags->WideTransfersActive ? "Wide " : ""),
+			    SynchronousTransferRate / 10,
+			    SynchronousTransferRate % 10,
+			    HostAdapter->SynchronousOffset[TargetID]);
+	    }
+	  else if (SynchronousTransferRate > 0)
+	    {
+	      SynchronousTransferRate = (SynchronousTransferRate + 5) / 10;
+	      BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at "
+			    "%d.%02d MB/sec, offset %d\n",
+			    HostAdapter, TargetID,
+			    HostAdapter->QueueDepth[TargetID],
+			    (TargetFlags->WideTransfersActive ? "Wide " : ""),
+			    SynchronousTransferRate / 100,
+			    SynchronousTransferRate % 100,
+			    HostAdapter->SynchronousOffset[TargetID]);
+	    }
+	  else BusLogic_Info("Target %d: Queue Depth %d, Asynchronous\n",
+			     HostAdapter, TargetID,
+			     HostAdapter->QueueDepth[TargetID]);
+	  TargetFlags->TargetInfoReported = true;
+	}
+    }
+}
+
+
+/*
+  BusLogic_InitializeHostStructure initializes the fields in the SCSI Host
+  structure.  The base, io_port, n_io_ports, irq, and dma_channel fields in the
+  SCSI Host structure are intentionally left uninitialized, as this driver
+  handles acquisition and release of these resources explicitly, as well as
   ensuring exclusive access to the Host Adapter hardware and data structures
   through explicit acquisition and release of the Host Adapter's Lock.
 */
@@ -2628,9 +2641,11 @@
 
 
 /*
-  BusLogic_SelectQueueDepths selects Queue Depths for each Target Device
-  based on the Host Adapter's Total Queue Depth and the number, type, speed,
-  and capabilities of the Target Devices.
+  BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based
+  on the Host Adapter's Total Queue Depth and the number, type, speed, and
+  capabilities of the Target Devices.  When called for the last Host Adapter,
+  it reports on the Target Device Information for all BusLogic Host Adapters
+  since all the Target Devices have now been probed.
 */
 
 static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
@@ -2638,41 +2653,69 @@
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Host->hostdata;
-  int TaggedQueueDepth = HostAdapter->TaggedQueueDepth;
-  int UntaggedQueueDepth = HostAdapter->UntaggedQueueDepth;
-  int TaggedDeviceCount = 0, UntaggedDeviceCount = 0;
-  int DesiredCCBs = HostAdapter->MaxTargetDevices - 1;
+  int TaggedDeviceCount = 0, AutomaticTaggedDeviceCount = 0;
+  int UntaggedDeviceCount = 0, AutomaticTaggedQueueDepth = 0;
+  int AllocatedQueueDepth = 0;
   SCSI_Device_T *Device;
-  for (Device = DeviceList; Device != NULL; Device = Device->next)
-    if (Device->host == Host)
+  int TargetID;
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    if (HostAdapter->TargetFlags[TargetID].TargetExists)
       {
-	if (Device->tagged_supported &&
-	    (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
-	  TaggedDeviceCount++;
-	else UntaggedDeviceCount++;
+	int QueueDepth = HostAdapter->QueueDepth[TargetID];
+	if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported &&
+	    (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
+	  {
+	    TaggedDeviceCount++;
+	    if (QueueDepth == 0) AutomaticTaggedDeviceCount++;
+	  }
+	else
+	  {
+	    UntaggedDeviceCount++;
+	    if (QueueDepth == 0 ||
+		QueueDepth > HostAdapter->UntaggedQueueDepth)
+	      {
+		QueueDepth = HostAdapter->UntaggedQueueDepth;
+		HostAdapter->QueueDepth[TargetID] = QueueDepth;
+	      }
+	  }
+	AllocatedQueueDepth += QueueDepth;
+	if (QueueDepth == 1)
+	  HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
       }
-  if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0)
+  HostAdapter->TargetDeviceCount = TaggedDeviceCount + UntaggedDeviceCount;
+  if (AutomaticTaggedDeviceCount > 0)
     {
-      TaggedQueueDepth =
-	1 + ((HostAdapter->HostAdapterQueueDepth
-	      - UntaggedDeviceCount * UntaggedQueueDepth)
-	     / TaggedDeviceCount);
-      if (TaggedQueueDepth > BusLogic_PreferredTaggedQueueDepth)
-	TaggedQueueDepth = BusLogic_PreferredTaggedQueueDepth;
+      AutomaticTaggedQueueDepth =
+	(HostAdapter->HostAdapterQueueDepth - AllocatedQueueDepth)
+	/ AutomaticTaggedDeviceCount;
+      if (AutomaticTaggedQueueDepth > BusLogic_MaxAutomaticTaggedQueueDepth)
+	AutomaticTaggedQueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth;
+      if (AutomaticTaggedQueueDepth < BusLogic_MinAutomaticTaggedQueueDepth)
+	AutomaticTaggedQueueDepth = BusLogic_MinAutomaticTaggedQueueDepth;
+      for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+	if (HostAdapter->TargetFlags[TargetID].TargetExists &&
+	    HostAdapter->QueueDepth[TargetID] == 0)
+	  {
+	    AllocatedQueueDepth += AutomaticTaggedQueueDepth;
+	    HostAdapter->QueueDepth[TargetID] = AutomaticTaggedQueueDepth;
+	  }
     }
   for (Device = DeviceList; Device != NULL; Device = Device->next)
     if (Device->host == Host)
-      {
-	if (Device->tagged_supported &&
-	    (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
-	  Device->queue_depth = TaggedQueueDepth;
-	else Device->queue_depth = UntaggedQueueDepth;
-	HostAdapter->QueueDepth[Device->id] = Device->queue_depth;
-	DesiredCCBs += Device->queue_depth;
-      }
+      Device->queue_depth = HostAdapter->QueueDepth[Device->id];
+  /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */
+  AllocatedQueueDepth += HostAdapter->TargetDeviceCount;
+  if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth)
+    AllocatedQueueDepth = HostAdapter->DriverQueueDepth;
   BusLogic_CreateAdditionalCCBs(HostAdapter,
-				DesiredCCBs - HostAdapter->AllocatedCCBs,
+				AllocatedQueueDepth
+				- HostAdapter->AllocatedCCBs,
 				false);
+  if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
+    for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
+	 HostAdapter != NULL;
+	 HostAdapter = HostAdapter->Next)
+      BusLogic_ReportTargetDeviceInfo(HostAdapter);
 }
 
 
@@ -2686,50 +2729,48 @@
 
 int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
 {
-  int BusLogicHostAdapterCount = 0, CommandLineEntryIndex = 0, ProbeIndex;
-  char *MessageBuffer = NULL;
-  if (BusLogic_ProbeOptions.Bits.NoProbe) return 0;
-  BusLogic_InitializeProbeInfoList();
+  int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
+  BusLogic_HostAdapter_T *PrototypeHostAdapter;
+  if (BusLogic_ProbeOptions.NoProbe) return 0;
+  BusLogic_ProbeInfoList = (BusLogic_ProbeInfo_T *)
+    kmalloc(BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T),
+	    GFP_ATOMIC);
+  if (BusLogic_ProbeInfoList == NULL)
+    {
+      BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL);
+      return 0;
+    }
+  memset(BusLogic_ProbeInfoList, 0,
+	 BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T));
+  PrototypeHostAdapter = (BusLogic_HostAdapter_T *)
+    kmalloc(sizeof(BusLogic_HostAdapter_T), GFP_ATOMIC);
+  if (PrototypeHostAdapter == NULL)
+    {
+      kfree(BusLogic_ProbeInfoList);
+      BusLogic_Error("BusLogic: Unable to allocate Prototype "
+		     "Host Adapter\n", NULL);
+      return 0;
+    }
+  memset(PrototypeHostAdapter, 0, sizeof(BusLogic_HostAdapter_T));
+  if (BusLogic_Options != NULL)
+    BusLogic_ParseDriverOptions(BusLogic_Options);
+  BusLogic_InitializeProbeInfoList(PrototypeHostAdapter);
   for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++)
     {
       BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex];
-      BusLogic_HostAdapter_T HostAdapterPrototype;
-      BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+      BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
       SCSI_Host_T *Host;
       if (ProbeInfo->IO_Address == 0) continue;
       memset(HostAdapter, 0, sizeof(BusLogic_HostAdapter_T));
-      HostAdapter->IO_Address = ProbeInfo->IO_Address;
-      HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
       HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType;
       HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType;
+      HostAdapter->IO_Address = ProbeInfo->IO_Address;
+      HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
       HostAdapter->Bus = ProbeInfo->Bus;
       HostAdapter->Device = ProbeInfo->Device;
       HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
       HostAdapter->AddressCount =
-	BusLogic_HostAdapter_AddressCount[HostAdapter->HostAdapterType];
-      if (MessageBuffer == NULL)
-	MessageBuffer =
-	  scsi_init_malloc(BusLogic_MessageBufferSize, GFP_ATOMIC);
-      if (MessageBuffer == NULL)
-	{
-	  BusLogic_Error("BusLogic: Unable to allocate Message Buffer\n",
-			 HostAdapter);
-	  return BusLogicHostAdapterCount;
-	}
-      HostAdapter->MessageBuffer = MessageBuffer;
-      /*
-	If an explicit I/O Address was specified, Initialize the Command Line
-	Entry field and inhibit the check for whether the I/O Address range is
-	already in use.
-      */
-      if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount &&
-	  BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address ==
-	  HostAdapter->IO_Address)
-	HostAdapter->CommandLineEntry =
-	  &BusLogic_CommandLineEntries[CommandLineEntryIndex++];
-      else if (check_region(HostAdapter->IO_Address,
-			    HostAdapter->AddressCount) < 0)
-	continue;
+	BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
       /*
 	Probe the Host Adapter.  If unsuccessful, abort further initialization.
       */
@@ -2738,22 +2779,20 @@
 	Hard Reset the Host Adapter.  If unsuccessful, abort further
 	initialization.
       */
-      if (!BusLogic_HardResetHostAdapter(HostAdapter)) continue;
+      if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue;
       /*
 	Check the Host Adapter.  If unsuccessful, abort further initialization.
       */
       if (!BusLogic_CheckHostAdapter(HostAdapter)) continue;
       /*
-	Initialize the Command Line Entry field if an explicit I/O Address
-	was not specified.
+	Initialize the Driver Options field if provided.
       */
-      if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount &&
-	  BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == 0)
-	HostAdapter->CommandLineEntry =
-	  &BusLogic_CommandLineEntries[CommandLineEntryIndex++];
+      if (DriverOptionsIndex < BusLogic_DriverOptionsCount)
+	HostAdapter->DriverOptions =
+	  &BusLogic_DriverOptions[DriverOptionsIndex++];
       /*
 	Announce the Driver Version and Date, Author's Name, Copyright Notice,
-	and Contact Address.
+	and Electronic Mail Address.
       */
       BusLogic_AnnounceDriver(HostAdapter);
       /*
@@ -2771,32 +2810,25 @@
       */
       Host = scsi_register(HostTemplate, sizeof(BusLogic_HostAdapter_T));
       HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata;
-      memcpy(HostAdapter, &HostAdapterPrototype,
-	     sizeof(BusLogic_HostAdapter_T));
+      memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T));
       HostAdapter->SCSI_Host = Host;
       HostAdapter->HostNumber = Host->host_no;
       Host->select_queue_depths = BusLogic_SelectQueueDepths;
       /*
 	Add Host Adapter to the end of the list of registered BusLogic
-	Host Adapters.  In order for Command Complete Interrupts to be
-	properly dismissed by BusLogic_InterruptHandler, the Host Adapter
-	must be registered.
+	Host Adapters.
       */
       BusLogic_RegisterHostAdapter(HostAdapter);
       /*
 	Read the Host Adapter Configuration, Configure the Host Adapter,
-	Acquire the System Resources necessary to use the Host Adapter,
-	then Test Interrupts, Create the Mailboxes, Initial CCBs, and
-	Target Device Statistics, Initialize the Host Adapter, and
-	finally perform Target Device Inquiry.
+	Acquire the System Resources necessary to use the Host Adapter, then
+	Create the Initial CCBs, Initialize the Host Adapter, and finally
+	perform Target Device Inquiry.
       */
       if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
 	  BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
 	  BusLogic_AcquireResources(HostAdapter) &&
-	  BusLogic_TestInterrupts(HostAdapter) &&
-	  BusLogic_CreateMailboxes(HostAdapter) &&
 	  BusLogic_CreateInitialCCBs(HostAdapter) &&
-	  BusLogic_CreateTargetDeviceStatistics(HostAdapter) &&
 	  BusLogic_InitializeHostAdapter(HostAdapter) &&
 	  BusLogic_TargetDeviceInquiry(HostAdapter))
 	{
@@ -2806,7 +2838,6 @@
 	    Name of the Host Adapter will appear, and initialize the SCSI
 	    Host structure.
 	  */
-	  MessageBuffer = NULL;
 	  release_region(HostAdapter->IO_Address,
 			 HostAdapter->AddressCount);
 	  request_region(HostAdapter->IO_Address,
@@ -2818,24 +2849,22 @@
       else
 	{
 	  /*
-	    An error occurred during Host Adapter Configuration Querying,
-	    Host Adapter Configuration, Resource Acquisition, Interrupt
-	    Testing, CCB Creation, Host Adapter Initialization, or Target
-	    Device Inquiry, so remove Host Adapter from the list of
-	    registered BusLogic Host Adapters, destroy the Target Device
-	    Statistics, CCBs, and Mailboxes, Release the System Resources,
-	    and Unregister the SCSI Host.
+	    An error occurred during Host Adapter Configuration Querying, Host
+	    Adapter Configuration, Resource Acquisition, CCB Creation, Host
+	    Adapter Initialization, or Target Device Inquiry, so remove Host
+	    Adapter from the list of registered BusLogic Host Adapters, destroy
+	    the CCBs, Release the System Resources, and Unregister the SCSI
+	    Host.
 	  */
-	  BusLogic_DestroyTargetDeviceStatistics(HostAdapter);
 	  BusLogic_DestroyCCBs(HostAdapter);
-	  BusLogic_DestroyMailboxes(HostAdapter);
 	  BusLogic_ReleaseResources(HostAdapter);
 	  BusLogic_UnregisterHostAdapter(HostAdapter);
 	  scsi_unregister(Host);
 	}
     }
-  if (MessageBuffer != NULL)
-    scsi_init_free(MessageBuffer, BusLogic_MessageBufferSize);
+  kfree(PrototypeHostAdapter);
+  kfree(BusLogic_ProbeInfoList);
+  BusLogic_ProbeInfoList = NULL;
   return BusLogicHostAdapterCount;
 }
 
@@ -2851,21 +2880,16 @@
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Host->hostdata;
   /*
-    FlashPoint Host Adapters must also be released by the FlashPoint
+    FlashPoint Host Adapters must first be released by the FlashPoint
     SCCB Manager.
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
-    {
-      FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle);
-      scsi_init_free((char *) HostAdapter->FlashPointInfo,
-		     sizeof(FlashPoint_Info_T));
-    }
+    FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle);
   /*
-    Destroy the CCBs and Mailboxes, and release any system resources acquired
-    to support Host Adapter.
+    Destroy the CCBs and release any system resources acquired to
+    support Host Adapter.
   */
   BusLogic_DestroyCCBs(HostAdapter);
-  BusLogic_DestroyMailboxes(HostAdapter);
   BusLogic_ReleaseResources(HostAdapter);
   /*
     Release usage of the I/O Address range.
@@ -2885,19 +2909,20 @@
 
 static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB)
 {
+  BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
   CCB->Status = BusLogic_CCB_Completed;
   CCB->Next = NULL;
-  if (BusLogic_FirstCompletedCCB == NULL)
+  if (HostAdapter->FirstCompletedCCB == NULL)
     {
-      BusLogic_FirstCompletedCCB = CCB;
-      BusLogic_LastCompletedCCB = CCB;
+      HostAdapter->FirstCompletedCCB = CCB;
+      HostAdapter->LastCompletedCCB = CCB;
     }
   else
     {
-      BusLogic_LastCompletedCCB->Next = CCB;
-      BusLogic_LastCompletedCCB = CCB;
+      HostAdapter->LastCompletedCCB->Next = CCB;
+      HostAdapter->LastCompletedCCB = CCB;
     }
-  CCB->HostAdapter->ActiveCommands[CCB->TargetID]--;
+  HostAdapter->ActiveCommands[CCB->TargetID]--;
 }
 
 
@@ -2988,27 +3013,29 @@
       BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
 	Bus_to_Virtual(NextIncomingMailbox->CCB);
       if (CompletionCode != BusLogic_AbortedCommandNotFound)
-	if (CCB->Status == BusLogic_CCB_Active ||
-	    CCB->Status == BusLogic_CCB_Reset)
-	  {
-	    /*
-	      Save the Completion Code for this CCB and queue the CCB
-	      for completion processing.
-	    */
-	    CCB->CompletionCode = CompletionCode;
-	    BusLogic_QueueCompletedCCB(CCB);
-	  }
-	else
-	  {
-	    /*
-	      If a CCB ever appears in an Incoming Mailbox and is not marked as
-	      status Active or Reset, then there is most likely a bug in the
-	      Host Adapter firmware.
-	    */
-	    BusLogic_Warning("Illegal CCB #%ld status %d in "
-			     "Incoming Mailbox\n", HostAdapter,
-			     CCB->SerialNumber, CCB->Status);
-	  }
+	{
+	  if (CCB->Status == BusLogic_CCB_Active ||
+	      CCB->Status == BusLogic_CCB_Reset)
+	    {
+	      /*
+		Save the Completion Code for this CCB and queue the CCB
+		for completion processing.
+	      */
+	      CCB->CompletionCode = CompletionCode;
+	      BusLogic_QueueCompletedCCB(CCB);
+	    }
+	  else
+	    {
+	      /*
+		If a CCB ever appears in an Incoming Mailbox and is not marked
+		as status Active or Reset, then there is most likely a bug in
+		the Host Adapter firmware.
+	      */
+	      BusLogic_Warning("Illegal CCB #%ld status %d in "
+			       "Incoming Mailbox\n", HostAdapter,
+			       CCB->SerialNumber, CCB->Status);
+	    }
+	}
       NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree;
       if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox)
 	NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
@@ -3018,25 +3045,23 @@
 
 
 /*
-  BusLogic_ProcessCompletedCCBs iterates over the completed CCBs setting
-  the SCSI Command Result Codes, deallocating the CCBs, and calling the
-  SCSI Subsystem Completion Routines.  Interrupts should already have been
-  disabled by the caller.
+  BusLogic_ProcessCompletedCCBs iterates over the completed CCBs for Host
+  Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and
+  calling the SCSI Subsystem Completion Routines.  The Host Adapter's Lock
+  should already have been acquired by the caller.
 */
 
-static void BusLogic_ProcessCompletedCCBs(void)
+static void BusLogic_ProcessCompletedCCBs(BusLogic_HostAdapter_T *HostAdapter)
 {
-  static boolean ProcessCompletedCCBsActive = false;
-  if (ProcessCompletedCCBsActive) return;
-  ProcessCompletedCCBsActive = true;
-  while (BusLogic_FirstCompletedCCB != NULL)
+  if (HostAdapter->ProcessCompletedCCBsActive) return;
+  HostAdapter->ProcessCompletedCCBsActive = true;
+  while (HostAdapter->FirstCompletedCCB != NULL)
     {
-      BusLogic_CCB_T *CCB = BusLogic_FirstCompletedCCB;
+      BusLogic_CCB_T *CCB = HostAdapter->FirstCompletedCCB;
       SCSI_Command_T *Command = CCB->Command;
-      BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
-      BusLogic_FirstCompletedCCB = CCB->Next;
-      if (BusLogic_FirstCompletedCCB == NULL)
-	BusLogic_LastCompletedCCB = NULL;
+      HostAdapter->FirstCompletedCCB = CCB->Next;
+      if (HostAdapter->FirstCompletedCCB == NULL)
+	HostAdapter->LastCompletedCCB = NULL;
       /*
 	Process the Completed CCB.
       */
@@ -3047,10 +3072,9 @@
 			   "%d Completed\n", HostAdapter,
 			   CCB->SerialNumber, TargetID);
 	  BusLogic_IncrementErrorCounter(
-	    &HostAdapter->TargetDeviceStatistics[TargetID]
-			  .BusDeviceResetsCompleted);
+	    &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted);
+	  HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
 	  HostAdapter->CommandsSinceReset[TargetID] = 0;
-	  HostAdapter->TaggedQueuingActive[TargetID] = false;
 	  HostAdapter->LastResetCompleted[TargetID] = jiffies;
 	  /*
 	    Place CCB back on the Host Adapter's free list.
@@ -3101,16 +3125,17 @@
 			       HostAdapter, CCB->SerialNumber, CCB->TargetID);
 	      break;
 	    case BusLogic_CommandCompletedWithoutError:
-	      HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+	      HostAdapter->TargetStatistics[CCB->TargetID]
 			   .CommandsCompleted++;
-	      HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true;
+	      HostAdapter->TargetFlags[CCB->TargetID]
+			   .CommandSuccessfulFlag = true;
 	      Command->result = DID_OK << 16;
 	      break;
 	    case BusLogic_CommandAbortedAtHostRequest:
 	      BusLogic_Warning("CCB #%ld to Target %d Aborted\n",
 			       HostAdapter, CCB->SerialNumber, CCB->TargetID);
 	      BusLogic_IncrementErrorCounter(
-		&HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+		&HostAdapter->TargetStatistics[CCB->TargetID]
 			      .CommandAbortsCompleted);
 	      Command->result = DID_ABORT << 16;
 	      break;
@@ -3121,9 +3146,9 @@
 					   CCB->TargetDeviceStatus);
 	      if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout)
 		{
-		  HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+		  HostAdapter->TargetStatistics[CCB->TargetID]
 			       .CommandsCompleted++;
-		  if (BusLogic_GlobalOptions.Bits.TraceErrors)
+		  if (BusLogic_GlobalOptions.TraceErrors)
 		      {
 			int i;
 			BusLogic_Notice("CCB #%ld Target %d: Result %X Host "
@@ -3147,6 +3172,22 @@
 	      break;
 	    }
 	  /*
+	    When an INQUIRY command completes normally, save the
+	    CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit
+	    Wide Data Transfers Supported) bits.
+	  */
+	  if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 &&
+	      CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally)
+	    {
+	      BusLogic_TargetFlags_T *TargetFlags =
+		&HostAdapter->TargetFlags[CCB->TargetID];
+	      SCSI_Inquiry_T *InquiryResult =
+		(SCSI_Inquiry_T *) Command->request_buffer;
+	      TargetFlags->TargetExists = true;
+	      TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue;
+	      TargetFlags->WideTransfersSupported = InquiryResult->WBus16;
+	    }
+	  /*
 	    Place CCB back on the Host Adapter's free list.
 	  */
 	  BusLogic_DeallocateCCB(CCB);
@@ -3156,7 +3197,7 @@
 	  Command->scsi_done(Command);
 	}
     }
-  ProcessCompletedCCBsActive = false;
+  HostAdapter->ProcessCompletedCCBsActive = false;
 }
 
 
@@ -3169,96 +3210,84 @@
 				      void *DeviceIdentifier,
 				      Registers_T *InterruptRegisters)
 {
-  BusLogic_HostAdapter_T *FirstHostAdapter =
-    BusLogic_RegisteredHostAdapters[IRQ_Channel];
-  boolean HostAdapterResetRequested = false;
-  BusLogic_HostAdapter_T *HostAdapter;
-  BusLogic_Lock_T Lock;
+  BusLogic_HostAdapter_T *HostAdapter =
+    (BusLogic_HostAdapter_T *) DeviceIdentifier;
+  ProcessorFlags_T ProcessorFlags;
   /*
-    Iterate over the installed BusLogic Host Adapters accepting any Incoming
-    Mailbox entries and saving the completed CCBs for processing.  This
-    interrupt handler is installed as a fast interrupt, so interrupts are
-    disabled when the interrupt handler is entered.
+    Acquire exclusive access to Host Adapter.
   */
-  for (HostAdapter = FirstHostAdapter;
-       HostAdapter != NULL;
-       HostAdapter = HostAdapter->Next)
+  BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags);
+  /*
+    Handle Interrupts appropriately for each Host Adapter type.
+  */
+  if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
     {
+      BusLogic_InterruptRegister_T InterruptRegister;
       /*
-	Acquire exclusive access to Host Adapter.
+	Read the Host Adapter Interrupt Register.
       */
-      BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
-      /*
-	Handle Interrupts appropriately for each Host Adapter type.
-      */
-      if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
+      InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+      if (InterruptRegister.Bits.InterruptValid)
 	{
-	  BusLogic_InterruptRegister_T InterruptRegister;
 	  /*
-	    Read the Host Adapter Interrupt Register.
+	    Acknowledge the interrupt and reset the Host Adapter
+	    Interrupt Register.
 	  */
-	  InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
-	  if (InterruptRegister.Bits.InterruptValid)
-	    {
-	      /*
-		Acknowledge the interrupt and reset the Host Adapter
-		Interrupt Register.
-	      */
-	      BusLogic_InterruptReset(HostAdapter);
-	      /*
-		Process valid External SCSI Bus Reset and Incoming Mailbox
-		Loaded Interrupts.  Command Complete Interrupts are noted,
-		and Outgoing Mailbox Available Interrupts are ignored, as
-		they are never enabled.
-	      */
-	      if (InterruptRegister.Bits.ExternalBusReset)
-		{
-		  HostAdapter->HostAdapterResetRequested = true;
-		  HostAdapterResetRequested = true;
-		}
-	      else if (InterruptRegister.Bits.IncomingMailboxLoaded)
-		BusLogic_ScanIncomingMailboxes(HostAdapter);
-	      else if (InterruptRegister.Bits.CommandComplete)
-		HostAdapter->HostAdapterCommandCompleted = true;
-	    }
-	}
-      else
-	{
+	  BusLogic_InterruptReset(HostAdapter);
 	  /*
-	    Check if there is a pending interrupt for this Host Adapter.
+	    Process valid External SCSI Bus Reset and Incoming Mailbox
+	    Loaded Interrupts.  Command Complete Interrupts are noted,
+	    and Outgoing Mailbox Available Interrupts are ignored, as
+	    they are never enabled.
 	  */
-	  if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
-	    if (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)
-		== FlashPoint_ExternalBusReset)
-	      {
-		HostAdapter->HostAdapterResetRequested = true;
-		HostAdapterResetRequested = true;
-	      }
+	  if (InterruptRegister.Bits.ExternalBusReset)
+	    HostAdapter->HostAdapterExternalReset = true;
+	  else if (InterruptRegister.Bits.IncomingMailboxLoaded)
+	    BusLogic_ScanIncomingMailboxes(HostAdapter);
+	  else if (InterruptRegister.Bits.CommandComplete)
+	    HostAdapter->HostAdapterCommandCompleted = true;
 	}
+    }
+  else
+    {
       /*
-	Release exclusive access to Host Adapter.
+	Check if there is a pending interrupt for this Host Adapter.
       */
-      BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
+      if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
+	switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
+	  {
+	  case FlashPoint_NormalInterrupt:
+	    break;
+	  case FlashPoint_ExternalBusReset:
+	    HostAdapter->HostAdapterExternalReset = true;
+	    break;
+	  case FlashPoint_InternalError:
+	    BusLogic_Warning("Internal FlashPoint Error detected"
+			     " - Resetting Host Adapter\n", HostAdapter);
+	    HostAdapter->HostAdapterInternalError = true;
+	    break;
+	  }
     }
   /*
     Process any completed CCBs.
   */
-  if (BusLogic_FirstCompletedCCB != NULL)
-    BusLogic_ProcessCompletedCCBs();
+  if (HostAdapter->FirstCompletedCCB != NULL)
+    BusLogic_ProcessCompletedCCBs(HostAdapter);
   /*
-    Iterate over the Host Adapters performing any requested
-    Host Adapter Resets.
+    Reset the Host Adapter if requested.
   */
-  if (HostAdapterResetRequested)
-    for (HostAdapter = FirstHostAdapter;
-	 HostAdapter != NULL;
-	 HostAdapter = HostAdapter->Next)
-      if (HostAdapter->HostAdapterResetRequested)
-	{
-	  BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
-	  HostAdapter->HostAdapterResetRequested = false;
-	  scsi_mark_host_reset(HostAdapter->SCSI_Host);
-	}
+  if (HostAdapter->HostAdapterExternalReset ||
+      HostAdapter->HostAdapterInternalError)
+    {
+      BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
+      HostAdapter->HostAdapterExternalReset = false;
+      HostAdapter->HostAdapterInternalError = false;
+      scsi_mark_host_reset(HostAdapter->SCSI_Host);
+    }
+  /*
+    Release exclusive access to Host Adapter.
+  */
+  BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags);
 }
 
 
@@ -3293,8 +3322,7 @@
 	{
 	  HostAdapter->ActiveCommands[CCB->TargetID]++;
 	  if (CCB->Opcode != BusLogic_BusDeviceReset)
-	    HostAdapter->TargetDeviceStatistics[CCB->TargetID]
-			 .CommandsAttempted++;
+	    HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++;
 	}
       return true;
     }
@@ -3312,8 +3340,10 @@
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
-  BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics =
-    HostAdapter->TargetDeviceStatistics;
+  BusLogic_TargetFlags_T *TargetFlags =
+    &HostAdapter->TargetFlags[Command->target];
+  BusLogic_TargetStatistics_T *TargetStatistics =
+    HostAdapter->TargetStatistics;
   unsigned char *CDB = Command->cmnd;
   int CDB_Length = Command->cmd_len;
   int TargetID = Command->target;
@@ -3321,7 +3351,7 @@
   void *BufferPointer = Command->request_buffer;
   int BufferLength = Command->request_bufflen;
   int SegmentCount = Command->use_sg;
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   BusLogic_CCB_T *CCB;
   /*
     SCSI REQUEST_SENSE commands will be executed automatically by the Host
@@ -3337,7 +3367,7 @@
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     Allocate a CCB from the Host Adapter's free list.  In the unlikely event
     that there are none available and memory allocation fails, wait 1 second
@@ -3371,13 +3401,9 @@
       int Segment;
       CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
       CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T);
-#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
       if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
 	CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
-      else CCB->DataPointer = (BusLogic_BusAddress_T) CCB->ScatterGatherList;
-#else
-      CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
-#endif
+      else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList);
       for (Segment = 0; Segment < SegmentCount; Segment++)
 	{
 	  CCB->ScatterGatherList[Segment].SegmentByteCount =
@@ -3391,22 +3417,20 @@
     case READ_6:
     case READ_10:
       CCB->DataDirection = BusLogic_DataInLengthChecked;
-      TargetDeviceStatistics[TargetID].ReadCommands++;
+      TargetStatistics[TargetID].ReadCommands++;
       BusLogic_IncrementByteCounter(
-	&TargetDeviceStatistics[TargetID].TotalBytesRead, BufferLength);
+	&TargetStatistics[TargetID].TotalBytesRead, BufferLength);
       BusLogic_IncrementSizeBucket(
-	TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets,
-	BufferLength);
+	TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength);
       break;
     case WRITE_6:
     case WRITE_10:
       CCB->DataDirection = BusLogic_DataOutLengthChecked;
-      TargetDeviceStatistics[TargetID].WriteCommands++;
+      TargetStatistics[TargetID].WriteCommands++;
       BusLogic_IncrementByteCounter(
-	&TargetDeviceStatistics[TargetID].TotalBytesWritten, BufferLength);
+	&TargetStatistics[TargetID].TotalBytesWritten, BufferLength);
       BusLogic_IncrementSizeBucket(
-	TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets,
-	BufferLength);
+	TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength);
       break;
     default:
       CCB->DataDirection = BusLogic_UncheckedDataTransfer;
@@ -3434,20 +3458,18 @@
     necessary to wait until there are no pending commands for a target device
     before queuing tagged commands.
   */
-  HostAdapter->TaggedQueuingSupported[TargetID] =
-    Command->device->tagged_supported;
   if (HostAdapter->CommandsSinceReset[TargetID]++ >=
 	BusLogic_MaxTaggedQueueDepth &&
-      !HostAdapter->TaggedQueuingActive[TargetID] &&
+      !TargetFlags->TaggedQueuingActive &&
       HostAdapter->ActiveCommands[TargetID] == 0 &&
-      HostAdapter->TaggedQueuingSupported[TargetID] &&
+      TargetFlags->TaggedQueuingSupported &&
       (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
     {
-      HostAdapter->TaggedQueuingActive[TargetID] = true;
+      TargetFlags->TaggedQueuingActive = true;
       BusLogic_Notice("Tagged Queuing now active for Target %d\n",
 		      HostAdapter, TargetID);
     }
-  if (HostAdapter->TaggedQueuingActive[TargetID])
+  if (TargetFlags->TaggedQueuingActive)
     {
       BusLogic_QueueTag_T QueueTag = BusLogic_SimpleQueueTag;
       /*
@@ -3457,7 +3479,7 @@
 	write nearer the head position continue to arrive without interruption.
 	Therefore, for each Target Device this driver keeps track of the last
 	time either the queue was empty or an Ordered Queue Tag was issued.  If
-	more than 3 seconds (one fifth of the 15 second disk timeout) have
+	more than 4 seconds (one fifth of the 20 second disk timeout) have
 	elapsed since this last sequence point, this command will be issued
 	with an Ordered Queue Tag rather than a Simple Queue Tag, which forces
 	the Target Device to complete all previously queued commands before
@@ -3465,7 +3487,7 @@
       */
       if (HostAdapter->ActiveCommands[TargetID] == 0)
 	HostAdapter->LastSequencePoint[TargetID] = jiffies;
-      else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 3*HZ)
+      else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4*HZ)
 	{
 	  HostAdapter->LastSequencePoint[TargetID] = jiffies;
 	  QueueTag = BusLogic_OrderedQueueTag;
@@ -3519,20 +3541,20 @@
       */
       CCB->Status = BusLogic_CCB_Active;
       HostAdapter->ActiveCommands[TargetID]++;
-      TargetDeviceStatistics[TargetID].CommandsAttempted++;
+      TargetStatistics[TargetID].CommandsAttempted++;
       FlashPoint_StartCCB(HostAdapter->CardHandle, CCB);
       /*
 	The Command may have already completed and BusLogic_QueueCompletedCCB
 	been called, or it may still be pending.
       */
       if (CCB->Status == BusLogic_CCB_Completed)
-	BusLogic_ProcessCompletedCCBs();
+	BusLogic_ProcessCompletedCCBs(HostAdapter);
     }
   /*
     Release exclusive access to Host Adapter.
   */
 Done:
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return 0;
 }
 
@@ -3546,15 +3568,15 @@
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
   int TargetID = Command->target;
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   BusLogic_CCB_T *CCB;
   int Result;
   BusLogic_IncrementErrorCounter(
-    &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsRequested);
+    &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested);
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     If this Command has already completed, then no Abort is necessary.
   */
@@ -3604,7 +3626,7 @@
 	Firmware version 5.xx does generate Abort Tag messages, so it is
 	possible to abort commands when Tagged Queuing is active.
       */
-      if (HostAdapter->TaggedQueuingActive[TargetID] &&
+      if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
 	  HostAdapter->FirmwareVersion[0] < '5')
 	{
 	  BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - "
@@ -3618,8 +3640,7 @@
 	  BusLogic_Warning("Aborting CCB #%ld to Target %d\n",
 			   HostAdapter, CCB->SerialNumber, TargetID);
 	  BusLogic_IncrementErrorCounter(
-	    &HostAdapter->TargetDeviceStatistics[TargetID]
-			  .CommandAbortsAttempted);
+	    &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
 	  Result = SCSI_ABORT_PENDING;
 	}
       else
@@ -3638,7 +3659,7 @@
       BusLogic_Warning("Aborting CCB #%ld to Target %d\n",
 		       HostAdapter, CCB->SerialNumber, TargetID);
       BusLogic_IncrementErrorCounter(
-	&HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsAttempted);
+	&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
       FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB);
       /*
 	The Abort may have already been completed and
@@ -3648,7 +3669,7 @@
       Result = SCSI_ABORT_PENDING;
       if (CCB->Status == BusLogic_CCB_Completed)
 	{
-	  BusLogic_ProcessCompletedCCBs();
+	  BusLogic_ProcessCompletedCCBs(HostAdapter);
 	  Result = SCSI_ABORT_SUCCESS;
 	}
     }
@@ -3656,7 +3677,7 @@
     Release exclusive access to Host Adapter.
   */
 Done:
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return Result;
 }
 
@@ -3670,18 +3691,31 @@
 				     SCSI_Command_T *Command,
 				     unsigned int ResetFlags)
 {
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   BusLogic_CCB_T *CCB;
   int TargetID, Result;
-  if (Command == NULL)
-    BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets);
-  else BusLogic_IncrementErrorCounter(
-	 &HostAdapter->TargetDeviceStatistics[Command->target]
-		       .HostAdapterResetsRequested);
+  boolean HardReset;
+  if (HostAdapter->HostAdapterExternalReset)
+    {
+      BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets);
+      HardReset = false;
+    }
+  else if (HostAdapter->HostAdapterInternalError)
+    {
+      BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors);
+      HardReset = true;
+    }
+  else
+    {
+      BusLogic_IncrementErrorCounter(
+	&HostAdapter->TargetStatistics[Command->target]
+		      .HostAdapterResetsRequested);
+      HardReset = true;
+    }
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     If this is an Asynchronous Reset and this Command has already completed,
     then no Reset is necessary.
@@ -3723,20 +3757,25 @@
 	}
     }
   if (Command == NULL)
-    BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n",
-		     HostAdapter, HostAdapter->FullModelName);
+    {
+      if (HostAdapter->HostAdapterInternalError)
+	BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n",
+			 HostAdapter, HostAdapter->FullModelName);
+      else BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n",
+			    HostAdapter, HostAdapter->FullModelName);
+    }
   else
     {
       BusLogic_Warning("Resetting %s due to Target %d\n", HostAdapter,
 		       HostAdapter->FullModelName, Command->target);
       BusLogic_IncrementErrorCounter(
-	&HostAdapter->TargetDeviceStatistics[Command->target]
+	&HostAdapter->TargetStatistics[Command->target]
 		      .HostAdapterResetsAttempted);
     }
   /*
     Attempt to Reset and Reinitialize the Host Adapter.
   */
-  if (!(BusLogic_HardResetHostAdapter(HostAdapter) &&
+  if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) &&
 	BusLogic_InitializeHostAdapter(HostAdapter)))
     {
       BusLogic_Error("Resetting %s Failed\n", HostAdapter,
@@ -3746,7 +3785,7 @@
     }
   if (Command != NULL)
     BusLogic_IncrementErrorCounter(
-      &HostAdapter->TargetDeviceStatistics[Command->target]
+      &HostAdapter->TargetStatistics[Command->target]
 		    .HostAdapterResetsCompleted);
   /*
     Mark all currently executing CCBs as having been Reset.
@@ -3761,7 +3800,8 @@
     Note that a timer interrupt may occur here, but all active CCBs have
     already been marked Reset and so a reentrant call will return Pending.
   */
-  BusLogic_Delay(HostAdapter->BusSettleTime);
+  if (HardReset)
+    BusLogic_Delay(HostAdapter->BusSettleTime);
   /*
     If this is a Synchronous Reset, perform completion processing for
     the Command being Reset.
@@ -3798,7 +3838,7 @@
     Release exclusive access to Host Adapter.
   */
 Done:
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return Result;
 }
 
@@ -3814,14 +3854,14 @@
 {
   int TargetID = Command->target;
   BusLogic_CCB_T *CCB, *XCCB;
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   int Result = -1;
   BusLogic_IncrementErrorCounter(
-    &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsRequested);
+    &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested);
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     If this is an Asynchronous Reset and this Command has already completed,
     then no Reset is necessary.
@@ -3891,7 +3931,7 @@
 	while there are tagged commands outstanding.  Therefore, in that case a
 	full Host Adapter Hard Reset and SCSI Bus Reset must be done.
       */
-      if (HostAdapter->TaggedQueuingActive[TargetID] &&
+      if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
 	  HostAdapter->ActiveCommands[TargetID] > 0 &&
 	  HostAdapter->FirmwareVersion[0] < '5')
 	goto Done;
@@ -3958,7 +3998,7 @@
     processing performed.
   */
   BusLogic_IncrementErrorCounter(
-    &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted);
+    &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsAttempted);
   HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB;
   HostAdapter->LastResetAttempted[TargetID] = jiffies;
   for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll)
@@ -3973,7 +4013,7 @@
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     if (CCB->Status == BusLogic_CCB_Completed)
       {
-	BusLogic_ProcessCompletedCCBs();
+	BusLogic_ProcessCompletedCCBs(HostAdapter);
 	Result = SCSI_RESET_SUCCESS;
       }
   /*
@@ -3986,7 +4026,7 @@
   /*
     Release exclusive access to Host Adapter.
   */
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return Result;
 }
 
@@ -4007,11 +4047,11 @@
     it has been less than 10 minutes since the last reset occurred, or since
     the system was initialized if no prior resets have occurred.
   */
-  if (HostAdapter->TaggedQueuingActive[TargetID] &&
+  if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
       jiffies - HostAdapter->LastResetCompleted[TargetID] < 10*60*HZ)
     {
       HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
-      HostAdapter->TaggedQueuingActive[TargetID] = false;
+      HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
       BusLogic_Warning("Tagged Queuing now disabled for Target %d\n",
 		       HostAdapter, TargetID);
     }
@@ -4032,10 +4072,10 @@
 	forcing a Hard Reset before the Bus Device Reset has had a chance to
 	clear the error condition.
       */
-      if (HostAdapter->CommandSuccessfulFlag[TargetID] ||
+      if (HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag ||
 	  jiffies - HostAdapter->LastResetAttempted[TargetID] < HZ/10)
 	{
-	  HostAdapter->CommandSuccessfulFlag[TargetID] = false;
+	  HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false;
 	  return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags);
 	}
       /* Fall through to Hard Reset case. */
@@ -4076,16 +4116,18 @@
   struct buffer_head *BufferHead;
   if (HostAdapter->ExtendedTranslationEnabled &&
       Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */)
-    if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */)
-      {
-	DiskParameters->Heads = 255;
-	DiskParameters->Sectors = 63;
-      }
-    else
-      {
-	DiskParameters->Heads = 128;
-	DiskParameters->Sectors = 32;
-      }
+    {
+      if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */)
+	{
+	  DiskParameters->Heads = 255;
+	  DiskParameters->Sectors = 63;
+	}
+      else
+	{
+	  DiskParameters->Heads = 128;
+	  DiskParameters->Sectors = 32;
+	}
+    }
   else
     {
       DiskParameters->Heads = 64;
@@ -4105,24 +4147,28 @@
   */
   if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55)
     {
-      struct partition *PartitionEntry =
-	(struct partition *) (BufferHead->b_data + 0x1BE);
+      PartitionTable_T *FirstPartitionEntry =
+	(PartitionTable_T *) (BufferHead->b_data + 0x1BE);
+      PartitionTable_T *PartitionEntry = FirstPartitionEntry;
       int SavedCylinders = DiskParameters->Cylinders, PartitionNumber;
+      unsigned char PartitionEntryEndHead, PartitionEntryEndSector;
       for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++)
 	{
-	  if (PartitionEntry->end_head == 64-1)
+	  PartitionEntryEndHead = PartitionEntry->end_head;
+	  PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F;
+	  if (PartitionEntryEndHead == 64-1)
 	    {
 	      DiskParameters->Heads = 64;
 	      DiskParameters->Sectors = 32;
 	      break;
 	    }
-	  else if (PartitionEntry->end_head == 128-1)
+	  else if (PartitionEntryEndHead == 128-1)
 	    {
 	      DiskParameters->Heads = 128;
 	      DiskParameters->Sectors = 32;
 	      break;
 	    }
-	  else if (PartitionEntry->end_head == 255-1)
+	  else if (PartitionEntryEndHead == 255-1)
 	    {
 	      DiskParameters->Heads = 255;
 	      DiskParameters->Sectors = 63;
@@ -4130,14 +4176,29 @@
 	    }
 	  PartitionEntry++;
 	}
+      if (PartitionNumber == 4)
+	{
+	  PartitionEntryEndHead = FirstPartitionEntry->end_head;
+	  PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F;
+	}
       DiskParameters->Cylinders =
 	Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
-      if (SavedCylinders != DiskParameters->Cylinders)
+      if (PartitionNumber < 4 &&
+	  PartitionEntryEndSector == DiskParameters->Sectors)
 	{
-	  BusLogic_Warning("Warning: Extended Translation Setting "
-			   "(> 1GB Switch) does not match\n", HostAdapter);
-	  BusLogic_Warning("Partition Table - Adopting %d/%d Geometry "
-			   "from Partition Table\n", HostAdapter,
+	  if (DiskParameters->Cylinders != SavedCylinders)
+	    BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n",
+			     HostAdapter,
+			     DiskParameters->Heads, DiskParameters->Sectors);
+	}
+      else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0)
+	{
+	  BusLogic_Warning("Warning: Partition Table appears to "
+			   "have Geometry %d/%d which is\n", HostAdapter,
+			   PartitionEntryEndHead + 1,
+			   PartitionEntryEndSector);
+	  BusLogic_Warning("not compatible with current BusLogic "
+			   "Host Adapter Geometry %d/%d\n", HostAdapter,
 			   DiskParameters->Heads, DiskParameters->Sectors);
 	}
     }
@@ -4155,22 +4216,21 @@
 			       int HostNumber, int WriteFlag)
 {
   BusLogic_HostAdapter_T *HostAdapter;
-  BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics;
-  int IRQ_Channel, TargetID, Length;
+  BusLogic_TargetStatistics_T *TargetStatistics;
+  int TargetID, Length;
   char *Buffer;
   if (WriteFlag) return 0;
-  for (IRQ_Channel = 0; IRQ_Channel < NR_IRQS; IRQ_Channel++)
+  for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
+       HostAdapter != NULL;
+       HostAdapter = HostAdapter->Next)
+    if (HostAdapter->HostNumber == HostNumber) break;
+  if (HostAdapter == NULL)
     {
-      HostAdapter = BusLogic_RegisteredHostAdapters[IRQ_Channel];
-      while (HostAdapter != NULL)
-	{
-	  if (HostAdapter->HostNumber == HostNumber) break;
-	  HostAdapter = HostAdapter->Next;
-	}
-      if (HostAdapter != NULL) break;
+      BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n",
+		     NULL, HostNumber);
+      return 0;
     }
-  if (HostAdapter == NULL) return -1;
-  TargetDeviceStatistics = HostAdapter->TargetDeviceStatistics;
+  TargetStatistics = HostAdapter->TargetStatistics;
   Buffer = HostAdapter->MessageBuffer;
   Length = HostAdapter->MessageBufferLength;
   Length += sprintf(&Buffer[Length], "\n\
@@ -4181,100 +4241,105 @@
   Length += sprintf(&Buffer[Length], "\n\n\
 			   DATA TRANSFER STATISTICS\n\
 \n\
-Target	Tagged Queuing	Queue Depth  Commands Attempted	 Commands Completed\n\
-======	==============	===========  ==================	 ==================\n");
+Target	Tagged Queuing	Queue Depth  Active  Attempted	Completed\n\
+======	==============	===========  ======  =========	=========\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
-	Length +=
-	  sprintf(&Buffer[Length], "  %2d	%s", TargetID,
-		  (HostAdapter->TaggedQueuingSupported[TargetID]
-		   ? (HostAdapter->TaggedQueuingActive[TargetID]
-		      ? "    Active"
-		      : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
-			 ? "  Permitted" : "   Disabled"))
-		   : "Not Supported"));
-	Length += sprintf(&Buffer[Length],
-			  "	    %3d		 %9u	     %9u\n",
-			  HostAdapter->QueueDepth[TargetID],
-			  TargetDeviceStatistics[TargetID].CommandsAttempted,
-			  TargetDeviceStatistics[TargetID].CommandsCompleted);
-      }
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length], "  %2d	%s", TargetID,
+		(TargetFlags->TaggedQueuingSupported
+		 ? (TargetFlags->TaggedQueuingActive
+		    ? "    Active"
+		    : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
+		       ? "  Permitted" : "   Disabled"))
+		 : "Not Supported"));
+      Length += sprintf(&Buffer[Length],
+			"	    %3d       %3u    %9u	%9u\n",
+			HostAdapter->QueueDepth[TargetID],
+			HostAdapter->ActiveCommands[TargetID],
+			TargetStatistics[TargetID].CommandsAttempted,
+			TargetStatistics[TargetID].CommandsCompleted);
+    }
   Length += sprintf(&Buffer[Length], "\n\
 Target  Read Commands  Write Commands   Total Bytes Read    Total Bytes Written\n\
 ======  =============  ==============  ===================  ===================\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length], "  %2d	  %9u	 %9u", TargetID,
+		TargetStatistics[TargetID].ReadCommands,
+		TargetStatistics[TargetID].WriteCommands);
+      if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0)
 	Length +=
-	  sprintf(&Buffer[Length], "  %2d	  %9u	 %9u", TargetID,
-		  TargetDeviceStatistics[TargetID].ReadCommands,
-		  TargetDeviceStatistics[TargetID].WriteCommands);
-	if (TargetDeviceStatistics[TargetID].TotalBytesRead.Billions > 0)
-	  Length +=
-	    sprintf(&Buffer[Length], "     %9u%09u",
-		    TargetDeviceStatistics[TargetID].TotalBytesRead.Billions,
-		    TargetDeviceStatistics[TargetID].TotalBytesRead.Units);
-	else
-	  Length +=
-	    sprintf(&Buffer[Length], "		%9u",
-		    TargetDeviceStatistics[TargetID].TotalBytesRead.Units);
-	if (TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions > 0)
-	  Length +=
-	    sprintf(&Buffer[Length], "   %9u%09u\n",
-		    TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions,
-		    TargetDeviceStatistics[TargetID].TotalBytesWritten.Units);
-	else
-	  Length +=
-	    sprintf(&Buffer[Length], "	     %9u\n",
-		    TargetDeviceStatistics[TargetID].TotalBytesWritten.Units);
-      }
+	  sprintf(&Buffer[Length], "     %9u%09u",
+		  TargetStatistics[TargetID].TotalBytesRead.Billions,
+		  TargetStatistics[TargetID].TotalBytesRead.Units);
+      else
+	Length +=
+	  sprintf(&Buffer[Length], "		%9u",
+		  TargetStatistics[TargetID].TotalBytesRead.Units);
+      if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0)
+	Length +=
+	  sprintf(&Buffer[Length], "   %9u%09u\n",
+		  TargetStatistics[TargetID].TotalBytesWritten.Billions,
+		  TargetStatistics[TargetID].TotalBytesWritten.Units);
+      else
+	Length +=
+	  sprintf(&Buffer[Length], "	     %9u\n",
+		  TargetStatistics[TargetID].TotalBytesWritten.Units);
+    }
   Length += sprintf(&Buffer[Length], "\n\
 Target  Command    0-1KB      1-2KB      2-4KB      4-8KB     8-16KB\n\
 ======  =======  =========  =========  =========  =========  =========\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[0],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[1],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[2],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[3],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[4]);
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[0],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[1],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[2],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[3],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[4]);
-      }
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[0],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[1],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[2],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[3],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[4]);
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[0],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[1],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[2],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[3],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[4]);
+    }
   Length += sprintf(&Buffer[Length], "\n\
 Target  Command   16-32KB    32-64KB   64-128KB   128-256KB   256KB+\n\
 ======  =======  =========  =========  =========  =========  =========\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[5],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[6],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[7],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[8],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[9]);
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[5],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[6],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[7],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[8],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[9]);
-      }
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[5],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[6],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[7],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[8],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[9]);
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[5],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[6],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[7],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[8],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[9]);
+    }
   Length += sprintf(&Buffer[Length], "\n\n\
 			   ERROR RECOVERY STATISTICS\n\
 \n\
@@ -4283,21 +4348,26 @@
   ID	\\\\\\\\ Attempted ////  \\\\\\\\ Attempted ////  \\\\\\\\ Attempted ////\n\
 ======	 ===== ===== =====    ===== ===== =====	   ===== ===== =====\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
       Length +=
 	sprintf(&Buffer[Length], "\
   %2d	 %5d %5d %5d    %5d %5d %5d	   %5d %5d %5d\n", TargetID,
-		TargetDeviceStatistics[TargetID].CommandAbortsRequested,
-		TargetDeviceStatistics[TargetID].CommandAbortsAttempted,
-		TargetDeviceStatistics[TargetID].CommandAbortsCompleted,
-		TargetDeviceStatistics[TargetID].BusDeviceResetsRequested,
-		TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted,
-		TargetDeviceStatistics[TargetID].BusDeviceResetsCompleted,
-		TargetDeviceStatistics[TargetID].HostAdapterResetsRequested,
-		TargetDeviceStatistics[TargetID].HostAdapterResetsAttempted,
-		TargetDeviceStatistics[TargetID].HostAdapterResetsCompleted);
+		TargetStatistics[TargetID].CommandAbortsRequested,
+		TargetStatistics[TargetID].CommandAbortsAttempted,
+		TargetStatistics[TargetID].CommandAbortsCompleted,
+		TargetStatistics[TargetID].BusDeviceResetsRequested,
+		TargetStatistics[TargetID].BusDeviceResetsAttempted,
+		TargetStatistics[TargetID].BusDeviceResetsCompleted,
+		TargetStatistics[TargetID].HostAdapterResetsRequested,
+		TargetStatistics[TargetID].HostAdapterResetsAttempted,
+		TargetStatistics[TargetID].HostAdapterResetsCompleted);
+    }
   Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n",
 		    HostAdapter->ExternalHostAdapterResets);
+  Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n",
+		    HostAdapter->HostAdapterInternalErrors);
   if (Length >= BusLogic_MessageBufferSize)
     BusLogic_Error("Message Buffer length %d exceeds size %d\n",
 		   HostAdapter, Length, BusLogic_MessageBufferSize);
@@ -4339,17 +4409,22 @@
 	     Buffer);
       HostAdapter->MessageBufferLength += Length;
       if (BeginningOfLine)
-	printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
-	       HostAdapter->HostNumber, Buffer);
+	{
+	  if (Buffer[0] != '\n' || Length > 1)
+	    printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
+		   HostAdapter->HostNumber, Buffer);
+	}
       else printk("%s", Buffer);
     }
   else
     {
       if (BeginningOfLine)
-	if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized)
-	  printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
-		 HostAdapter->HostNumber, Buffer);
-	else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+	{
+	  if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized)
+	    printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
+		   HostAdapter->HostNumber, Buffer);
+	  else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+	}
       else printk("%s", Buffer);
     }
   BeginningOfLine = (Buffer[Length-1] == '\n');
@@ -4357,364 +4432,553 @@
 
 
 /*
-  BusLogic_Setup handles processing of Kernel Command Line Arguments.
+  BusLogic_ParseKeyword parses an individual option keyword.  It returns true
+  and updates the pointer if the keyword is recognized and false otherwise.
+*/
 
-  For the BusLogic driver, a Kernel Command Line Entry comprises the driver
-  identifier "BusLogic=" optionally followed by a comma-separated sequence of
-  integers and then optionally followed by a comma-separated sequence of
-  strings.  Each command line entry applies to one BusLogic Host Adapter.
-  Multiple command line entries may be used in systems which contain multiple
-  BusLogic Host Adapters.
+static boolean BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
+{
+  char *Pointer = *StringPointer;
+  while (*Keyword != '\0')
+    {
+      char StringChar = *Pointer++;
+      char KeywordChar = *Keyword++;
+      if (StringChar >= 'A' && StringChar <= 'Z')
+	StringChar += 'a' - 'Z';
+      if (KeywordChar >= 'A' && KeywordChar <= 'Z')
+	KeywordChar += 'a' - 'Z';
+      if (StringChar != KeywordChar) return false;
+    }
+  *StringPointer = Pointer;
+  return true;
+}
 
-  The first integer specified is the I/O Address at which the Host Adapter is
-  located.  If unspecified, it defaults to 0 which means to apply this entry to
-  the first BusLogic Host Adapter found during the default probe sequence.  If
-  any I/O Address parameters are provided on the command line, then the default
-  probe sequence is omitted.
-
-  The second integer specified is the Tagged Queue Depth to use for Target
-  Devices that support Tagged Queuing.  The Queue Depth is the number of SCSI
-  commands that are allowed to be concurrently presented for execution.  If
-  unspecified, it defaults to 0 which means to use a value determined
-  automatically based on the Host Adapter's Total Queue Depth and the number,
-  type, speed, and capabilities of the detected Target Devices.  For Host
-  Adapters that require ISA Bounce Buffers, the Tagged Queue Depth is
-  automatically set to BusLogic_TaggedQueueDepthBounceBuffers to avoid
-  excessive preallocation of DMA Bounce Buffer memory.  Target Devices that do
-  not support Tagged Queuing use a Queue Depth of BusLogic_UntaggedQueueDepth.
-
-  The third integer specified is the Bus Settle Time in seconds.  This is
-  the amount of time to wait between a Host Adapter Hard Reset which initiates
-  a SCSI Bus Reset and issuing any SCSI Commands.  If unspecified, it defaults
-  to 0 which means to use the value of BusLogic_DefaultBusSettleTime.
-
-  The fourth integer specified is the Local Options.  If unspecified, it
-  defaults to 0.  Note that Local Options are only applied to a specific Host
-  Adapter.
 
-  The fifth integer specified is the Global Options.  If unspecified, it
-  defaults to 0.  Note that Global Options are applied across all Host
-  Adapters.
+/*
+  BusLogic_ParseDriverOptions handles processing of BusLogic Driver Options
+  specifications.
 
-  The string options are used to provide control over Tagged Queuing, Error
-  Recovery, and Host Adapter Probing.
+  BusLogic Driver Options may be specified either via the Linux Kernel Command
+  Line or via the Loadable Kernel Module Installation Facility.  Driver Options
+  for multiple host adapters may be specified either by separating the option
+  strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
+  command line.  Individual option specifications for a single host adapter are
+  separated by commas.  The Probing and Debugging Options apply to all host
+  adapters whereas the remaining options apply individually only to the
+  selected host adapter.
 
-  The Tagged Queuing specification begins with "TQ:" and allows for explicitly
-  specifying whether Tagged Queuing is permitted on Target Devices that support
-  it.  The following specification options are available:
-
-  TQ:Default		Tagged Queuing will be permitted based on the firmware
-			version of the BusLogic Host Adapter and based on
-			whether the Tagged Queue Depth value allows queuing
-			multiple commands.
-
-  TQ:Enable		Tagged Queuing will be enabled for all Target Devices
-			on this Host Adapter overriding any limitation that
-			would otherwise be imposed based on the Host Adapter
-			firmware version.
-
-  TQ:Disable		Tagged Queuing will be disabled for all Target Devices
-			on this Host Adapter.
-
-  TQ:<Per-Target-Spec>	Tagged Queuing will be controlled individually for each
-			Target Device.  <Per-Target-Spec> is a sequence of "Y",
-			"N", and "X" characters.  "Y" enabled Tagged Queuing,
-			"N" disables Tagged Queuing, and "X" accepts the
-			default based on the firmware version.  The first
-			character refers to Target Device 0, the second to
-			Target Device 1, and so on; if the sequence of "Y",
-			"N", and "X" characters does not cover all the Target
-			Devices, unspecified characters are assumed to be "X".
-
-  Note that explicitly requesting Tagged Queuing may lead to problems; this
-  facility is provided primarily to allow disabling Tagged Queuing on Target
-  Devices that do not implement it correctly.
-
-  The Error Recovery Strategy specification begins with "ER:" and allows for
-  explicitly specifying the Error Recovery action to be performed when
-  ResetCommand is called due to a SCSI Command failing to complete
-  successfully.  The following specification options are available:
-
-  ER:Default		Error Recovery will select between the Hard Reset and
-			Bus Device Reset options based on the recommendation
-			of the SCSI Subsystem.
-
-  ER:HardReset		Error Recovery will initiate a Host Adapter Hard Reset
-			which also causes a SCSI Bus Reset.
-
-  ER:BusDeviceReset	Error Recovery will send a Bus Device Reset message to
-			the individual Target Device causing the error.  If
-			Error Recovery is again initiated for this Target
-			Device and no SCSI Command to this Target Device has
-			completed successfully since the Bus Device Reset
-			message was sent, then a Hard Reset will be attempted.
-
-  ER:None		Error Recovery will be suppressed.  This option should
-			only be selected if a SCSI Bus Reset or Bus Device
-			Reset will cause the Target Device to fail completely
-			and unrecoverably.
-
-  ER:<Per-Target-Spec>	Error Recovery will be controlled individually for each
-			Target Device.  <Per-Target-Spec> is a sequence of "D",
-			"H", "B", and "N" characters.  "D" selects Default, "H"
-			selects Hard Reset, "B" selects Bus Device Reset, and
-			"N" selects None.  The first character refers to Target
-			Device 0, the second to Target Device 1, and so on; if
-			the sequence of "D", "H", "B", and "N" characters does
-			not cover all the possible Target Devices, unspecified
-			characters are assumed to be "D".
-
-  The Host Adapter Probing specification comprises the following strings:
-
-  NoProbe		No probing of any kind is to be performed, and hence
-			no BusLogic Host Adapters will be detected.
-
-  NoProbeISA		No probing of the standard ISA I/O Addresses will
-			be done, and hence only PCI MultiMaster and FlashPoint
-			Host Adapters will be detected.
-
-  NoProbePCI		No interrogation of PCI Configuration Space will be
-			made, and hence only ISA Multimaster Host Adapters
-			will be detected, as well as PCI Multimaster Host
-			Adapters that have their ISA Compatible I/O Port
-			set to "Primary" or "Alternate".
-
-  NoSortPCI		PCI MultiMaster Host Adapters will be enumerated in
-			the order provided by the PCI BIOS, ignoring any
-			setting of the AutoSCSI "Use Bus And Device # For PCI
-			Scanning Seq." option.
-
-  MultiMasterFirst	By default, if both FlashPoint and PCI MultiMaster
-			Host Adapters are present, this driver will probe for
-			FlashPoint Host Adapters first unless the BIOS primary
-			disk is controlled by the first PCI MultiMaster Host
-			Adapter, in which case MultiMaster Host Adapters will
-			be probed first.  This option forces MultiMaster Host
-			Adapters to be probed first.
-
-  FlashPointFirst	By default, if both FlashPoint and PCI MultiMaster
-			Host Adapters are present, this driver will probe for
-			FlashPoint Host Adapters first unless the BIOS primary
-			disk is controlled by the first PCI MultiMaster Host
-			Adapter, in which case MultiMaster Host Adapters will
-			be probed first.  This option forces FlashPoint Host
-			Adapters to be probed first.
-
-  Debug			Sets all the tracing bits in BusLogic_GlobalOptions.
-
-*/
-
-void BusLogic_Setup(char *Strings, int *Integers)
-{
-  BusLogic_CommandLineEntry_T *CommandLineEntry =
-    &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++];
-  int IntegerCount = Integers[0];
-  int TargetID, i;
-  CommandLineEntry->IO_Address = 0;
-  CommandLineEntry->TaggedQueueDepth = 0;
-  CommandLineEntry->BusSettleTime = 0;
-  CommandLineEntry->TaggedQueuingPermitted = 0;
-  CommandLineEntry->TaggedQueuingPermittedMask = 0;
-  CommandLineEntry->LocalOptions.All = 0;
-  memset(CommandLineEntry->ErrorRecoveryStrategy,
-	 BusLogic_ErrorRecovery_Default,
-	 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-  if (IntegerCount > 5)
-    BusLogic_Error("BusLogic: Unexpected Command Line Integers "
-		   "ignored\n", NULL);
-  if (IntegerCount >= 1)
-    {
-      BusLogic_IO_Address_T IO_Address = Integers[1];
-      if (IO_Address > 0)
-	{
-	  BusLogic_ProbeInfo_T *ProbeInfo;
-	  for (i = 0; ; i++)
-	    if (BusLogic_ISA_StandardAddresses[i] == 0)
-	      {
-		BusLogic_Error("BusLogic: Invalid Command Line Entry "
-			       "(illegal I/O Address 0x%X)\n",
-			       NULL, IO_Address);
-		return;
-	      }
-	    else if (i < BusLogic_ProbeInfoCount &&
-		     IO_Address == BusLogic_ProbeInfoList[i].IO_Address)
-	      {
-		BusLogic_Error("BusLogic: Invalid Command Line Entry "
-			       "(duplicate I/O Address 0x%X)\n",
-			       NULL, IO_Address);
-		return;
-	      }
-	    else if (IO_Address >= 0x400 ||
-		     IO_Address == BusLogic_ISA_StandardAddresses[i]) break;
-	  ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	  ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-	  ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-	}
-      CommandLineEntry->IO_Address = IO_Address;
-    }
-  if (IntegerCount >= 2)
-    {
-      unsigned short TaggedQueueDepth = Integers[2];
-      if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
-	{
-	  BusLogic_Error("BusLogic: Invalid Command Line Entry "
-			 "(illegal Tagged Queue Depth %d)\n",
-			 NULL, TaggedQueueDepth);
+  The BusLogic Driver Probing Options comprise the following:
+
+  IO:<integer>
+
+    The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI
+    MultiMaster Host Adapter.  If neither "IO:" nor "NoProbeISA" options are
+    specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses
+    will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134).  Multiple
+    "IO:" options may be specified to precisely determine the I/O Addresses to
+    be probed, but the probe order will always follow the standard list.
+
+  NoProbe
+
+    The "NoProbe" option disables all probing and therefore no BusLogic Host
+    Adapters will be detected.
+
+  NoProbeISA
+
+    The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O
+    Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters
+    will be detected.
+
+  NoProbePCI
+
+    The "NoProbePCI" options disables the interrogation of PCI Configuration
+    Space and therefore only ISA Multimaster Host Adapters will be detected, as
+    well as PCI Multimaster Host Adapters that have their ISA Compatible I/O
+    Port set to "Primary" or "Alternate".
+
+  NoSortPCI
+
+    The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be
+    enumerated in the order provided by the PCI BIOS, ignoring any setting of
+    the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
+
+  MultiMasterFirst
+
+    The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed
+    before FlashPoint Host Adapters.  By default, if both FlashPoint and PCI
+    MultiMaster Host Adapters are present, this driver will probe for
+    FlashPoint Host Adapters first unless the BIOS primary disk is controlled
+    by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host
+    Adapters will be probed first.
+
+  FlashPointFirst
+
+    The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed
+    before MultiMaster Host Adapters.
+
+  The BusLogic Driver Tagged Queuing Options allow for explicitly specifying
+  the Queue Depth and whether Tagged Queuing is permitted for each Target
+  Device (assuming that the Target Device supports Tagged Queuing).  The Queue
+  Depth is the number of SCSI Commands that are allowed to be concurrently
+  presented for execution (either to the Host Adapter or Target Device).  Note
+  that explicitly enabling Tagged Queuing may lead to problems; the option to
+  enable or disable Tagged Queuing is provided primarily to allow disabling
+  Tagged Queuing on Target Devices that do not implement it correctly.  The
+  following options are available:
+
+  QueueDepth:<integer>
+
+    The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
+    Target Devices that support Tagged Queuing, as well as the maximum Queue
+    Depth for devices that do not support Tagged Queuing.  If no Queue Depth
+    option is provided, the Queue Depth will be determined automatically based
+    on the Host Adapter's Total Queue Depth and the number, type, speed, and
+    capabilities of the detected Target Devices.  For Host Adapters that
+    require ISA Bounce Buffers, the Queue Depth is automatically set by default
+    to BusLogic_TaggedQueueDepthBB or BusLogic_UntaggedQueueDepthBB to avoid
+    excessive preallocation of DMA Bounce Buffer memory.  Target Devices that
+    do not support Tagged Queuing always have their Queue Depth set to
+    BusLogic_UntaggedQueueDepth or BusLogic_UntaggedQueueDepthBB, unless a
+    lower Queue Depth option is provided.  A Queue Depth of 1 automatically
+    disables Tagged Queuing.
+
+  QueueDepth:[<integer>,<integer>...]
+
+    The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth
+    individually for each Target Device.  If an <integer> is omitted, the
+    associated Target Device will have its Queue Depth selected automatically.
+
+  TaggedQueuing:Default
+
+    The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing
+    based on the firmware version of the BusLogic Host Adapter and based on
+    whether the Queue Depth allows queuing multiple commands.
+
+  TaggedQueuing:Enable
+
+    The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for
+    all Target Devices on this Host Adapter, overriding any limitation that
+    would otherwise be imposed based on the Host Adapter firmware version.
+
+  TaggedQueuing:Disable
+
+    The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing
+    for all Target Devices on this Host Adapter.
+
+  TaggedQueuing:<Target-Spec>
+
+    The "TaggedQueuing:<Target-Spec>" or "TQ:<Target-Spec>" option controls
+    Tagged Queuing individually for each Target Device.  <Target-Spec> is a
+    sequence of "Y", "N", and "X" characters.  "Y" enables Tagged Queuing, "N"
+    disables Tagged Queuing, and "X" accepts the default based on the firmware
+    version.  The first character refers to Target Device 0, the second to
+    Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters
+    does not cover all the Target Devices, unspecified characters are assumed
+    to be "X".
+
+  The BusLogic Driver Error Recovery Option allows for explicitly specifying
+  the Error Recovery action to be performed when BusLogic_ResetCommand is
+  called due to a SCSI Command failing to complete successfully.  The following
+  options are available:
+
+  ErrorRecovery:Default
+
+    The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard
+    Reset and Bus Device Reset options based on the recommendation of the SCSI
+    Subsystem.
+
+  ErrorRecovery:HardReset
+
+    The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host
+    Adapter Hard Reset which also causes a SCSI Bus Reset.
+
+  ErrorRecovery:BusDeviceReset
+
+    The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send
+    a Bus Device Reset message to the individual Target Device causing the
+    error.  If Error Recovery is again initiated for this Target Device and no
+    SCSI Command to this Target Device has completed successfully since the Bus
+    Device Reset message was sent, then a Hard Reset will be attempted.
+
+  ErrorRecovery:None
+
+    The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery.
+    This option should only be selected if a SCSI Bus Reset or Bus Device Reset
+    will cause the Target Device or a critical operation to suffer a complete
+    and unrecoverable failure.
+
+  ErrorRecovery:<Target-Spec>
+
+    The "ErrorRecovery:<Target-Spec>" or "ER:<Target-Spec>" option controls
+    Error Recovery individually for each Target Device.  <Target-Spec> is a
+    sequence of "D", "H", "B", and "N" characters.  "D" selects Default, "H"
+    selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None.
+    The first character refers to Target Device 0, the second to Target Device
+    1, and so on; if the sequence of "D", "H", "B", and "N" characters does not
+    cover all the possible Target Devices, unspecified characters are assumed
+    to be "D".
+
+  The BusLogic Driver Miscellaneous Options comprise the following:
+
+  BusSettleTime:<seconds>
+
+    The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in
+    seconds.  The Bus Settle Time is the amount of time to wait between a Host
+    Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI
+    Commands.  If unspecified, it defaults to BusLogic_DefaultBusSettleTime.
+
+  InhibitTargetInquiry
+
+    The "InhibitTargetInquiry" option inhibits the execution of an Inquire
+    Target Devices or Inquire Installed Devices command on MultiMaster Host
+    Adapters.  This may be necessary with some older Target Devices that do not
+    respond correctly when Logical Units above 0 are addressed.
+
+  The BusLogic Driver Debugging Options comprise the following:
+
+  TraceProbe
+
+    The "TraceProbe" option enables tracing of Host Adapter Probing.
+
+  TraceHardwareReset
+
+    The "TraceHardwareReset" option enables tracing of Host Adapter Hardware
+    Reset.
+
+  TraceConfiguration
+
+    The "TraceConfiguration" option enables tracing of Host Adapter
+    Configuration.
+
+  TraceErrors
+
+    The "TraceErrors" option enables tracing of SCSI Commands that return an
+    error from the Target Device.  The CDB and Sense Data will be printed for
+    each SCSI Command that fails.
+
+  Debug
+
+    The "Debug" option enables all debugging options.
+
+  The following examples demonstrate setting the Queue Depth for Target Devices
+  1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target
+  Devices on the second host adapter to 31, and the Bus Settle Time on the
+  second host adapter to 30 seconds.
+
+  Linux Kernel Command Line:
+
+    linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30
+
+  LILO Linux Boot Loader (in /etc/lilo.conf):
+
+    append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"
+
+  INSMOD Loadable Kernel Module Installation Facility:
+
+    insmod BusLogic.o \
+	'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"'
+
+  NOTE: Module Utilities 2.1.71 or later is required for correct parsing
+	of driver options containing commas.
+
+*/
+
+static void BusLogic_ParseDriverOptions(char *OptionsString)
+{
+  while (true)
+    {
+      BusLogic_DriverOptions_T *DriverOptions =
+	&BusLogic_DriverOptions[BusLogic_DriverOptionsCount++];
+      int TargetID;
+      memset(DriverOptions, 0, sizeof(BusLogic_DriverOptions_T));
+      for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+	DriverOptions->ErrorRecoveryStrategy[TargetID] =
+	  BusLogic_ErrorRecovery_Default;
+      while (*OptionsString != '\0' && *OptionsString != ';')
+	{
+	  /* Probing Options. */
+	  if (BusLogic_ParseKeyword(&OptionsString, "IO:"))
+	    {
+	      BusLogic_IO_Address_T IO_Address =
+		simple_strtoul(OptionsString, &OptionsString, 0);
+	      BusLogic_ProbeOptions.LimitedProbeISA = true;
+	      switch (IO_Address)
+		{
+		case 0x330:
+		  BusLogic_ProbeOptions.Probe330 = true;
+		  break;
+		case 0x334:
+		  BusLogic_ProbeOptions.Probe334 = true;
+		  break;
+		case 0x230:
+		  BusLogic_ProbeOptions.Probe230 = true;
+		  break;
+		case 0x234:
+		  BusLogic_ProbeOptions.Probe234 = true;
+		  break;
+		case 0x130:
+		  BusLogic_ProbeOptions.Probe130 = true;
+		  break;
+		case 0x134:
+		  BusLogic_ProbeOptions.Probe134 = true;
+		  break;
+		default:
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(illegal I/O Address 0x%X)\n",
+				 NULL, IO_Address);
+		  return;
+		}
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA"))
+	    BusLogic_ProbeOptions.NoProbeISA = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI"))
+	    BusLogic_ProbeOptions.NoProbePCI = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe"))
+	    BusLogic_ProbeOptions.NoProbe = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI"))
+	    BusLogic_ProbeOptions.NoSortPCI = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst"))
+	    BusLogic_ProbeOptions.MultiMasterFirst = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst"))
+	    BusLogic_ProbeOptions.FlashPointFirst = true;
+	  /* Tagged Queuing Options. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") ||
+		   BusLogic_ParseKeyword(&OptionsString, "QD:["))
+	    {
+	      for (TargetID = 0;
+		   TargetID < BusLogic_MaxTargetDevices;
+		   TargetID++)
+		{
+		  unsigned short QueueDepth =
+		    simple_strtoul(OptionsString, &OptionsString, 0);
+		  if (QueueDepth > BusLogic_MaxTaggedQueueDepth)
+		    {
+		      BusLogic_Error("BusLogic: Invalid Driver Options "
+				     "(illegal Queue Depth %d)\n",
+				     NULL, QueueDepth);
+		      return;
+		    }
+		  DriverOptions->QueueDepth[TargetID] = QueueDepth;
+		  if (*OptionsString == ',')
+		    OptionsString++;
+		  else if (*OptionsString == ']')
+		    break;
+		  else
+		    {
+		      BusLogic_Error("BusLogic: Invalid Driver Options "
+				     "(',' or ']' expected at '%s')\n",
+				     NULL, OptionsString);
+		      return;
+		    }
+		}
+	      if (*OptionsString != ']')
+		{
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(']' expected at '%s')\n",
+				 NULL, OptionsString);
+		  return;
+		}
+	      else OptionsString++;
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "QD:"))
+	    {
+	      unsigned short QueueDepth =
+		simple_strtoul(OptionsString, &OptionsString, 0);
+	      if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth)
+		{
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(illegal Queue Depth %d)\n",
+				 NULL, QueueDepth);
+		  return;
+		}
+	      DriverOptions->CommonQueueDepth = QueueDepth;
+	      for (TargetID = 0;
+		   TargetID < BusLogic_MaxTargetDevices;
+		   TargetID++)
+		DriverOptions->QueueDepth[TargetID] = QueueDepth;
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "TQ:"))
+	    {
+	      if (BusLogic_ParseKeyword(&OptionsString, "Default"))
+		{
+		  DriverOptions->TaggedQueuingPermitted = 0x0000;
+		  DriverOptions->TaggedQueuingPermittedMask = 0x0000;
+		}
+	      else if (BusLogic_ParseKeyword(&OptionsString, "Enable"))
+		{
+		  DriverOptions->TaggedQueuingPermitted = 0xFFFF;
+		  DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+		}
+	      else if (BusLogic_ParseKeyword(&OptionsString, "Disable"))
+		{
+		  DriverOptions->TaggedQueuingPermitted = 0x0000;
+		  DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+		}
+	      else
+		{
+		  unsigned short TargetBit;
+		  for (TargetID = 0, TargetBit = 1;
+		       TargetID < BusLogic_MaxTargetDevices;
+		       TargetID++, TargetBit <<= 1)
+		    switch (*OptionsString++)
+		      {
+		      case 'Y':
+			DriverOptions->TaggedQueuingPermitted |= TargetBit;
+			DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+			break;
+		      case 'N':
+			DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+			DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+			break;
+		      case 'X':
+			break;
+		      default:
+			OptionsString--;
+			TargetID = BusLogic_MaxTargetDevices;
+			break;
+		      }
+		}
+	    }
+	  /* Error Recovery Option. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "ErrorRecovery:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "ER:"))
+	    {
+	      if (BusLogic_ParseKeyword(&OptionsString, "Default"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_Default;
+	      else if (BusLogic_ParseKeyword(&OptionsString, "HardReset"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_HardReset;
+	      else if (BusLogic_ParseKeyword(&OptionsString, "BusDeviceReset"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_BusDeviceReset;
+	      else if (BusLogic_ParseKeyword(&OptionsString, "None"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_None;
+	      else
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  switch (*OptionsString++)
+		    {
+		    case 'D':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_Default;
+		      break;
+		    case 'H':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_HardReset;
+		      break;
+		    case 'B':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_BusDeviceReset;
+		      break;
+		    case 'N':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_None;
+		      break;
+		    default:
+		      OptionsString--;
+		      TargetID = BusLogic_MaxTargetDevices;
+		      break;
+		    }
+	    }
+	  /* Miscellaneous Options. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "BST:"))
+	    {
+	      unsigned short BusSettleTime =
+		simple_strtoul(OptionsString, &OptionsString, 0);
+	      if (BusSettleTime > 5 * 60)
+		{
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(illegal Bus Settle Time %d)\n",
+				 NULL, BusSettleTime);
+		  return;
+		}
+	      DriverOptions->BusSettleTime = BusSettleTime;
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString,
+					 "InhibitTargetInquiry"))
+	    DriverOptions->LocalOptions.InhibitTargetInquiry = true;
+	  /* Debugging Options. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe"))
+	      BusLogic_GlobalOptions.TraceProbe = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset"))
+	      BusLogic_GlobalOptions.TraceHardwareReset = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration"))
+	      BusLogic_GlobalOptions.TraceConfiguration = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors"))
+	      BusLogic_GlobalOptions.TraceErrors = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "Debug"))
+	    {
+	      BusLogic_GlobalOptions.TraceProbe = true;
+	      BusLogic_GlobalOptions.TraceHardwareReset = true;
+	      BusLogic_GlobalOptions.TraceConfiguration = true;
+	      BusLogic_GlobalOptions.TraceErrors = true;
+	    }
+	  if (*OptionsString == ',')
+	    OptionsString++;
+	  else if (*OptionsString != ';' && *OptionsString != '\0')
+	    {
+	      BusLogic_Error("BusLogic: Unexpected Driver Option '%s' "
+			     "ignored\n", NULL, OptionsString);
+	      *OptionsString = '\0';
+	    }
+	}
+      if (!(BusLogic_DriverOptionsCount == 0 ||
+	    BusLogic_ProbeInfoCount == 0 ||
+	    BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount))
+	{
+	  BusLogic_Error("BusLogic: Invalid Driver Options "
+			 "(all or no I/O Addresses must be specified)\n", NULL);
 	  return;
 	}
-      CommandLineEntry->TaggedQueueDepth = TaggedQueueDepth;
+      /*
+	Tagged Queuing is disabled when the Queue Depth is 1 since queuing
+	multiple commands is not possible.
+      */
+      for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+	if (DriverOptions->QueueDepth[TargetID] == 1)
+	  {
+	    unsigned short TargetBit = 1 << TargetID;
+	    DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+	    DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+	  }
+      if (*OptionsString == ';') OptionsString++;
+      if (*OptionsString == '\0') return;
     }
-  if (IntegerCount >= 3)
-    CommandLineEntry->BusSettleTime = Integers[3];
-  if (IntegerCount >= 4)
-    CommandLineEntry->LocalOptions.All = Integers[4];
-  if (IntegerCount >= 5)
-    BusLogic_GlobalOptions.All |= Integers[5];
-  if (!(BusLogic_CommandLineEntryCount == 0 ||
-	BusLogic_ProbeInfoCount == 0 ||
-	BusLogic_CommandLineEntryCount == BusLogic_ProbeInfoCount))
+}
+
+
+/*
+  BusLogic_Setup handles processing of Kernel Command Line Arguments.
+*/
+
+void BusLogic_Setup(char *CommandLineString, int *CommandLineIntegers)
+{
+  if (CommandLineIntegers[0] != 0)
     {
-      BusLogic_Error("BusLogic: Invalid Command Line Entry "
-		     "(all or no I/O Addresses must be specified)\n", NULL);
+      BusLogic_Error("BusLogic: Obsolete Command Line Entry "
+		     "Format Ignored\n", NULL);
       return;
     }
-  if (Strings == NULL) return;
-  while (*Strings != '\0')
-    if (strncmp(Strings, "TQ:", 3) == 0)
-      {
-	Strings += 3;
-	if (strncmp(Strings, "Default", 7) == 0)
-	  Strings += 7;
-	else if (strncmp(Strings, "Enable", 6) == 0)
-	  {
-	    Strings += 6;
-	    CommandLineEntry->TaggedQueuingPermitted = 0xFFFF;
-	    CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
-	  }
-	else if (strncmp(Strings, "Disable", 7) == 0)
-	  {
-	    Strings += 7;
-	    CommandLineEntry->TaggedQueuingPermitted = 0x0000;
-	    CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
-	  }
-	else
-	  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
-	    switch (*Strings++)
-	      {
-	      case 'Y':
-		CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID;
-		CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
-		break;
-	      case 'N':
-		CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
-		break;
-	      case 'X':
-		break;
-	      default:
-		Strings--;
-		TargetID = BusLogic_MaxTargetDevices;
-		break;
-	      }
-      }
-    else if (strncmp(Strings, "ER:", 3) == 0)
-      {
-	Strings += 3;
-	if (strncmp(Strings, "Default", 7) == 0)
-	  Strings += 7;
-	else if (strncmp(Strings, "HardReset", 9) == 0)
-	  {
-	    Strings += 9;
-	    memset(CommandLineEntry->ErrorRecoveryStrategy,
-		   BusLogic_ErrorRecovery_HardReset,
-		   sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	  }
-	else if (strncmp(Strings, "BusDeviceReset", 14) == 0)
-	  {
-	    Strings += 14;
-	    memset(CommandLineEntry->ErrorRecoveryStrategy,
-		   BusLogic_ErrorRecovery_BusDeviceReset,
-		   sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	  }
-	else if (strncmp(Strings, "None", 4) == 0)
-	  {
-	    Strings += 4;
-	    memset(CommandLineEntry->ErrorRecoveryStrategy,
-		   BusLogic_ErrorRecovery_None,
-		   sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	  }
-	else
-	  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
-	    switch (*Strings++)
-	      {
-	      case 'D':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_Default;
-		break;
-	      case 'H':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_HardReset;
-		break;
-	      case 'B':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_BusDeviceReset;
-		break;
-	      case 'N':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_None;
-		break;
-	      default:
-		Strings--;
-		TargetID = BusLogic_MaxTargetDevices;
-		break;
-	      }
-      }
-    else if (strcmp(Strings, "NoProbe") == 0 ||
-	     strcmp(Strings, "noprobe") == 0)
-      {
-	Strings += 7;
-	BusLogic_ProbeOptions.Bits.NoProbe = true;
-      }
-    else if (strncmp(Strings, "NoProbeISA", 10) == 0)
-      {
-	Strings += 10;
-	BusLogic_ProbeOptions.Bits.NoProbeISA = true;
-      }
-    else if (strncmp(Strings, "NoProbePCI", 10) == 0)
-      {
-	Strings += 10;
-	BusLogic_ProbeOptions.Bits.NoProbePCI = true;
-      }
-    else if (strncmp(Strings, "NoSortPCI", 9) == 0)
-      {
-	Strings += 9;
-	BusLogic_ProbeOptions.Bits.NoSortPCI = true;
-      }
-    else if (strncmp(Strings, "MultiMasterFirst", 16) == 0)
-      {
-	Strings += 16;
-	BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst = true;
-      }
-    else if (strncmp(Strings, "FlashPointFirst", 15) == 0)
-      {
-	Strings += 15;
-	BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst = true;
-      }
-    else if (strncmp(Strings, "Debug", 5) == 0)
-      {
-	Strings += 5;
-	BusLogic_GlobalOptions.Bits.TraceProbe = true;
-	BusLogic_GlobalOptions.Bits.TraceHardReset = true;
-	BusLogic_GlobalOptions.Bits.TraceConfiguration = true;
-	BusLogic_GlobalOptions.Bits.TraceErrors = true;
-      }
-    else if (*Strings == ',')
-      Strings++;
-    else
-      {
-	BusLogic_Error("BusLogic: Unexpected Command Line String '%s' "
-		       "ignored\n", NULL, Strings);
-	break;
-      }
+  if (CommandLineString == NULL || *CommandLineString == '\0') return;
+  BusLogic_ParseDriverOptions(CommandLineString);
 }
 
 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v2.0.33/linux/drivers/scsi/BusLogic.h	Wed Oct 15 15:24:02 1997
+++ linux/drivers/scsi/BusLogic.h	Wed Jun  3 15:17:48 1998
@@ -2,12 +2,11 @@
 
   Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
 
-  Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
-  Free Software Foundation, provided that none of the source code or runtime
-  copyright notices are removed or modified.
+  Free Software Foundation.
 
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
@@ -37,7 +36,9 @@
 
 typedef kdev_t KernelDevice_T;
 typedef struct proc_dir_entry PROC_DirectoryEntry_T;
+typedef unsigned long ProcessorFlags_T;
 typedef struct pt_regs Registers_T;
+typedef struct partition PartitionTable_T;
 typedef Scsi_Host_Template SCSI_Host_Template_T;
 typedef struct Scsi_Host SCSI_Host_T;
 typedef struct scsi_device SCSI_Device_T;
@@ -66,28 +67,19 @@
   Define the BusLogic SCSI Host Template structure.
 */
 
-#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	     */
+#define BUSLOGIC							       \
+  { proc_dir:       &BusLogic_ProcDirectoryEntry, /* ProcFS Directory Entry */ \
+    proc_info:      BusLogic_ProcDirectoryInfo,	  /* ProcFS 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 Initial Value  */ \
+    use_clustering: ENABLE_CLUSTERING }		  /* Enable Clustering	    */
 
 
 /*
@@ -98,6 +90,24 @@
 
 
 /*
+  FlashPoint support is only available for the Intel x86 Architecture with
+  CONFIG_PCI set.
+*/
+
+#ifndef __i386__
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#endif
+
+#ifndef CONFIG_PCI
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#define BusLogic_InitializeProbeInfoListISA \
+  BusLogic_InitializeProbeInfoList
+#endif
+
+
+/*
   Define the maximum number of BusLogic Host Adapters supported by this driver.
 */
 
@@ -121,16 +131,17 @@
 
 
 /*
-  Define the maximum, preferred, and default Queue Depth to allow for Target
-  Devices depending on whether or not they support Tagged Queuing and whether
-  or not ISA Bounce Buffers are required.
+  Define the maximum, maximum automatic, minimum automatic, and default Queue
+  Depth to allow for Target Devices depending on whether or not they support
+  Tagged Queuing and whether or not ISA Bounce Buffers are required.
 */
 
-#define BusLogic_MaxTaggedQueueDepth		63
-#define BusLogic_PreferredTaggedQueueDepth	28
-#define BusLogic_TaggedQueueDepthBounceBuffers	2
-#define BusLogic_TaggedQueueDepthAutomatic	0
+#define BusLogic_MaxTaggedQueueDepth		64
+#define BusLogic_MaxAutomaticTaggedQueueDepth	28
+#define BusLogic_MinAutomaticTaggedQueueDepth	7
+#define BusLogic_TaggedQueueDepthBB		3
 #define BusLogic_UntaggedQueueDepth		3
+#define BusLogic_UntaggedQueueDepthBB		2
 
 
 /*
@@ -144,11 +155,29 @@
 
 
 /*
+  Define the maximum number of Mailboxes that should be used for MultiMaster
+  Host Adapters.  This number is chosen to be larger than the maximum Host
+  Adapter Queue Depth and small enough so that the Host Adapter structure
+  does not cross an allocation block size boundary.
+*/
+
+#define BusLogic_MaxMailboxes			211
+
+
+/*
+  Define the number of CCBs that should be allocated as a group to optimize
+  Kernel memory allocation.
+*/
+
+#define BusLogic_CCB_AllocationGroupSize	7
+
+
+/*
   Define the Host Adapter Line and Message Buffer Sizes.
 */
 
 #define BusLogic_LineBufferSize			100
-#define BusLogic_MessageBufferSize		9900
+#define BusLogic_MessageBufferSize		9700
 
 
 /*
@@ -167,7 +196,27 @@
 
 static char
   *BusLogic_MessageLevelMap[] =
-    { KERN_INFO, KERN_INFO, KERN_NOTICE, KERN_WARNING, KERN_ERR };
+    { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR };
+
+
+/*
+  Define Driver Message macros.
+*/
+
+#define BusLogic_Announce(Format, Arguments...) \
+  BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments)
+
+#define BusLogic_Info(Format, Arguments...) \
+  BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments)
+
+#define BusLogic_Notice(Format, Arguments...) \
+  BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments)
+
+#define BusLogic_Warning(Format, Arguments...) \
+  BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments)
+
+#define BusLogic_Error(Format, Arguments...) \
+  BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments)
 
 
 /*
@@ -187,11 +236,34 @@
 #define BusLogic_FlashPointAddressCount		256
 
 static int
-  BusLogic_HostAdapter_AddressCount[3] =
+  BusLogic_HostAdapterAddressCount[3] =
     { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount };
 
 
 /*
+  Define macros for testing the Host Adapter Type.
+*/
+
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+  (HostAdapter->HostAdapterType == BusLogic_MultiMaster)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+  (HostAdapter->HostAdapterType == BusLogic_FlashPoint)
+
+#else
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+  (true)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+  (false)
+
+#endif
+
+
+/*
   Define the possible Host Adapter Bus Types.
 */
 
@@ -204,6 +276,7 @@
   BusLogic_VESA_Bus =				4,
   BusLogic_MCA_Bus =				5
 }
+__attribute__ ((packed))
 BusLogic_HostAdapterBusType_T;
 
 static char
@@ -257,6 +330,13 @@
 
 
 /*
+  Define a 32 bit Base Address data type.
+*/
+
+typedef unsigned int BusLogic_Base_Address_T;
+
+
+/*
   Define a 32 bit Bus Address data type.
 */
 
@@ -288,11 +368,10 @@
 
 typedef struct BusLogic_ProbeInfo
 {
+  BusLogic_HostAdapterType_T HostAdapterType;
+  BusLogic_HostAdapterBusType_T HostAdapterBusType;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
-  BusLogic_HostAdapterType_T HostAdapterType:2;
-  BusLogic_HostAdapterBusType_T HostAdapterBusType:3;
-  unsigned char :3;
   unsigned char Bus;
   unsigned char Device;
   unsigned char IRQ_Channel;
@@ -301,35 +380,24 @@
 
 
 /*
-  BusLogic_ISA_StandardAddresses is the list of standard ISA I/O Addresses at
-  which BusLogic MultiMaster Host Adapters may potentially be found.  The first
-  I/O Address 0x330 is known as the "Primary" I/O Address.  A Host Adapter
-  configured to use the Primary I/O Address will always be the preferred boot
-  device.
-*/
-
-#define BusLogic_ISA_StandardAddressesCount	6
-
-static BusLogic_IO_Address_T
-  BusLogic_ISA_StandardAddresses[BusLogic_ISA_StandardAddressesCount] =
-    { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134 };
-
-
-/*
   Define the Probe Options.
 */
 
-typedef union BusLogic_ProbeOptions
+typedef struct BusLogic_ProbeOptions
 {
-  unsigned short All;
-  struct {
-    boolean NoProbe:1;					/* Bit 0 */
-    boolean NoProbeISA:1;				/* Bit 1 */
-    boolean NoProbePCI:1;				/* Bit 2 */
-    boolean NoSortPCI:1;				/* Bit 3 */
-    boolean ProbeMultiMasterFirst:1;			/* Bit 4 */
-    boolean ProbeFlashPointFirst:1;			/* Bit 5 */
-  } Bits;
+  boolean NoProbe:1;					/* Bit 0 */
+  boolean NoProbeISA:1;					/* Bit 1 */
+  boolean NoProbePCI:1;					/* Bit 2 */
+  boolean NoSortPCI:1;					/* Bit 3 */
+  boolean MultiMasterFirst:1;				/* Bit 4 */
+  boolean FlashPointFirst:1;				/* Bit 5 */
+  boolean LimitedProbeISA:1;				/* Bit 6 */
+  boolean Probe330:1;					/* Bit 7 */
+  boolean Probe334:1;					/* Bit 8 */
+  boolean Probe230:1;					/* Bit 9 */
+  boolean Probe234:1;					/* Bit 10 */
+  boolean Probe130:1;					/* Bit 11 */
+  boolean Probe134:1;					/* Bit 12 */
 }
 BusLogic_ProbeOptions_T;
 
@@ -338,15 +406,12 @@
   Define the Global Options.
 */
 
-typedef union BusLogic_GlobalOptions
+typedef struct BusLogic_GlobalOptions
 {
-  unsigned short All;
-  struct {
-    boolean TraceProbe:1;				/* Bit 0 */
-    boolean TraceHardReset:1;				/* Bit 1 */
-    boolean TraceConfiguration:1;			/* Bit 2 */
-    boolean TraceErrors:1;				/* Bit 3 */
-  } Bits;
+  boolean TraceProbe:1;					/* Bit 0 */
+  boolean TraceHardwareReset:1;				/* Bit 1 */
+  boolean TraceConfiguration:1;				/* Bit 2 */
+  boolean TraceErrors:1;				/* Bit 3 */
 }
 BusLogic_GlobalOptions_T;
 
@@ -355,13 +420,9 @@
   Define the Local Options.
 */
 
-typedef union BusLogic_LocalOptions
+typedef struct BusLogic_LocalOptions
 {
-  unsigned short All;
-  struct {
-    boolean InhibitTargetInquiry:1;			/* Bit 0 */
-    boolean InhibitInterruptTest:1;			/* Bit 1 */
-  } Bits;
+  boolean InhibitTargetInquiry:1;			/* Bit 0 */
 }
 BusLogic_LocalOptions_T;
 
@@ -619,10 +680,13 @@
   unsigned char Signature;				/* Byte 17 */
   unsigned char CharacterD;				/* Byte 18 */
   unsigned char HostBusType;				/* Byte 19 */
-  unsigned char :8;					/* Byte 20 */
-  unsigned char :8;					/* Byte 21 */
+  unsigned char WideTransfersPermittedID0to7;		/* Byte 20 */
+  unsigned char WideTransfersActiveID0to7;		/* Byte 21 */
   BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */
   unsigned char DisconnectPermittedID8to15;		/* Byte 30 */
+  unsigned char :8;					/* Byte 31 */
+  unsigned char WideTransfersPermittedID8to15;		/* Byte 32 */
+  unsigned char WideTransfersActiveID8to15;		/* Byte 33 */
 }
 BusLogic_SetupInformation_T;
 
@@ -903,16 +967,6 @@
 
 
 /*
-  Define the Lock data structure.  Until a true symmetric multiprocessing
-  kernel with fine grained locking is available, acquiring the lock is
-  implemented as saving the processor flags and disabling interrupts, and
-  releasing the lock restores the saved processor flags.
-*/
-
-typedef unsigned long BusLogic_Lock_T;
-
-
-/*
   Define the Outgoing Mailbox Action Codes.
 */
 
@@ -1064,6 +1118,21 @@
 
 
 /*
+  Define the Driver CCB Status Codes.
+*/
+
+typedef enum
+{
+  BusLogic_CCB_Free =				0,
+  BusLogic_CCB_Active =				1,
+  BusLogic_CCB_Completed =			2,
+  BusLogic_CCB_Reset =				3
+}
+__attribute__ ((packed))
+BusLogic_CCB_Status_T;
+
+
+/*
   Define the 32 Bit Mode Command Control Block (CCB) structure.  The first 40
   bytes are defined by and common to both the MultiMaster Firmware and the
   FlashPoint SCCB Manager.  The next 60 bytes are defined by the FlashPoint
@@ -1113,27 +1182,26 @@
     FlashPoint SCCB Manager Defined Portion.
   */
   void (*CallbackFunction)(struct BusLogic_CCB *);	/* Bytes 40-43 */
-  BusLogic_IO_Address_T BaseAddress;			/* Bytes 44-47 */
+  BusLogic_Base_Address_T BaseAddress;			/* Bytes 44-47 */
   BusLogic_CompletionCode_T CompletionCode;		/* Byte 48 */
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
   unsigned char :8;					/* Byte 49 */
   unsigned short OS_Flags;				/* Bytes 50-51 */
   unsigned char Private[48];				/* Bytes 52-99 */
+#endif
   /*
     BusLogic Linux Driver Defined Portion.
   */
-  struct BusLogic_HostAdapter *HostAdapter;
-  SCSI_Command_T *Command;
-  enum { BusLogic_CCB_Free =	    0,
-	 BusLogic_CCB_Active =	    1,
-	 BusLogic_CCB_Completed =   2,
-	 BusLogic_CCB_Reset =	    3 } Status;
+  boolean AllocationGroupHead;
+  BusLogic_CCB_Status_T Status;
   unsigned long SerialNumber;
+  SCSI_Command_T *Command;
+  struct BusLogic_HostAdapter *HostAdapter;
   struct BusLogic_CCB *Next;
   struct BusLogic_CCB *NextAll;
   BusLogic_ScatterGatherSegment_T
     ScatterGatherList[BusLogic_ScatterGatherLimit];
 }
-__attribute__ ((packed))
 BusLogic_CCB_T;
 
 
@@ -1166,32 +1234,49 @@
 
 
 /*
-  Define the Linux BusLogic Driver Command Line Entry structure.
+  Define the BusLogic Driver Options structure.
 */
 
-typedef struct BusLogic_CommandLineEntry
+typedef struct BusLogic_DriverOptions
 {
-  BusLogic_IO_Address_T IO_Address;
-  unsigned short TaggedQueueDepth;
-  unsigned short BusSettleTime;
   unsigned short TaggedQueuingPermitted;
   unsigned short TaggedQueuingPermittedMask;
+  unsigned short BusSettleTime;
   BusLogic_LocalOptions_T LocalOptions;
+  unsigned char CommonQueueDepth;
+  unsigned char QueueDepth[BusLogic_MaxTargetDevices];
   BusLogic_ErrorRecoveryStrategy_T
     ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
 }
-BusLogic_CommandLineEntry_T;
+BusLogic_DriverOptions_T;
+
+
+/*
+  Define the Host Adapter Target Flags structure.
+*/
+
+typedef struct BusLogic_TargetFlags
+{
+  boolean TargetExists:1;
+  boolean TaggedQueuingSupported:1;
+  boolean WideTransfersSupported:1;
+  boolean TaggedQueuingActive:1;
+  boolean WideTransfersActive:1;
+  boolean CommandSuccessfulFlag:1;
+  boolean TargetInfoReported:1;
+}
+BusLogic_TargetFlags_T;
 
 
 /*
-  Define the Host Adapter Target Device Statistics structure.
+  Define the Host Adapter Target Statistics structure.
 */
 
 #define BusLogic_SizeBuckets			10
 
 typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets];
 
-typedef struct BusLogic_TargetDeviceStatistics
+typedef struct BusLogic_TargetStatistics
 {
   unsigned int CommandsAttempted;
   unsigned int CommandsCompleted;
@@ -1211,7 +1296,7 @@
   unsigned short HostAdapterResetsAttempted;
   unsigned short HostAdapterResetsCompleted;
 }
-BusLogic_TargetDeviceStatistics_T;
+BusLogic_TargetStatistics_T;
 
 
 /*
@@ -1230,7 +1315,7 @@
 
 typedef struct FlashPoint_Info
 {
-  BusLogic_IO_Address_T BaseAddress;			/* Bytes 0-3 */
+  BusLogic_Base_Address_T BaseAddress;			/* Bytes 0-3 */
   boolean Present;					/* Byte 4 */
   unsigned char IRQ_Channel;				/* Byte 5 */
   unsigned char SCSI_ID;				/* Byte 6 */
@@ -1265,12 +1350,14 @@
 
 
 /*
-  Define the Linux BusLogic Driver Host Adapter structure.
+  Define the BusLogic Driver Host Adapter structure.
 */
 
 typedef struct BusLogic_HostAdapter
 {
   SCSI_Host_T *SCSI_Host;
+  BusLogic_HostAdapterType_T HostAdapterType;
+  BusLogic_HostAdapterBusType_T HostAdapterBusType;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
   unsigned short AddressCount;
@@ -1278,19 +1365,16 @@
   unsigned char ModelName[9];
   unsigned char FirmwareVersion[6];
   unsigned char FullModelName[18];
-  unsigned char InterruptLabel[68];
+  unsigned char Bus;
+  unsigned char Device;
   unsigned char IRQ_Channel;
   unsigned char DMA_Channel;
   unsigned char SCSI_ID;
-  unsigned char Bus;
-  unsigned char Device;
-  BusLogic_HostAdapterType_T HostAdapterType;
-  BusLogic_HostAdapterBusType_T HostAdapterBusType:3;
   boolean IRQ_ChannelAcquired:1;
   boolean DMA_ChannelAcquired:1;
   boolean ExtendedTranslationEnabled:1;
   boolean ParityCheckingEnabled:1;
-  boolean BusResetEnabled;
+  boolean BusResetEnabled:1;
   boolean LevelSensitiveInterrupt:1;
   boolean HostWideSCSI:1;
   boolean HostDifferentialSCSI:1;
@@ -1304,9 +1388,11 @@
   boolean StrictRoundRobinModeSupport:1;
   boolean SCAM_Enabled:1;
   boolean SCAM_Level2:1;
-  boolean HostAdapterInitialized;
-  boolean HostAdapterResetRequested:1;
-  volatile boolean HostAdapterCommandCompleted:1;
+  boolean HostAdapterInitialized:1;
+  boolean HostAdapterExternalReset:1;
+  boolean HostAdapterInternalError:1;
+  boolean ProcessCompletedCCBsActive;
+  volatile boolean HostAdapterCommandCompleted;
   unsigned short HostAdapterScatterGatherLimit;
   unsigned short DriverScatterGatherLimit;
   unsigned short MaxTargetDevices;
@@ -1317,8 +1403,8 @@
   unsigned short AllocatedCCBs;
   unsigned short DriverQueueDepth;
   unsigned short HostAdapterQueueDepth;
-  unsigned short TaggedQueueDepth;
   unsigned short UntaggedQueueDepth;
+  unsigned short CommonQueueDepth;
   unsigned short BusSettleTime;
   unsigned short SynchronousPermitted;
   unsigned short FastPermitted;
@@ -1327,26 +1413,25 @@
   unsigned short DisconnectPermitted;
   unsigned short TaggedQueuingPermitted;
   unsigned short ExternalHostAdapterResets;
-  BusLogic_LocalOptions_T LocalOptions;
+  unsigned short HostAdapterInternalErrors;
+  unsigned short TargetDeviceCount;
+  unsigned short MessageBufferLength;
   BusLogic_BusAddress_T BIOS_Address;
-  BusLogic_InstalledDevices_T InstalledDevices;
-  BusLogic_SynchronousValues_T SynchronousValues;
-  BusLogic_SynchronousPeriod_T SynchronousPeriod;
-  BusLogic_CommandLineEntry_T *CommandLineEntry;
-  FlashPoint_Info_T *FlashPointInfo;
+  BusLogic_DriverOptions_T *DriverOptions;
+  FlashPoint_Info_T FlashPointInfo;
   FlashPoint_CardHandle_T CardHandle;
   struct BusLogic_HostAdapter *Next;
-  char *MessageBuffer;
-  int MessageBufferLength;
   BusLogic_CCB_T *All_CCBs;
   BusLogic_CCB_T *Free_CCBs;
+  BusLogic_CCB_T *FirstCompletedCCB;
+  BusLogic_CCB_T *LastCompletedCCB;
   BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
   BusLogic_ErrorRecoveryStrategy_T
     ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
-  boolean TaggedQueuingSupported[BusLogic_MaxTargetDevices];
-  boolean TaggedQueuingActive[BusLogic_MaxTargetDevices];
-  boolean CommandSuccessfulFlag[BusLogic_MaxTargetDevices];
+  BusLogic_TargetFlags_T TargetFlags[BusLogic_MaxTargetDevices];
   unsigned char QueueDepth[BusLogic_MaxTargetDevices];
+  unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices];
+  unsigned char SynchronousOffset[BusLogic_MaxTargetDevices];
   unsigned char ActiveCommands[BusLogic_MaxTargetDevices];
   unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices];
   unsigned long LastSequencePoint[BusLogic_MaxTargetDevices];
@@ -1358,7 +1443,11 @@
   BusLogic_IncomingMailbox_T *FirstIncomingMailbox;
   BusLogic_IncomingMailbox_T *LastIncomingMailbox;
   BusLogic_IncomingMailbox_T *NextIncomingMailbox;
-  BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics;
+  BusLogic_TargetStatistics_T TargetStatistics[BusLogic_MaxTargetDevices];
+  unsigned char MailboxSpace[BusLogic_MaxMailboxes
+			     * (sizeof(BusLogic_OutgoingMailbox_T)
+				+ sizeof(BusLogic_IncomingMailbox_T))];
+  char MessageBuffer[BusLogic_MessageBufferSize];
 }
 BusLogic_HostAdapter_T;
 
@@ -1377,14 +1466,49 @@
 
 
 /*
+  Define a structure for the SCSI Inquiry command results.
+*/
+
+typedef struct SCSI_Inquiry
+{
+  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
+  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
+  unsigned char DeviceTypeModifier:7;			/* Byte 1 Bits 0-6 */
+  boolean RMB:1;					/* Byte 1 Bit 7 */
+  unsigned char ANSI_ApprovedVersion:3;			/* Byte 2 Bits 0-2 */
+  unsigned char ECMA_Version:3;				/* Byte 2 Bits 3-5 */
+  unsigned char ISO_Version:2;				/* Byte 2 Bits 6-7 */
+  unsigned char ResponseDataFormat:4;			/* Byte 3 Bits 0-3 */
+  unsigned char :2;					/* Byte 3 Bits 4-5 */
+  boolean TrmIOP:1;					/* Byte 3 Bit 6 */
+  boolean AENC:1;					/* Byte 3 Bit 7 */
+  unsigned char AdditionalLength;			/* Byte 4 */
+  unsigned char :8;					/* Byte 5 */
+  unsigned char :8;					/* Byte 6 */
+  boolean SftRe:1;					/* Byte 7 Bit 0 */
+  boolean CmdQue:1;					/* Byte 7 Bit 1 */
+  boolean :1;						/* Byte 7 Bit 2 */
+  boolean Linked:1;					/* Byte 7 Bit 3 */
+  boolean Sync:1;					/* Byte 7 Bit 4 */
+  boolean WBus16:1;					/* Byte 7 Bit 5 */
+  boolean WBus32:1;					/* Byte 7 Bit 6 */
+  boolean RelAdr:1;					/* Byte 7 Bit 7 */
+  unsigned char VendorIdentification[8];		/* Bytes 8-15 */
+  unsigned char ProductIdentification[16];		/* Bytes 16-31 */
+  unsigned char ProductRevisionLevel[4];		/* Bytes 32-35 */
+}
+SCSI_Inquiry_T;
+
+
+/*
   BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter.
 */
 
 static inline
 void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
-				     BusLogic_Lock_T *Lock)
+				     ProcessorFlags_T *ProcessorFlags)
 {
-  save_flags(*Lock);
+  save_flags(*ProcessorFlags);
   cli();
 }
 
@@ -1395,32 +1519,32 @@
 
 static inline
 void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
-				     BusLogic_Lock_T *Lock)
+				     ProcessorFlags_T *ProcessorFlags)
 {
-  restore_flags(*Lock);
+  restore_flags(*ProcessorFlags);
 }
 
 
 /*
-  BusLogic_AcquireHostAdapterLockID acquires exclusive access to Host Adapter,
-  but is only called when interrupts are disabled.
+  BusLogic_AcquireHostAdapterLockIH acquires exclusive access to Host Adapter,
+  but is only called from the interrupt handler when interrupts are disabled.
 */
 
 static inline
-void BusLogic_AcquireHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
-				       BusLogic_Lock_T *Lock)
+void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+				       ProcessorFlags_T *ProcessorFlags)
 {
 }
 
 
 /*
-  BusLogic_ReleaseHostAdapterLockID releases exclusive access to Host Adapter,
-  but is only called when interrupts are disabled.
+  BusLogic_ReleaseHostAdapterLockIH releases exclusive access to Host Adapter,
+  but is only called from the interrupt handler when interrupts are disabled.
 */
 
 static inline
-void BusLogic_ReleaseHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
-				       BusLogic_Lock_T *Lock)
+void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+				       ProcessorFlags_T *ProcessorFlags)
 {
 }
 
@@ -1526,10 +1650,11 @@
 
 static inline void BusLogic_Delay(int Seconds)
 {
+  int Milliseconds = 1000 * Seconds;
   unsigned long ProcessorFlags;
   save_flags(ProcessorFlags);
   sti();
-  while (--Seconds >= 0) udelay(1000000);
+  while (--Milliseconds >= 0) udelay(1000);
   restore_flags(ProcessorFlags);
 }
 
@@ -1551,6 +1676,19 @@
 
 
 /*
+  Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and
+  32 bit Kernel Virtual Addresses.  This avoids compilation warnings
+  on 64 bit architectures.
+*/
+
+static inline
+BusLogic_BusAddress_T Virtual_to_32Bit_Virtual(void *VirtualAddress)
+{
+  return (BusLogic_BusAddress_T) (unsigned long) VirtualAddress;
+}
+
+
+/*
   BusLogic_IncrementErrorCounter increments Error Counter by 1, stopping at
   65535 rather than wrapping around to 0.
 */
@@ -1588,93 +1726,27 @@
 {
   int Index = 0;
   if (Amount < 8*1024)
-    if (Amount < 2*1024)
-      Index = (Amount < 1*1024 ? 0 : 1);
-    else Index = (Amount < 4*1024 ? 2 : 3);
+    {
+      if (Amount < 2*1024)
+	Index = (Amount < 1*1024 ? 0 : 1);
+      else Index = (Amount < 4*1024 ? 2 : 3);
+    }
   else if (Amount < 128*1024)
-    if (Amount < 32*1024)
-      Index = (Amount < 16*1024 ? 4 : 5);
-    else Index = (Amount < 64*1024 ? 6 : 7);
+    {
+      if (Amount < 32*1024)
+	Index = (Amount < 16*1024 ? 4 : 5);
+      else Index = (Amount < 64*1024 ? 6 : 7);
+    }
   else Index = (Amount < 256*1024 ? 8 : 9);
   CommandSizeBuckets[Index]++;
 }
 
 
 /*
-  If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT, and use the
-  ISA only probe function as the general one.
-*/
-
-#ifndef CONFIG_PCI
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList
-
-#endif
-
-
-/*
-  FlashPoint support is only available for the Intel x86 Architecture.
-*/
-
-#ifndef __i386__
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
-/*
-  Define macros for testing the Host Adapter Type.
-*/
-
-#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
-
-#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
-  (HostAdapter->HostAdapterType == BusLogic_MultiMaster)
-
-#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
-  (HostAdapter->HostAdapterType == BusLogic_FlashPoint)
-
-#else
-
-#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
-  (true)
-
-#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
-  (false)
-
-#endif
-
-
-/*
-  Define Driver Message Macros.
-*/
-
-#define BusLogic_Announce(Format, Arguments...) \
-  BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments)
-
-#define BusLogic_Info(Format, Arguments...) \
-  BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments)
-
-#define BusLogic_Notice(Format, Arguments...) \
-  BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments)
-
-#define BusLogic_Warning(Format, Arguments...) \
-  BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments)
-
-#define BusLogic_Error(Format, Arguments...) \
-  BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments)
-
-
-/*
   Define the version number of the FlashPoint Firmware (SCCB Manager).
 */
 
-#define FlashPoint_FirmwareVersion		"5.01"
+#define FlashPoint_FirmwareVersion		"5.02"
 
 
 /*
@@ -1682,35 +1754,22 @@
 */
 
 #define FlashPoint_NormalInterrupt		0x00
+#define FlashPoint_InternalError		0xFE
 #define FlashPoint_ExternalBusReset		0xFF
 
 
 /*
-  Define prototypes for the FlashPoint SCCB Manager Functions.
-*/
-
-extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *);
-extern FlashPoint_CardHandle_T
-       FlashPoint_HardResetHostAdapter(FlashPoint_Info_T *);
-extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
-extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
-extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
-extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
-extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
-
-
-/*
   Define prototypes for the forward referenced BusLogic Driver
   Internal Functions.
 */
 
-static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB);
+static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *);
 static void BusLogic_InterruptHandler(int, void *, Registers_T *);
 static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *,
-				     SCSI_Command_T *,
-				     unsigned int);
-static void BusLogic_Message(BusLogic_MessageLevel_T, char *Format,
+				     SCSI_Command_T *, unsigned int);
+static void BusLogic_Message(BusLogic_MessageLevel_T, char *,
 			     BusLogic_HostAdapter_T *, ...);
+static void BusLogic_ParseDriverOptions(char *);
 
 
 #endif /* BusLogic_DriverVersion */
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.0.33/linux/drivers/scsi/ChangeLog.ncr53c8xx	Thu Aug 14 10:30:08 1997
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Wed Jun  3 15:17:48 1998
@@ -1,3 +1,75 @@
+Fri Jan 2 18:00 1998 Gerard Roudier (groudier@club-internet.fr)
+	* Revision 2.5f
+	- Use FAST-5 instead of SLOW for slow scsi devices according to 
+	  new SPI-2 draft.
+	- Make some changes in order to accomodate with 875 rev <= 3 
+	  device errata listing 397. Minor consequences are:
+	  . Leave use of PCI Write and Invalidate under user control.
+	    Now, by default the driver does not enable PCI MWI and option
+	    'specf:y' is required in order to enable this feature.
+	  . Memory Read Line is not enabled for 875 and 875-like chips.
+	  . Programmed burst length set to 64 DWORDS (instead of 128).
+	    (Note: SYMBIOS uses 32 DWORDS for the SDMS BIOS)
+
+Sun Oct 26 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5e
+	- Add 'buschk' boot option.
+	  This option enables checking of SCSI BUS data lines after SCSI 
+	  RESET (set by default). (Submitted by Richard Waltham).
+	- Update the README file.
+
+Sat Oct 4 18:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5d
+	- Dispatch CONDITION MET and RESERVATION CONFLICT scsi status 
+	  as OK driver status.
+	- Update the README file and the Symbios NVRAM format definition 
+	  with removable media flags values (available with SDMS 4.09).
+
+Sat Sep 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5c
+	- Several PCI configuration registers fix-ups for powerpc.
+	  (Patch sent by Cort).
+
+Thu Aug 28 10:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5b
+	- Add 'ncr53c8xx' char pointer variable. This variable allows to 
+	  pass a boot command to the driver when it is loaded as a module.
+	  Option separator is ' ' instead of ','. Example:
+	    insmod <mod_path>/ncr53c8xx.o ncr53c8xx='verb:2 sync:0 specf:n'
+	- Always use 'driver_setup.settle_delay' for internal resets.
+	  2 seconds hardcoded is sometimes too short. Suggested by Richard W. 
+	  This delay may be shortenned in order to avoid spurious timeouts.
+	- Fix release module stuff that failed for more than 1 controller.
+	- For linux versions > 1.3.70, trust the 'dev_id' parameter passed 
+	  to the interrupt handler (dev_id = struct ncb *).
+	- Fix up in 'ncr_log_hard_error()' when the DSP points outside scripts.
+	  Suggested by Stefan Esser.
+
+Tue Aug 23 23:43 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5a
+	- Update Configure.help for inclusion in linux-2.1.51/2/3
+	- Use BASE_2 address from PCI config space instead of some 
+	  IO register for getting the on-board SRAM bus address.
+	- Remove error testing of pcibios_read/write functions.
+	  These functions are intended to be used for successfully 
+	  detected PCI devices. Expecting error condition from them 
+	  is nothing but paranoia.
+
+Thu Aug 21 23:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5
+	- 53C860 chip support fix.
+	- Move the 'host_status' to the last DWORD of the CCB header.
+	  This header is copied back by the script processor. This 
+	  guarantees that the header is entirely copied back over 
+	  the PCI when the CPU completes a CCB.
+	- (re)read ISTAT prior to scanning CCBs for completion. This
+	  ensure that any posted buffer are flushed prior CCBs scan.
+	- Support for BIG ENDIAN cpu. Added by Cort <cort@cs.nmt.edu>.
+	  Initial patch did'nt support disconnections and tagged commands.
+	  I've completed the patch and it seems that all is ok now.
+	  Only some powerpc under 2.1.X is supported for the moment.
+	- Misc. trivial fixes and cleanups.
+
 Sat July 26 18:00 1997 Gerard Roudier (groudier@club-internet.fr)
 	* revision 2.4
 	Several clean-ups:
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.0.33/linux/drivers/scsi/Config.in	Mon Sep 15 09:41:28 1997
+++ linux/drivers/scsi/Config.in	Wed Jun  3 15:17:48 1998
@@ -20,14 +20,12 @@
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
-    bool '   Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
     bool '   Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
     if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
-      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24
     fi
-    bool '   Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
     bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
-    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
@@ -79,6 +77,9 @@
   fi
 fi
 dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI
+if [ "$CONFIG_SCSI_PPA" != "n" ]; then
+    bool '  Buggy EPP chipset support' CONFIG_SCSI_PPA_HAVE_PEDANTIC
+fi
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/FlashPoint.c linux/drivers/scsi/FlashPoint.c
--- v2.0.33/linux/drivers/scsi/FlashPoint.c	Mon Aug 11 00:10:00 1997
+++ linux/drivers/scsi/FlashPoint.c	Wed Jun  3 15:17:48 1998
@@ -19,40 +19,15 @@
 #include <linux/config.h>
 
 
-/*
-  If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT.
-*/
-
-#ifndef CONFIG_PCI
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
-/*
-  FlashPoint support is only available for the Intel x86 Architecture.
-*/
-
-#ifndef __i386__
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
 #ifndef CONFIG_SCSI_OMIT_FLASHPOINT
 
 
 #define UNIX
 #define FW_TYPE		_SCCB_MGR_
 #define MAX_CARDS	8
+#undef BUSTYPE_PCI
 
 
-#include <asm/io.h>
-
 #define OS_InPortByte(port)		inb(port)
 #define OS_InPortWord(port)		inw(port)
 #define OS_InPortLong(port)		inl(port)
@@ -68,7 +43,7 @@
 */
 
 #define SccbMgr_sense_adapter		FlashPoint_ProbeHostAdapter
-#define SccbMgr_config_adapter		FlashPoint_HardResetHostAdapter
+#define SccbMgr_config_adapter		FlashPoint_HardwareResetHostAdapter
 #define SccbMgr_unload_card		FlashPoint_ReleaseHostAdapter
 #define SccbMgr_start_sccb		FlashPoint_StartCCB
 #define SccbMgr_abort_sccb		FlashPoint_AbortCCB
@@ -169,6 +144,7 @@
 #define stwidn				FPT_stwidn
 #define sxfrp				FPT_sxfrp
 #define utilEERead			FPT_utilEERead
+#define utilEEReadOrg			FPT_utilEEReadOrg
 #define utilEESendCmdAddr		FPT_utilEESendCmdAddr
 #define utilEEWrite			FPT_utilEEWrite
 #define utilEEWriteOnOff		FPT_utilEEWriteOnOff
@@ -1317,9 +1293,9 @@
  *
  *   Description:  Register definitions for HARPOON ASIC.
  *
- *   $Date: 1997/01/31 02:14:28 $
+ *   $Date: 1997/07/09 21:44:36 $
  *
- *   $Revision: 1.6 $
+ *   $Revision: 1.9 $
  *
  *----------------------------------------------------------------------*/
 
@@ -2070,9 +2046,14 @@
 UCHAR RdStack(USHORT port, UCHAR index);
 void  WrStack(USHORT portBase, UCHAR index, UCHAR data);
 UCHAR ChkIfChipInitialized(USHORT ioPort);
+
+#if defined(V302)
 UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun);
+#endif
+
 void SendMsg(USHORT port, UCHAR message);
 void  queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id);
 #else
 UCHAR sfm(ULONG port, PSCCB pcurrSCCB);
 void  scsiStartAuto(ULONG port);
@@ -2090,7 +2071,11 @@
 UCHAR RdStack(ULONG port, UCHAR index);
 void  WrStack(ULONG portBase, UCHAR index, UCHAR data);
 UCHAR ChkIfChipInitialized(ULONG ioPort);
+
+#if defined(V302)
 UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tar, PUCHAR lun);
+#endif
+
 void SendMsg(ULONG port, UCHAR message);
 void  queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
 #endif
@@ -2130,6 +2115,7 @@
 void  utilEEWriteOnOff(USHORT p_port,UCHAR p_mode);
 void  utilEEWrite(USHORT p_port, USHORT ee_data, USHORT ee_addr);
 USHORT utilEERead(USHORT p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr);
 void  utilEESendCmdAddr(USHORT p_port, UCHAR ee_cmd, USHORT ee_addr);
 #else
 void  Wait1Second(ULONG p_port);
@@ -2137,6 +2123,7 @@
 void  utilEEWriteOnOff(ULONG p_port,UCHAR p_mode);
 void  utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr);
 USHORT utilEERead(ULONG p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr);
 void  utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr);
 #endif
 
@@ -2339,7 +2326,7 @@
 extern unsigned int SccbGlobalFlags;
 
 
-#ident "$Id: sccb.c 1.17 1997/02/11 21:06:41 mohan Exp $"
+#ident "$Id: sccb.c 1.18 1997/06/10 16:47:04 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -2353,9 +2340,9 @@
  *   Description:  Functions relating to handling of the SCCB interface
  *                 between the device driver and the HARPOON.
  *
- *   $Date: 1997/02/11 21:06:41 $
+ *   $Date: 1997/06/10 16:47:04 $
  *
- *   $Revision: 1.17 $
+ *   $Revision: 1.18 $
  *
  *----------------------------------------------------------------------*/
 
@@ -2477,6 +2464,7 @@
 		if(ChkIfChipInitialized(ioport) == FALSE)
 		{
 			pCurrNvRam = NULL;
+		   WR_HARPOON(ioport+hp_semaphore, 0x00);
 			XbowInit(ioport, 0);             /*Must Init the SCSI before attempting */
 			DiagEEPROM(ioport);
 		}
@@ -3036,6 +3024,7 @@
 		if(ChkIfChipInitialized(ioport) == FALSE)
 		{
 			pCurrNvRam = NULL;
+		   WR_HARPOON(ioport+hp_semaphore, 0x00);
 			XbowInit(ioport, 0);                /*Must Init the SCSI before attempting */
 			DiagEEPROM(ioport);
 		}
@@ -4802,7 +4791,23 @@
                may not show up if another device reselects us in 1.5us or
                less.  SRR Wednesday, 3/8/1995.
              */
-	   while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) ;
+	   while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)) &&
+		  !((RDW_HARPOON((ioport+hp_intstat)) & PHASE) &&
+		    RD_HARPOON((ioport+hp_scsisig)) ==
+		    (SCSI_BSY | SCSI_REQ | SCSI_CD | SCSI_MSG | SCSI_IOBIT))) ;
+
+	   /*
+	     The additional loop exit condition above detects a timing problem
+	     with the revision D/E harpoon chips.  The caller should reset the
+	     host adapter to recover when 0xFE is returned.
+	   */
+	   if (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)))
+	     {
+	       mOS_Lock((PSCCBcard)pCurrCard);
+	       MENABLE_INT(ioport);
+	       mOS_UnLock((PSCCBcard)pCurrCard);
+	       return 0xFE;
+	     }
 
          WRW_HARPOON((ioport+hp_intstat), (BUS_FREE | ITAR_DISC));
 
@@ -5347,7 +5352,7 @@
 }
 
 #endif
-#ident "$Id: sccb_dat.c 1.9 1997/01/31 02:12:58 mohan Exp $"
+#ident "$Id: sccb_dat.c 1.10 1997/02/22 03:16:02 awin Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -5361,9 +5366,9 @@
  *   Description:  Functions relating to handling of the SCCB interface 
  *                 between the device driver and the HARPOON.
  *
- *   $Date: 1997/01/31 02:12:58 $
+ *   $Date: 1997/02/22 03:16:02 $
  *
- *   $Revision: 1.9 $
+ *   $Revision: 1.10 $
  *
  *----------------------------------------------------------------------*/
 
@@ -5378,18 +5383,19 @@
 /*#include <target.h>*/
 /*#include <harpoon.h>*/
 
+/*
+**  IMPORTANT NOTE!!!
+**
+**  You MUST preassign all data to a valid value or zero.  This is
+**  required due to the MS compiler bug under OS/2 and Solaris Real-Mode
+**  driver environment.
+*/
+
 
-#if defined(OS2) || defined (SOLARIS_REAL_MODE)
-SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { 0 };
-SCCBCARD BL_Card[MAX_CARDS] = { 0 };
-SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { 0 };
-NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { 0 };
-#else
-SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
-SCCBCARD BL_Card[MAX_CARDS];
-SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR];
-NVRAMINFO nvRamInfo[MAX_MB_CARDS];
-#endif
+SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { { { 0 } } };
+SCCBCARD BL_Card[MAX_CARDS] = { { 0 } };
+SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { { { 0 } } };
+NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { { 0 } };
 
 
 #if defined(OS2)
@@ -5402,23 +5408,23 @@
 #endif
 
 #if defined(DOS)
-UCHAR first_time;
+UCHAR first_time = 0;
 #endif
 
-UCHAR mbCards;
+UCHAR mbCards = 0;
 UCHAR scamHAString[] = {0x63, 0x07, 'B', 'U', 'S', 'L', 'O', 'G', 'I', 'C', \
 								' ', 'B', 'T', '-', '9', '3', '0', \
 								0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \
 								0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
 
-USHORT default_intena;
+USHORT default_intena = 0;
 
 #if defined(BUGBUG)
-UCHAR    debug_int[MAX_CARDS][debug_size];
-UCHAR    debug_index[MAX_CARDS];
-UCHAR    reserved_1[3];
+UCHAR    debug_int[MAX_CARDS][debug_size] = { 0 };
+UCHAR    debug_index[MAX_CARDS] = { 0 };
+UCHAR    reserved_1[3] = { 0 };
 #endif
-#ident "$Id: scsi.c 1.19 1997/01/31 02:08:14 mohan Exp $"
+#ident "$Id: scsi.c 1.23 1997/07/09 21:42:54 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -5433,9 +5439,9 @@
  *                 selection/reselection, sync negotiation, message-in
  *                 decoding.
  *
- *   $Date: 1997/01/31 02:08:14 $
+ *   $Date: 1997/07/09 21:42:54 $
  *
- *   $Revision: 1.19 $
+ *   $Revision: 1.23 $
  *
  *----------------------------------------------------------------------*/
 
@@ -5483,11 +5489,13 @@
 	while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
 			(TimeOutLoop++ < 20000) ){}
 
+
 	WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
 
 	message = RD_HARPOON(port+hp_scsidata_0);
 
-	WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+	WR_HARPOON(port+hp_scsisig, SCSI_ACK + S_MSGI_PH);
+
 
 	if (TimeOutLoop > 20000)
 		message = 0x00;   /* force message byte = 0 if Time Out on Req */
@@ -5495,6 +5503,10 @@
 	if ((RDW_HARPOON((port+hp_intstat)) & PARITY) &&
 		(RD_HARPOON(port+hp_addstat) & SCSI_PAR_ERR))
 	{
+		WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+		WR_HARPOON(port+hp_xferstat, 0);
+		WR_HARPOON(port+hp_fiforead, 0);
+		WR_HARPOON(port+hp_fifowrite, 0);
 		if (pCurrSCCB != NULL)
 		{
 			pCurrSCCB->Sccb_scsimsg = SMPARITY;
@@ -5503,6 +5515,7 @@
 		do
 		{
 			ACCEPT_MSG_ATN(port);
+			TimeOutLoop = 0;
 			while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
 				(TimeOutLoop++ < 20000) ){}
 			if (TimeOutLoop > 20000)
@@ -5524,6 +5537,10 @@
 		}while(1);
 
 	}
+	WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+	WR_HARPOON(port+hp_xferstat, 0);
+	WR_HARPOON(port+hp_fiforead, 0);
+	WR_HARPOON(port+hp_fifowrite, 0);
 	return(message);
 }
 
@@ -5894,12 +5911,20 @@
 void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard)
 #endif
 {
+
+#if defined(V302)
 #ifdef DOS
    UCHAR our_target,message, msgRetryCount;
    extern UCHAR lun, tag;
 #else
    UCHAR our_target,message,lun,tag, msgRetryCount;
 #endif
+
+#else  /* V302 */
+   UCHAR our_target, message, lun = 0, tag, msgRetryCount;
+#endif /* V302 */
+
+
    PSCCBMgr_tar_info currTar_Info;
 	PSCCB currSCCB;
 
@@ -5972,7 +5997,103 @@
 	msgRetryCount = 0;
 	do
 	{
+
+#if defined(V302)
+
 		message = GetTarLun(port, p_card, our_target, pCurrCard, &tag, &lun);
+
+#else /* V302 */
+
+		currTar_Info = &sccbMgrTbl[p_card][our_target];
+		tag = 0;
+
+
+		while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ))
+		{
+			if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY))
+			{
+
+				WRW_HARPOON((port+hp_intstat), PHASE);
+				return;
+			}
+		}
+
+		WRW_HARPOON((port+hp_intstat), PHASE);
+		if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH)
+		{
+
+			message = sfm(port,pCurrCard->currentSCCB);
+			if (message)
+			{
+
+				if (message <= (0x80 | LUN_MASK))
+				{
+					lun = message & (UCHAR)LUN_MASK;
+
+#if !defined(DOS)
+					if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING)
+					{
+						if (currTar_Info->TarTagQ_Cnt != 0)
+						{
+
+							if (!(currTar_Info->TarLUN_CA))
+							{
+								ACCEPT_MSG(port);    /*Release the ACK for ID msg. */
+
+
+								message = sfm(port,pCurrCard->currentSCCB);
+								if (message)
+								{
+									ACCEPT_MSG(port);
+								}
+
+								else
+   								message = FALSE;
+
+								if(message != FALSE)
+								{
+									tag = sfm(port,pCurrCard->currentSCCB);
+
+									if (!(tag)) 
+										message = FALSE;
+								}
+
+							} /*C.A. exists! */
+
+						} /*End Q cnt != 0 */
+
+					} /*End Tag cmds supported! */
+#endif /* !DOS */
+
+				} /*End valid ID message.  */
+
+				else
+				{
+
+					ACCEPT_MSG_ATN(port);
+				}
+
+			} /* End good id message. */
+
+			else
+			{
+
+				message = FALSE;
+			}
+		}
+		else
+		{
+			ACCEPT_MSG_ATN(port);
+
+		   while (!(RDW_HARPOON((port+hp_intstat)) & (PHASE | RESET)) &&
+			  !(RD_HARPOON(port+hp_scsisig) & SCSI_REQ) &&
+			  (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
+
+			return;
+		}
+	
+#endif /* V302 */
+
 		if(message == FALSE)
 		{
 			msgRetryCount++;
@@ -6071,6 +6192,8 @@
 	  (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
 }
 
+#if defined(V302)
+
 #if defined(DOS)
 UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun)
 #else
@@ -6162,6 +6285,7 @@
 	return(TRUE);
 }
 
+#endif /* V302 */
 
 #if defined(DOS)
 void SendMsg(USHORT port, UCHAR message)
@@ -6469,6 +6593,10 @@
 				ACCEPT_MSG(port);
 			WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
 		}
+	}else
+	{
+			if(pCurrSCCB->Sccb_scsimsg == SMPARITY)
+				WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
 	}
 }
 
@@ -7386,6 +7514,7 @@
    p_sccb->Sccb_scsistat      = BUS_FREE_ST;
    p_sccb->SccbStatus         = SCCB_IN_PROCESS;
    p_sccb->Sccb_scsimsg       = SMNO_OP;
+
 }
 
 
@@ -9222,7 +9351,7 @@
       currSCCB->Sccb_XferCnt = currSCCB->DataLength - currSCCB->Sccb_ATC;
       }
 }
-#ident "$Id: scam.c 1.16 1997/01/31 02:11:12 mohan Exp $"
+#ident "$Id: scam.c 1.17 1997/03/20 23:49:37 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -9237,9 +9366,9 @@
  *                 and the determination of the SCSI IDs to be assigned
  *                 to all perspective SCSI targets.
  *
- *   $Date: 1997/01/31 02:11:12 $
+ *   $Date: 1997/03/20 23:49:37 $
  *
- *   $Revision: 1.16 $
+ *   $Revision: 1.17 $
  *
  *----------------------------------------------------------------------*/
 
@@ -9468,7 +9597,7 @@
      	if (((ScamFlg & SCAM_ENABLED) && (scamInfo[i].state == LEGACY))
 			|| (i != p_our_id))
         	{
-         scsell(p_port,i);
+         scsellDOS(p_port,i);
   	      }
   	}
 #endif
@@ -9885,6 +10014,7 @@
             }
 
          if ((ret_data & 0x1F) == 0)
+	   {
 /*
 				if(bit_cnt != 0 || bit_cnt != 8)
 				{
@@ -9899,6 +10029,7 @@
                return(0x00);
             else
                return(0xFF);
+	   }
 
          } /*bit loop */
 
@@ -10090,6 +10221,90 @@
       }
 }
 
+#if defined(DOS)
+/*---------------------------------------------------------------------
+ *
+ * Function: scsell for DOS
+ *
+ * Description: Select the specified device ID using a selection timeout
+ *              less than 2ms.  This was specially required to solve
+ *              the problem with Plextor 12X CD-ROM drive. This drive
+ *					 was responding the Selection at the end of 4ms and 
+ *					 hanging the system.
+ *
+ *---------------------------------------------------------------------*/
+
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id)
+{
+   USHORT i;
+
+   WR_HARPOON(p_port+hp_page_ctrl,
+      (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE));
+
+   ARAM_ACCESS(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) | SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_2ms);
+
+
+   for (i = p_port+CMD_STRT; i < p_port+CMD_STRT+12; i+=2) {
+      WRW_HARPOON(i, (MPM_OP+ACOMMAND));
+      }
+   WRW_HARPOON(i, (BRH_OP+ALWAYS+    NP));
+
+   WRW_HARPOON((p_port+hp_intstat),
+	       (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT));
+
+   WR_HARPOON(p_port+hp_select_id, targ_id);
+
+   WR_HARPOON(p_port+hp_portctrl_0, SCSI_PORT);
+   WR_HARPOON(p_port+hp_autostart_3, (SELECT | CMD_ONLY_STRT));
+   WR_HARPOON(p_port+hp_scsictrl_0, (SEL_TAR | ENA_RESEL));
+
+
+   while (!(RDW_HARPOON((p_port+hp_intstat)) &
+	    (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) {}
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & RESET)
+         Wait(p_port, TO_250ms);
+
+   DISABLE_AUTO(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) & ~SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_290ms);
+
+   SGRAM_ACCESS(p_port);
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & (RESET | TIMEOUT) ) {
+
+      WRW_HARPOON((p_port+hp_intstat),
+		  (RESET | TIMEOUT | SEL | BUS_FREE | PHASE));
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(FALSE);  /*No legacy device */
+      }
+
+   else {
+
+      while(!(RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)) {
+				if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ)
+					{
+					WR_HARPOON(p_port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+      			ACCEPT_MSG(p_port);
+					}
+		}
+
+      WRW_HARPOON((p_port+hp_intstat), CLR_ALL_INT_1);
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(TRUE);  /*Found one of them oldies! */
+      }
+}
+#endif  /* DOS */
 
 /*---------------------------------------------------------------------
  *
@@ -10252,10 +10467,12 @@
       match--;
 
       if (match == 0xFF)
+	{
          if (p_id_string[0] & BIT(5))
             match = 7;
          else
             match = MAX_SCSI_TAR-1;
+	}
       }
 
 
@@ -10300,10 +10517,12 @@
       match--;
 
       if (match == 0xFF)
+	{
          if (p_id_string[0] & BIT(5))
             match = 7;
          else
             match = MAX_SCSI_TAR-1;
+	}
       }
 
    return(NO_ID_AVAIL);
@@ -10362,7 +10581,7 @@
    utilEEWrite(p_port, sum_data, EEPROM_CHECK_SUM/2);
    utilEEWriteOnOff(p_port,0);   /* Turn off write access */
 }
-#ident "$Id: diagnose.c 1.9 1997/01/31 02:09:48 mohan Exp $"
+#ident "$Id: diagnose.c 1.10 1997/06/10 16:51:47 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -10376,9 +10595,9 @@
  *   Description:  Diagnostic funtions for testing the integrity of
  *                 the HARPOON.
  *
- *   $Date: 1997/01/31 02:09:48 $
+ *   $Date: 1997/06/10 16:51:47 $
  *
- *   $Revision: 1.9 $
+ *   $Revision: 1.10 $
  *
  *----------------------------------------------------------------------*/
 
@@ -10419,7 +10638,7 @@
    WR_HARPOON(port+hp_scsireset,(DMA_RESET | HPSCSI_RESET | PROG_RESET | \
 				 FIFO_CLR));
 
-   WR_HARPOON(port+hp_scsireset,0x00);
+   WR_HARPOON(port+hp_scsireset,SCSI_INI);
 
    WR_HARPOON(port+hp_clkctrl_0,CLKCTRL_DEFAULT);
 
@@ -10703,8 +10922,8 @@
    temp += 0x70D3;
    utilEEWrite(p_port, 0x0010, BIOS_CONFIG/2);
    temp += 0x0010;
-   utilEEWrite(p_port, 0x0007, SCAM_CONFIG/2);
-   temp += 0x0007;
+   utilEEWrite(p_port, 0x0003, SCAM_CONFIG/2);
+   temp += 0x0003;
    utilEEWrite(p_port, 0x0007, ADAPTER_SCSI_ID/2);
    temp += 0x0007;
 
@@ -10807,7 +11026,7 @@
 
 }
 
-#ident "$Id: utility.c 1.22 1997/01/31 02:12:23 mohan Exp $"
+#ident "$Id: utility.c 1.23 1997/06/10 16:55:06 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -10821,9 +11040,9 @@
  *   Description:  Utility functions relating to queueing and EEPROM
  *                 manipulation and any other garbage functions.
  *
- *   $Date: 1997/01/31 02:12:23 $
+ *   $Date: 1997/06/10 16:55:06 $
  *
- *   $Revision: 1.22 $
+ *   $Revision: 1.23 $
  *
  *----------------------------------------------------------------------*/
 /*#include <globals.h>*/
@@ -11617,10 +11836,13 @@
 	 ee_value &= ~SEE_DO;
 
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value |= SEE_CLK;          /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  }
    ee_value &= (EXT_ARB_ACK | SCSI_TERM_ENA_H);
    WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS));
@@ -11632,7 +11854,6 @@
    WR_HARPOON(p_port+hp_ee_ctrl, ee_value);       /* Turn off Master Select */
 }
 
-
 /*---------------------------------------------------------------------
  *
  * Function: Read EEPROM
@@ -11648,6 +11869,40 @@
 USHORT utilEERead(ULONG p_port, USHORT ee_addr)
 #endif
 {
+   USHORT i, ee_data1, ee_data2;
+
+	i = 0;
+	ee_data1 = utilEEReadOrg(p_port, ee_addr);
+	do
+	{
+		ee_data2 = utilEEReadOrg(p_port, ee_addr);
+
+		if(ee_data1 == ee_data2)
+			return(ee_data1);
+
+		ee_data1 = ee_data2;
+		i++;
+
+	}while(i < 4);
+
+	return(ee_data1);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Read EEPROM Original 
+ *
+ * Description: Read a word from the EEPROM at the desired
+ *              address.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr)
+#else
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr)
+#endif
+{
 
    UCHAR ee_value;
    USHORT i, ee_data;
@@ -11666,8 +11921,10 @@
 
 	  ee_value |= SEE_CLK;          /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 
 	  ee_data <<= 1;
 
@@ -11722,10 +11979,13 @@
 		 ee_value &= ~SEE_DO;
 
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value |= SEE_CLK;                         /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  }
 
 
@@ -11744,10 +12004,13 @@
 		 ee_value &= ~SEE_DO;
 
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value |= SEE_CLK;                         /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 
 	  i >>= 1;
 	  }
@@ -11783,6 +12046,114 @@
 	return(lrc);
 }
 
+
+
+/*
+  The following inline definitions avoid type conflicts.
+*/
+
+static inline unsigned char
+FlashPoint__ProbeHostAdapter(FlashPoint_Info_T *FlashPointInfo)
+{
+  return FlashPoint_ProbeHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+
+static inline FlashPoint_CardHandle_T
+FlashPoint__HardwareResetHostAdapter(FlashPoint_Info_T *FlashPointInfo)
+{
+  return FlashPoint_HardwareResetHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+static inline void
+FlashPoint__ReleaseHostAdapter(FlashPoint_CardHandle_T CardHandle)
+{
+  FlashPoint_ReleaseHostAdapter(CardHandle);
+}
+
+
+static inline void
+FlashPoint__StartCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB)
+{
+  FlashPoint_StartCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline void
+FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB)
+{
+  FlashPoint_AbortCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline boolean
+FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle)
+{
+  return FlashPoint_InterruptPending(CardHandle);
+}
+
+
+static inline int
+FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle)
+{
+  return FlashPoint_HandleInterrupt(CardHandle);
+}
+
+
+#define FlashPoint_ProbeHostAdapter	    FlashPoint__ProbeHostAdapter
+#define FlashPoint_HardwareResetHostAdapter FlashPoint__HardwareResetHostAdapter
+#define FlashPoint_ReleaseHostAdapter	    FlashPoint__ReleaseHostAdapter
+#define FlashPoint_StartCCB		    FlashPoint__StartCCB
+#define FlashPoint_AbortCCB		    FlashPoint__AbortCCB
+#define FlashPoint_InterruptPending	    FlashPoint__InterruptPending
+#define FlashPoint_HandleInterrupt	    FlashPoint__HandleInterrupt
+
+
+/*
+  FlashPoint_InquireTargetInfo returns the Synchronous Period, Synchronous
+  Offset, and Wide Transfers Active information for TargetID on CardHandle.
+*/
+
+void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T CardHandle,
+				  int TargetID,
+				  unsigned char *SynchronousPeriod,
+				  unsigned char *SynchronousOffset,
+				  unsigned char *WideTransfersActive)
+{
+  SCCBMGR_TAR_INFO *TargetInfo =
+    &sccbMgrTbl[((SCCBCARD *)CardHandle)->cardIndex][TargetID];
+  if ((TargetInfo->TarSyncCtrl & SYNC_OFFSET) > 0)
+    {
+      *SynchronousPeriod = 5 * ((TargetInfo->TarSyncCtrl >> 5) + 1);
+      *SynchronousOffset = TargetInfo->TarSyncCtrl & SYNC_OFFSET;
+    }
+  else
+    {
+      *SynchronousPeriod = 0;
+      *SynchronousOffset = 0;
+    }
+  *WideTransfersActive = (TargetInfo->TarSyncCtrl & NARROW_SCSI ? 0 : 1);
+}
+
+
+#else  /* CONFIG_SCSI_OMIT_FLASHPOINT */
+
+
+/*
+  Define prototypes for the FlashPoint SCCB Manager Functions.
+*/
+
+extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *);
+extern FlashPoint_CardHandle_T
+       FlashPoint_HardwareResetHostAdapter(FlashPoint_Info_T *);
+extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
+extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
+extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
+extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
+extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
+extern void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T,
+					 int, unsigned char *,
+					 unsigned char *, unsigned char *);
 
 
 #endif /* CONFIG_SCSI_OMIT_FLASHPOINT */
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.0.33/linux/drivers/scsi/Makefile	Thu Aug 14 10:31:20 1997
+++ linux/drivers/scsi/Makefile	Wed Jun  3 15:17:48 1998
@@ -370,12 +370,6 @@
 
 include $(TOPDIR)/Rules.make
 
-BusLogic.o: BusLogic.c FlashPoint.c
-	$(CC) $(CFLAGS) -c BusLogic.c -o BusLogic.O
-	$(CC) $(CFLAGS) -c FlashPoint.c -o FlashPoint.O
-	$(LD) -r -o BusLogic.o BusLogic.O FlashPoint.O
-	rm -f BusLogic.O FlashPoint.O
-
 aha152x.o: aha152x.c
 	$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.0.33/linux/drivers/scsi/NCR5380.c	Tue Oct 29 06:21:48 1996
+++ linux/drivers/scsi/NCR5380.c	Wed Jun  3 15:17:48 1998
@@ -491,11 +491,11 @@
  */
 #ifndef USLEEP_SLEEP
 /* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP 2
+#define USLEEP_SLEEP (20*HZ/1000)
 #endif
 /* 300 RPM (floppy speed) */
 #ifndef USLEEP_POLL
-#define USLEEP_POLL 20
+#define USLEEP_POLL (200*HZ/1000)
 #endif
 
 static struct Scsi_Host * expires_first = NULL;
@@ -643,7 +643,7 @@
 	    == 0)) 
 	    trying_irqs |= mask;
 
-    timeout = jiffies + 25;
+    timeout = jiffies + 250*HZ/1000;
     probe_irq = IRQ_NONE;
 
 /*
@@ -819,7 +819,7 @@
 SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
 #endif
 
-   SPRINTF("\nBase Addr: 0x%05X    ", (int)instance->base);
+   SPRINTF("\nBase Addr: 0x%05lX    ", (long)instance->base);
    SPRINTF("io_port: %04x      ", (int)instance->io_port);
    if (instance->irq == IRQ_NONE)
       SPRINTF("IRQ: None.\n");
@@ -1002,7 +1002,7 @@
 	case 5:
 	    printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
 		instance->host_no);
-	    timeout = jiffies + 500;
+	    timeout = jiffies + 5*HZ;
 	    while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY));
 	    break;
 	case 2:
@@ -1618,7 +1618,7 @@
      * selection.
      */
 
-    timeout = jiffies + 25; 
+    timeout = jiffies + 250*HZ/1000;
 
     /* 
      * XXX very interesting - we're seeing a bounce where the BSY we 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h
--- v2.0.33/linux/drivers/scsi/NCR5380.h	Mon Apr 29 07:14:19 1996
+++ linux/drivers/scsi/NCR5380.h	Wed Jun  3 15:17:48 1998
@@ -314,29 +314,33 @@
 static int NCR5380_transfer_pio (struct Scsi_Host *instance,
 	unsigned char *phase, int *count, unsigned char **data);
 
-#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
-static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
+#if (defined(REAL_DMA) || defined(REAL_DMA_POLL))
+
+#if defined(i386) || defined(__alpha__)
+
+static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance,
 	unsigned char *ptr, unsigned int count, unsigned char mode) {
     unsigned limit;
+    unsigned long bus_addr = virt_to_bus(ptr);
 
     if (instance->dma_channel <=3) {
 	if (count > 65536)
 	    count = 65536;
-	limit = 65536 - (((unsigned) ptr) & 0xFFFF);
+	limit = 65536 - (bus_addr & 0xFFFF);
     } else {
 	if (count > 65536 * 2) 
 	    count = 65536 * 2;
-	limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF);
+	limit = 65536* 2 - (bus_addr & 0x1FFFF);
     }
 
     if (count > limit) count = limit;
 
-    if ((count & 1) || (((unsigned) ptr) & 1))
+    if ((count & 1) || (bus_addr & 1))
 	panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
     cli();
     disable_dma(instance->dma_channel);
     clear_dma_ff(instance->dma_channel);
-    set_dma_addr(instance->dma_channel, (unsigned int) ptr);
+    set_dma_addr(instance->dma_channel, bus_addr);
     set_dma_count(instance->dma_channel, count);
     set_dma_mode(instance->dma_channel, mode);
     enable_dma(instance->dma_channel);
@@ -344,17 +348,17 @@
     return count;
 }
 
-static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance,
     unsigned char *src, unsigned int count) {
-    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE);
+    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE);
 }
 
-static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance,
     unsigned char *src, unsigned int count) {
-    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ);
+    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ);
 }
 
-static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
+static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) {
     register int tmp;
     cli();
     clear_dma_ff(instance->dma_channel);
@@ -362,7 +366,8 @@
     sti();
     return tmp;
 }
-#endif /* defined(REAL_DMA) && defined(i386)  */
+#endif /* defined(i386) || defined(__alpha__) */
+#endif /* defined(REAL_DMA)  */
 #endif __KERNEL_
 #endif /* ndef ASM */
 #endif /* NCR5380_H */
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/README.BusLogic linux/drivers/scsi/README.BusLogic
--- v2.0.33/linux/drivers/scsi/README.BusLogic	Mon Aug 11 00:10:00 1997
+++ linux/drivers/scsi/README.BusLogic	Wed Jun  3 15:17:48 1998
@@ -1,41 +1,48 @@
 	   BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
 
-			 Version 2.0.10 for Linux 2.0
+			 Version 2.0.14 for Linux 2.0
 
 			      PRODUCTION RELEASE
 
-				11 August 1997
+				 29 April 1998
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
 			       lnz@dandelion.com
 
-	   Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+	 Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
 
 
 				 INTRODUCTION
 
-BusLogic, Inc. designs and manufactures a variety of high performance SCSI host
-adapters which share a common programming interface across a diverse collection
-of bus architectures by virtue of their MultiMaster ASIC technology.  This
-driver supports all present BusLogic MultiMaster Host Adapters, and should
+BusLogic, Inc. designed and manufactured a variety of high performance SCSI
+host adapters which share a common programming interface across a diverse
+collection of bus architectures by virtue of their MultiMaster ASIC technology.
+BusLogic was acquired by Mylex Corporation in February 1996, but the products
+supported by this driver originated under the BusLogic name and so that name is
+retained in the source code and documentation.
+
+This driver supports all present BusLogic MultiMaster Host Adapters, and should
 support any future MultiMaster designs with little or no modification.  More
-recently, BusLogic has introduced the FlashPoint Host Adapters, which are less
+recently, BusLogic introduced the FlashPoint Host Adapters, which are less
 costly and rely on the host CPU, rather than including an onboard processor.
-Mylex/BusLogic has recently provided me with the FlashPoint Driver Developer's
-Kit, which comprises documentation and freely redistributable source code for
-the FlashPoint SCCB Manager.  The SCCB Manager is the library of code that runs
-on the host CPU and performs functions analogous to the firmware on the
-MultiMaster Host Adapters.  Thanks to their having provided the SCCB Manager,
-this driver now supports the FlashPoint Host Adapters as well.
+Despite not having an onboard CPU, the FlashPoint Host Adapters perform very
+well and have very low command latency.  BusLogic has recently provided me with
+the FlashPoint Driver Developer's Kit, which comprises documentation and freely
+redistributable source code for the FlashPoint SCCB Manager.  The SCCB Manager
+is the library of code that runs on the host CPU and performs functions
+analogous to the firmware on the MultiMaster Host Adapters.  Thanks to their
+having provided the SCCB Manager, this driver now supports the FlashPoint Host
+Adapters as well.
 
 My primary goals in writing this completely new BusLogic driver for Linux are
 to achieve the full performance that BusLogic SCSI Host Adapters and modern
 SCSI peripherals are capable of, and to provide a highly robust driver that can
 be depended upon for high performance mission critical applications.  All of
 the major performance and error recovery features can be configured from the
-Linux kernel command line, allowing individual installations to tune driver
-performance and error recovery to their particular needs.
+Linux kernel command line or at module initialization time, allowing individual
+installations to tune driver performance and error recovery to their particular
+needs.
 
 The latest information on Linux support for BusLogic SCSI Host Adapters, as
 well as the most recent release of this driver and the latest firmware for the
@@ -48,33 +55,35 @@
 relevant to SCSI operations, and a detailed description of your system's
 hardware configuration.
 
-BusLogic has been an excellent company to work with and I highly recommend
-their products to the Linux community.  In November 1995, I was offered the
+Mylex has been an excellent company to work with and I highly recommend their
+products to the Linux community.  In November 1995, I was offered the
 opportunity to become a beta test site for their latest MultiMaster product,
 the BT-948 PCI Ultra SCSI Host Adapter, and then again for the BT-958 PCI Wide
 Ultra SCSI Host Adapter in January 1996.  This was mutually beneficial since
-BusLogic received a degree and kind of testing that their own testing group
-cannot readily achieve, and the Linux community has available high performance
-host adapters that have been well tested with Linux even before being brought
-to market.  This relationship has also given me the opportunity to interact
+Mylex received a degree and kind of testing that their own testing group cannot
+readily achieve, and the Linux community has available high performance host
+adapters that have been well tested with Linux even before being brought to
+market.  This relationship has also given me the opportunity to interact
 directly with their technical staff, to understand more about the internal
 workings of their products, and in turn to educate them about the needs and
-potential of the Linux community.  Their interest and support is greatly
-appreciated.
+potential of the Linux community.
+
+More recently, Mylex has reaffirmed the company's interest in supporting the
+Linux community, and I am now working on a Linux driver for the DAC960 PCI RAID
+Controllers.  Mylex's interest and support is greatly appreciated.
 
-Unlike some other vendors, if you contact BusLogic Technical Support with a
+Unlike some other vendors, if you contact Mylex Technical Support with a
 problem and are running Linux, they will not tell you that your use of their
 products is unsupported.  Their latest product marketing literature even states
-"BusLogic SCSI host adapters are compatible with all major operating systems
+"Mylex SCSI host adapters are compatible with all major operating systems
 including: ... Linux ...".
 
-BusLogic, Inc. is located at 4151 Burton Drive, Santa Clara, California, 95054,
-USA and can be reached by Voice at 408/492-9090 or by FAX at 408/492-1542.
-BusLogic maintains a World Wide Web site at http://www.buslogic.com, an
-anonymous FTP site at ftp.buslogic.com, and a BBS at 408/492-1984.  BusLogic
-Technical Support can be reached by electronic mail at techsup@buslogic.com, by
-Voice at 408/654-0760, or by FAX at 408/492-1542.  Contact information for
-offices in Europe and Japan is available on the Web site.
+Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont, California
+94555, USA and can be reached at 510/796-6100 or on the World Wide Web at
+http://www.mylex.com.  Mylex Technical Support can be reached by electronic
+mail at techsup@mylex.com, by Voice at 510/608-2400, or by FAX at 510/745-7715.
+Contact information for offices in Europe and Japan is available on the Web
+site.
 
 
 				DRIVER FEATURES
@@ -83,15 +92,46 @@
 
   During system initialization, the driver reports extensively on the host
   adapter hardware configuration, including the synchronous transfer parameters
-  negotiated with each target device.  In addition, the driver tests the
-  hardware interrupt configuration to verify that interrupts are actually
-  delivered correctly to the interrupt handler.  This should catch a high
-  percentage of PCI motherboard configuration errors early, because when the
-  host adapter is probed successfully, most of the remaining problems appear to
-  be related to interrupts.  Most often, any remaining hardware problems are
-  related to the specific configuration of devices on the SCSI bus, and the
-  quality of cabling and termination used.  Finally, this BusLogic driver
-  should never incorrectly attempt to support an Adaptec 154x Host Adapter.
+  requested and negotiated with each target device.  AutoSCSI settings for
+  Synchronous Negotiation, Wide Negotiation, and Disconnect/Reconnect are
+  reported for each target device, as well as the status of Tagged Queuing and
+  Error Recovery.  If the same setting is in effect for all target devices,
+  then a single word or phrase is used; otherwise, a letter is provided for
+  each target device to indicate the individual status.  The following examples
+  should clarify this reporting format:
+
+    Synchronous Negotiation: Ultra
+
+      Synchronous negotiation is enabled for all target devices and the host
+      adapter will attempt to negotiate for 20.0 mega-transfers/second.
+
+    Synchronous Negotiation: Fast
+
+      Synchronous negotiation is enabled for all target devices and the host
+      adapter will attempt to negotiate for 10.0 mega-transfers/second.
+
+    Synchronous Negotiation: Slow
+
+      Synchronous negotiation is enabled for all target devices and the host
+      adapter will attempt to negotiate for 5.0 mega-transfers/second.
+
+    Synchronous Negotiation: Disabled
+
+      Synchronous negotiation is disabled and all target devices are limited to
+      asynchronous operation.
+
+    Synchronous Negotiation: UFSNUUU#UUUUUUUU
+
+      Synchronous negotiation to Ultra speed is enabled for target devices 0
+      and 4 through 15, to Fast speed for target device 1, to Slow speed for
+      target device 2, and is not permitted to target device 3.  The host
+      adapter's SCSI ID is represented by the "#".
+
+    The status of Wide Negotiation, Disconnect/Reconnect, and Tagged Queuing
+    are reported as "Enabled", Disabled", or a sequence of "Y" and "N" letters.
+
+    The Error Recovery option is reported as "Default", "Hard Reset",
+    "Bus Device Reset", "None" or a sequence of "D", "H", "B", and "N" letters.
 
 o Performance Features
 
@@ -103,16 +143,15 @@
   addition, BusLogic's Strict Round Robin Mode is used to optimize host adapter
   performance, and scatter/gather I/O can support as many segments as can be
   effectively utilized by the Linux I/O subsystem.  Control over the use of
-  tagged queuing for each target device as well as selection of the tagged
-  queue depth is available from the kernel command line.  By default, the queue
-  depth is automatically determined based on the number, type, speed, and
-  capabilities of the target devices found.  In addition, tagged queuing is
-  automatically disabled whenever the host adapter firmware version is known
-  not to implement it correctly, or whenever a tagged queue depth of 1 is
-  selected.  Tagged queuing is also disabled for individual target devices if
-  disconnect/reconnect is disabled for that device.  In performance testing,
-  sustained disk writes of 7.3MB per second have been observed to a /dev/sd
-  device.
+  tagged queuing for each target device as well as individual selection of the
+  tagged queue depth is available through driver options provided on the kernel
+  command line or at module initialization time.  By default, the queue depth
+  is determined automatically based on the host adapter's total queue depth and
+  the number, type, speed, and capabilities of the target devices found.  In
+  addition, tagged queuing is automatically disabled whenever the host adapter
+  firmware version is known not to implement it correctly, or whenever a tagged
+  queue depth of 1 is selected.  Tagged queuing is also disabled for individual
+  target devices if disconnect/reconnect is disabled for that device.
 
 o Robustness Features
 
@@ -121,15 +160,15 @@
   a selection is made between a full host adapter hard reset and SCSI bus reset
   versus sending a bus device reset message to the individual target device
   based on the recommendation of the SCSI subsystem.  Error recovery strategies
-  are selectable from the kernel command line individually for each target
-  device, and also include sending a bus device reset to the specific target
-  device associated with the command being reset, as well as suppressing error
+  are selectable through driver options individually for each target device,
+  and also include sending a bus device reset to the specific target device
+  associated with the command being reset, as well as suppressing error
   recovery entirely to avoid perturbing an improperly functioning device.  If
   the bus device reset error recovery strategy is selected and sending a bus
   device reset does not restore correct operation, the next command that is
   reset will force a full host adapter hard reset and SCSI bus reset.  SCSI bus
   resets caused by other devices and detected by the host adapter are also
-  handled by issuing a hard reset to the host adapter and re-initialization.
+  handled by issuing a soft reset to the host adapter and re-initialization.
   Finally, if tagged queuing is active and more than one command reset occurs
   in a 10 minute interval, or if a command reset occurs within the first 10
   minutes of operation, then tagged queuing will be disabled for that target
@@ -138,15 +177,6 @@
   lock up or crash, and thereby allowing a clean shutdown and restart after the
   offending component is removed.
 
-o Extensive Testing
-
-  This driver has undergone extensive testing and improvement over a period of
-  several months, and is routinely being used on heavily loaded systems.  Over
-  300 people retrieved the driver during the beta test period.  In addition to
-  testing in normal system operation, error recovery tests have been performed
-  to verify proper system recovery in the case of simulated dropped interrupts,
-  external SCSI bus resets, and SCSI command errors due to bad CD-ROM media.
-
 o PCI Configuration Support
 
   On PCI systems running kernels compiled with PCI BIOS support enabled, this
@@ -159,8 +189,8 @@
 
 o /proc File System Support
 
-  Copies of the host adapter configuration information together with data
-  transfer and error recovery statistics are now available through the
+  Copies of the host adapter configuration information together with updated
+  data transfer and error recovery statistics are available through the
   /proc/scsi/BusLogic/<N> interface.
 
 o Shared Interrupts Support
@@ -168,16 +198,6 @@
   On systems that support shared interrupts, any number of BusLogic Host
   Adapters may share the same interrupt request channel.
 
-o Wide SCSI Support
-
-  All BusLogic MultiMaster SCSI Host Adapters share a common programming
-  interface, except for the inevitable improvements and extensions as new
-  models are released, so support for Wide SCSI data transfer has automatically
-  been available without explicit driver support.  When used with Linux 2.0.x,
-  this driver adds explicit support for up to 15 target devices and 64 logical
-  units per target device, to fully exploit the capabilities of the newest
-  BusLogic Wide SCSI Host Adapters.
-
 
 			    SUPPORTED HOST ADAPTERS
 
@@ -188,16 +208,21 @@
 
 FlashPoint Series PCI Host Adapters:
 
-FlashPoint LT (BT-930)	Ultra SCSI-2
-FlashPoint DL (BT-932)	Dual Channel Ultra SCSI-2
-FlashPoint LW (BT-950)	Wide Ultra SCSI-2
-FlashPoint DW (BT-952)	Dual Channel Wide Ultra SCSI-2
+FlashPoint LT (BT-930)	Ultra SCSI-3
+FlashPoint LT (BT-930R)	Ultra SCSI-3 with RAIDPlus
+FlashPoint LT (BT-920)	Ultra SCSI-3 (BT-930 without BIOS)
+FlashPoint DL (BT-932)	Dual Channel Ultra SCSI-3
+FlashPoint DL (BT-932R)	Dual Channel Ultra SCSI-3 with RAIDPlus
+FlashPoint LW (BT-950)	Wide Ultra SCSI-3
+FlashPoint LW (BT-950R)	Wide Ultra SCSI-3 with RAIDPlus
+FlashPoint DW (BT-952)	Dual Channel Wide Ultra SCSI-3
+FlashPoint DW (BT-952R)	Dual Channel Wide Ultra SCSI-3 with RAIDPlus
 
 MultiMaster "W" Series Host Adapters:
 
-BT-948	    PCI		Ultra SCSI-2
-BT-958	    PCI		Wide Ultra SCSI-2
-BT-958D	    PCI		Wide Differential Ultra SCSI-2
+BT-948	    PCI		Ultra SCSI-3
+BT-958	    PCI		Wide Ultra SCSI-3
+BT-958D	    PCI		Wide Differential Ultra SCSI-3
 
 MultiMaster "C" Series Host Adapters:
 
@@ -231,6 +256,39 @@
 AMI FastDisk Host Adapters that are true BusLogic MultiMaster clones are also
 supported by this driver.
 
+BusLogic SCSI Host Adapters are available packaged both as bare boards and as
+retail kits.  The BT- model numbers above refer to the bare board packaging.
+The retail kit model numbers are found by replacing BT- with KT- in the above
+list.  The retail kit includes the bare board and manual as well as cabling and
+driver media and documentation that are not provided with bare boards.
+
+
+			 FLASHPOINT INSTALLATION NOTES
+
+o RAIDPlus Support
+
+  FlashPoint Host Adapters now include RAIDPlus, Mylex's bootable software
+  RAID.  RAIDPlus is not supported on Linux, and there are no plans to support
+  it.  The MD driver in Linux 2.0 provides for concatenation (LINEAR) and
+  striping (RAID-0), and support for mirroring (RAID-1), fixed parity (RAID-4),
+  and distributed parity (RAID-5) is available separately.  The built-in Linux
+  RAID support is generally more flexible and is expected to perform better
+  than RAIDPlus, so there is little impetus to include RAIDPlus support in the
+  BusLogic driver.
+
+o Enabling UltraSCSI Transfers
+
+  FlashPoint Host Adapters ship with their configuration set to "Factory
+  Default" settings that are conservative and do not allow for UltraSCSI speed
+  to be negotiated.  This results in fewer problems when these host adapters
+  are installed in systems with cabling or termination that is not sufficient
+  for UltraSCSI operation, or where existing SCSI devices do not properly
+  respond to synchronous transfer negotiation for UltraSCSI speed.  AutoSCSI
+  may be used to load "Optimum Performance" settings which allow UltraSCSI
+  speed to be negotiated with all devices, or UltraSCSI speed can be enabled on
+  an individual basis.  It is recommended that SCAM be manually disabled after
+  the "Optimum Performance" settings are loaded.
+
 
 		      BT-948/958/958D INSTALLATION NOTES
 
@@ -284,113 +342,258 @@
   so as to recognize the host adapters in the same order as they are enumerated
   by the host adapter's BIOS.
 
-o Mega-Transfers/Second
+o Enabling UltraSCSI Transfers
+
+  The BT-948/958/958D ship with their configuration set to "Factory Default"
+  settings that are conservative and do not allow for UltraSCSI speed to be
+  negotiated.  This results in fewer problems when these host adapters are
+  installed in systems with cabling or termination that is not sufficient for
+  UltraSCSI operation, or where existing SCSI devices do not properly respond
+  to synchronous transfer negotiation for UltraSCSI speed.  AutoSCSI may be
+  used to load "Optimum Performance" settings which allow UltraSCSI speed to be
+  negotiated with all devices, or UltraSCSI speed can be enabled on an
+  individual basis.  It is recommended that SCAM be manually disabled after the
+  "Optimum Performance" settings are loaded.
+
+
+				DRIVER OPTIONS
+
+BusLogic Driver Options may be specified either via the Linux Kernel Command
+Line or via the Loadable Kernel Module Installation Facility.  Driver Options
+for multiple host adapters may be specified either by separating the option
+strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
+command line.  Individual option specifications for a single host adapter are
+separated by commas.  The Probing and Debugging Options apply to all host
+adapters whereas the remaining options apply individually only to the
+selected host adapter.
+
+The BusLogic Driver Probing Options comprise the following:
+
+IO:<integer>
+
+  The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI
+  MultiMaster Host Adapter.  If neither "IO:" nor "NoProbeISA" options are
+  specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses
+  will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134).  Multiple
+  "IO:" options may be specified to precisely determine the I/O Addresses to
+  be probed, but the probe order will always follow the standard list.
+
+NoProbe
+
+  The "NoProbe" option disables all probing and therefore no BusLogic Host
+  Adapters will be detected.
+
+NoProbeISA
+
+  The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O
+  Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters
+  will be detected.
 
-  The driver reports on the synchronous transfer parameters negotiated between
-  the host adapter and target devices in units of "mega-transfers/second".  For
-  wide devices, the unit of transfer is 16 bits if wide negotiation has been
-  successfully completed.  Therefore, the total transfer rate to wide devices
-  will generally be twice the synchronous tranfer rate reported by the driver.
+NoProbePCI
 
+  The "NoProbePCI" options disables the interrogation of PCI Configuration
+  Space and therefore only ISA Multimaster Host Adapters will be detected, as
+  well as PCI Multimaster Host Adapters that have their ISA Compatible I/O
+  Port set to "Primary" or "Alternate".
 
-			     COMMAND LINE OPTIONS
+NoSortPCI
 
-Many features of this driver are configurable by specification of appropriate
-kernel command line options.  A full description of the command line options
-may be found in the comments before BusLogic_Setup in the kernel source code
-file "BusLogic.c".  The following examples may be useful as a starting point:
+  The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be
+  enumerated in the order provided by the PCI BIOS, ignoring any setting of
+  the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
 
-  "BusLogic=NoProbe"
+MultiMasterFirst
 
-    No probing of any kind is to be performed, and hence no BusLogic Host
-    Adapters will be detected.
+  The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed
+  before FlashPoint Host Adapters.  By default, if both FlashPoint and PCI
+  MultiMaster Host Adapters are present, this driver will probe for
+  FlashPoint Host Adapters first unless the BIOS primary disk is controlled
+  by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host
+  Adapters will be probed first.
 
-  "BusLogic=NoProbeISA"
+FlashPointFirst
 
-    No probing of the standard ISA I/O Addresses will be done, and hence only
-    PCI Host Adapters will be detected.
+  The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed
+  before MultiMaster Host Adapters.
 
-  "BusLogic=NoProbePCI"
+The BusLogic Driver Tagged Queuing Options allow for explicitly specifying
+the Queue Depth and whether Tagged Queuing is permitted for each Target
+Device (assuming that the Target Device supports Tagged Queuing).  The Queue
+Depth is the number of SCSI Commands that are allowed to be concurrently
+presented for execution (either to the Host Adapter or Target Device).  Note
+that explicitly enabling Tagged Queuing may lead to problems; the option to
+enable or disable Tagged Queuing is provided primarily to allow disabling
+Tagged Queuing on Target Devices that do not implement it correctly.  The
+following options are available:
 
-    No interrogation of PCI Configuration Space will be made, and hence only
-    ISA Multimaster Host Adapters will be detected, as well as PCI Multimaster
-    Host Adapters that have their ISA Compatible I/O Port set to "Primary" or
-    "Alternate".
+QueueDepth:<integer>
 
-  "BusLogic=NoSortPCI"
+  The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
+  Target Devices that support Tagged Queuing, as well as the maximum Queue
+  Depth for devices that do not support Tagged Queuing.  If no Queue Depth
+  option is provided, the Queue Depth will be determined automatically based
+  on the Host Adapter's Total Queue Depth and the number, type, speed, and
+  capabilities of the detected Target Devices.  For Host Adapters that
+  require ISA Bounce Buffers, the Queue Depth is automatically set by default
+  to BusLogic_TaggedQueueDepthBB or BusLogic_UntaggedQueueDepthBB to avoid
+  excessive preallocation of DMA Bounce Buffer memory.  Target Devices that
+  do not support Tagged Queuing always have their Queue Depth set to
+  BusLogic_UntaggedQueueDepth or BusLogic_UntaggedQueueDepthBB, unless a
+  lower Queue Depth option is provided.  A Queue Depth of 1 automatically
+  disables Tagged Queuing.
 
-    PCI MultiMaster Host Adapters will be enumerated in the order provided by
-    the PCI BIOS, ignoring any setting of the AutoSCSI "Use Bus And Device #
-    For PCI Scanning Seq." option.
+QueueDepth:[<integer>,<integer>...]
 
-  "BusLogic=MultiMasterFirst"
+  The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth
+  individually for each Target Device.  If an <integer> is omitted, the
+  associated Target Device will have its Queue Depth selected automatically.
 
-    By default, if both FlashPoint and PCI MultiMaster Host Adapters are
-    present, this driver will probe for FlashPoint Host Adapters first unless
-    the BIOS primary disk is controlled by the first PCI MultiMaster Host
-    Adapter, in which case MultiMaster Host Adapters will be probed first.
-    This option forces MultiMaster Host Adapters to be probed first.
+TaggedQueuing:Default
 
-  "BusLogic=FlashPointFirst"
+  The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing
+  based on the firmware version of the BusLogic Host Adapter and based on
+  whether the Queue Depth allows queuing multiple commands.
 
-    By default, if both FlashPoint and PCI MultiMaster Host Adapters are
-    present, this driver will probe for FlashPoint Host Adapters first unless
-    the BIOS primary disk is controlled by the first PCI MultiMaster Host
-    Adapter, in which case MultiMaster Host Adapters will be probed first.
-    This option forces FlashPoint Host Adapters to be probed first.
+TaggedQueuing:Enable
 
-  "BusLogic=0x330"
+  The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for
+  all Target Devices on this Host Adapter, overriding any limitation that
+  would otherwise be imposed based on the Host Adapter firmware version.
 
-    This command line limits probing to the single I/O port at 0x330.
+TaggedQueuing:Disable
 
-  "BusLogic=0,1"
+  The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing
+  for all Target Devices on this Host Adapter.
 
-    This command line selects default probing and a tagged queue depth of 1
-    which also disables tagged queuing.  It may be useful if problems arise
-    during installation on a system with a flaky SCSI configuration.  In cases
-    of a marginal SCSI configuration it may also be beneficial to disable fast
-    transfers and/or synchronous negotiation using AutoSCSI on FlashPoint and
-    "W" and "C" series MultiMaster host adapters.  Disconnect/reconnect may
-    also be disabled for fast devices such as disk drives, but should not be
-    disabled for tape drives or other devices where a single command may take
-    over a second to execute.
+TaggedQueuing:<Target-Spec>
 
-  "BusLogic=0,0,30"
+  The "TaggedQueuing:<Target-Spec>" or "TQ:<Target-Spec>" option controls
+  Tagged Queuing individually for each Target Device.  <Target-Spec> is a
+  sequence of "Y", "N", and "X" characters.  "Y" enables Tagged Queuing, "N"
+  disables Tagged Queuing, and "X" accepts the default based on the firmware
+  version.  The first character refers to Target Device 0, the second to
+  Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters
+  does not cover all the Target Devices, unspecified characters are assumed
+  to be "X".
 
-    This command line selects default probing and automatic tagged queue depth
-    selection, but changes the bus settle time to 30 seconds.  It may be useful
-    with SCSI devices that take an unusually long time to become ready to
-    accept commands after a SCSI bus reset.  Some tape drives will not respond
-    properly immediately after a SCSI bus reset, especially if a tape is
-    present in the drive.
+The BusLogic Driver Error Recovery Option allows for explicitly specifying
+the Error Recovery action to be performed when BusLogic_ResetCommand is
+called due to a SCSI Command failing to complete successfully.  The following
+options are available:
 
-  "BusLogic=TQ:Disable"
+ErrorRecovery:Default
 
-    This command line selects default probing and disables tagged queuing.
+  The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard
+  Reset and Bus Device Reset options based on the recommendation of the SCSI
+  Subsystem.
 
-  "BusLogic=0,15,TQ:N"
+ErrorRecovery:HardReset
 
-    This command line selects a tagged queue depth of 15 and disables tagged
-    queuing for target 0, while allowing tagged queuing for all other target
-    devices.
+  The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host
+  Adapter Hard Reset which also causes a SCSI Bus Reset.
 
-Note that limiting the tagged queue depth or disabling tagged queuing can
-substantially impact performance.
+ErrorRecovery:BusDeviceReset
 
+  The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send
+  a Bus Device Reset message to the individual Target Device causing the
+  error.  If Error Recovery is again initiated for this Target Device and no
+  SCSI Command to this Target Device has completed successfully since the Bus
+  Device Reset message was sent, then a Hard Reset will be attempted.
 
-				 INSTALLATION
+ErrorRecovery:None
 
-This distribution was prepared for Linux kernel version 2.0.30, but should be
-compatible with 2.0.4 or any later 2.0 series kernel if BusLogic.patch is also
-applied.
+  The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery.
+  This option should only be selected if a SCSI Bus Reset or Bus Device Reset
+  will cause the Target Device or a critical operation to suffer a complete
+  and unrecoverable failure.
+
+ErrorRecovery:<Target-Spec>
+
+  The "ErrorRecovery:<Target-Spec>" or "ER:<Target-Spec>" option controls
+  Error Recovery individually for each Target Device.  <Target-Spec> is a
+  sequence of "D", "H", "B", and "N" characters.  "D" selects Default, "H"
+  selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None.
+  The first character refers to Target Device 0, the second to Target Device
+  1, and so on; if the sequence of "D", "H", "B", and "N" characters does not
+  cover all the possible Target Devices, unspecified characters are assumed
+  to be "D".
+
+The BusLogic Driver Miscellaneous Options comprise the following:
+
+BusSettleTime:<seconds>
+
+  The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in
+  seconds.  The Bus Settle Time is the amount of time to wait between a Host
+  Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI
+  Commands.  If unspecified, it defaults to BusLogic_DefaultBusSettleTime.
+
+InhibitTargetInquiry
+
+  The "InhibitTargetInquiry" option inhibits the execution of an Inquire
+  Target Devices or Inquire Installed Devices command on MultiMaster Host
+  Adapters.  This may be necessary with some older Target Devices that do not
+  respond correctly when Logical Units above 0 are addressed.
+
+The BusLogic Driver Debugging Options comprise the following:
+
+TraceProbe
+
+  The "TraceProbe" option enables tracing of Host Adapter Probing.
+
+TraceHardwareReset
+
+  The "TraceHardwareReset" option enables tracing of Host Adapter Hardware
+  Reset.
+
+TraceConfiguration
+
+  The "TraceConfiguration" option enables tracing of Host Adapter
+  Configuration.
+
+TraceErrors
+
+  The "TraceErrors" option enables tracing of SCSI Commands that return an
+  error from the Target Device.  The CDB and Sense Data will be printed for
+  each SCSI Command that fails.
+
+Debug
+
+  The "Debug" option enables all debugging options.
+
+The following examples demonstrate setting the Queue Depth for Target Devices
+1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target
+Devices on the second host adapter to 31, and the Bus Settle Time on the
+second host adapter to 30 seconds.
+
+Linux Kernel Command Line:
+
+  linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30
+
+LILO Linux Boot Loader (in /etc/lilo.conf):
+
+  append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"
+
+INSMOD Loadable Kernel Module Installation Facility:
+
+  insmod BusLogic.o \
+      'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"'
+
+NOTE: Module Utilities 2.1.71 or later is required for correct parsing
+      of driver options containing commas.
+
+
+			      DRIVER INSTALLATION
+
+This distribution was prepared for Linux kernel version 2.0.33, but should be
+compatible with 2.0.4 or any later 2.0 series kernel.
 
 To install the new BusLogic SCSI driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf BusLogic-2.0.10.tar.gz
+  tar -xvzf BusLogic-2.0.14.tar.gz
   mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
-  patch -p < BusLogic.patch	    # Only for kernels prior to 2.0.30
+  patch -p < BusLogic.patch
   cd linux
   make config
   make depend
@@ -398,11 +601,6 @@
 
 Then install "arch/i386/boot/zImage" as your standard kernel, run lilo if
 appropriate, and reboot.
-
-Be sure to answer "y" to the "BusLogic SCSI support" query during the "make
-config" step.  If your system was already configured for the old BusLogic
-driver or for an older version of this driver, you may omit the "make config"
-step above.
 
 
 		      BUSLOGIC ANNOUNCEMENTS MAILING LIST
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/README.Mylex linux/drivers/scsi/README.Mylex
--- v2.0.33/linux/drivers/scsi/README.Mylex	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/README.Mylex	Wed Jun  3 15:17:48 1998
@@ -0,0 +1,6 @@
+Please see the file README.BusLogic for information about Linux support for
+Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters.
+
+The Mylex DAC960 PCI RAID Controllers are not supported at the present time,
+but work on a Linux driver for the DAC960 is in progress.  Please consult
+http://www.dandelion.com/Linux/ for further information on the DAC960 driver.
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v2.0.33/linux/drivers/scsi/README.aic7xxx	Sat Apr 20 10:59:10 1996
+++ linux/drivers/scsi/README.aic7xxx	Wed Jun  3 15:17:48 1998
@@ -1,8 +1,7 @@
 			    AIC7xxx Driver for Linux
-				 April 15, 1996
 
 Introduction
-------------------------
+----------------------------
 The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
 SCSI controllers and chipsets. Major portions of the driver and driver
 development are shared between both Linux and FreeBSD. Support for the
@@ -11,31 +10,42 @@
 2.1.0 or later.
 
   Supported cards/chipsets
-  ------------------------
+  ----------------------------
     Adaptec Cards
-    -----------------------
-    AHA-274x               
-    AHA-2842               
+    ----------------------------
+    AHA-274x
+    AHA-274xT               
+    AHA-2842
+    AHA-2910B               
     AHA-2940               
     AHA-2940W              
     AHA-2940U              
-    AHA-2940UW             
+    AHA-2940UW
+    AHA-2940AU             
     AHA-2944D              
     AHA-2944WD
+    AHA-2944UD
+    AHA-2944UWD
     AHA-3940
+    AHA-3940U
     AHA-3940W
+    AHA-3940UW
     AHA-3985
+    AHA-3985U
     AHA-3985W
+    AHA-3985UW
 
     Motherboard Chipsets
-    -----------------------
+    ----------------------------
     AIC-777x   
     AIC-785x
+    AIC-786x
     AIC-787x
     AIC-788x
+    AIC-7895
 
     Bus Types
-    -----------------------
+    ----------------------------
     W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
         SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
     U - Ultra SCSI, transfer rates up to 40MB/s.
@@ -49,22 +59,28 @@
     AHA-398x - PCI RAID controllers with three separate SCSI controllers
                on-board.
 
-    NOTE: The AHA-2920 is NOT a AIC-7xxx based controller, and is not
+    NOTE: The AHA-2920 is NOT an AIC-7xxx based controller, and is not
           handled by this driver.
 
   People
-  ------------------------
-    Justin T Gibbs  gibbs@freefall.FreeBSD.org     (BSD Driver Author)
-    Dan Eischen     deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
-    Dean Gehnert    deang@teleport.com             (Linux FTP/patch maintainer)
-    Jess Johnson    jester@frenzy.com              (AIC7xxx FAQ author)
-
+  ------------------------------
+    Justin T Gibbs  gibbs@plutotech.com
+      (BSD Driver Author)
+    Dan Eischen     deischen@iworks.InterWorks.org
+      (Original Linux Driver Co-maintainer)
+    Dean Gehnert    deang@teleport.com
+      (Original Linux FTP/patch maintainer)
+    Jess Johnson    jester@frenzy.com
+      (AIC7xxx FAQ author)
+    Doug Ledford    dledford@dialnet.net
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
+    
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
     again for all his work!
-
+    
   Mailing list
-  ------------------------
+  ------------------------------
     There is a mailing list available for users who want to track development
     and converse with other users and developers. This list is for both
     FreeBSD and Linux support of the AIC7xxx chipsets.
@@ -82,13 +98,150 @@
 
     Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
     
-  Command line options
-  ------------------------
+  Boot Command line options
+  ------------------------------
     "aic7xxx=no_reset" -  Eliminate the SCSI reset delay during startup.
         Some SCSI devices need some extra time to reset.
+    "aic7xxx=reverse_scan" - Have the driver register the SCSI cards in the
+        reverse of the normal order.  This may help those people who have more
+        than one PCI Adaptec controller force the correct controller to be
+        scsi0 under linux so that their boot hard drive is also sda under
+        linux
+    "aic7xxx=extended" - Force the driver to detect extended drive translation
+        on your controller.  This helps those people who have cards without
+        a SEEPROM make sure that linux and all other operating systems think
+        the same way about your hard drives.
+    "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+        to use the correct IRQ type for your card.  This only applies to EISA
+        based controllers.  On these controllers, 0 is for Edge triggered
+        interrupts, and 1 is for Level triggered interrupts.  If you aren't
+        sure or don't know which IRQ trigger type your EISA card uses, then
+        let the kernel autodetect the trigger type.
+    "aic7xxx=verbose" - This option can be used in one of two ways.  If you
+        simply specify aic7xxx=verbose, then the kernel will automatically pick
+        the default set of verbose messages for you to see.  Alternatively, you
+        can specify the command as "aic7xxx=verbose:0xXXXX" where the X entries
+        are replaced with hexadecimal digits.  This option is a bit field type
+        option.  For a full listing of the available options, search for the
+        #define VERBOSE_xxxxxx lines in the aic7xxx.c file.  If you want verbose
+        messages, then it is recommended that you simply use the aic7xxx=verbose
+        variant of this command.
+    "aic7xxx=7895_irq_hack:x" - This option enables some work around code to
+        fix a bug in the Tyan Thunder II motherboard BIOS.  The BIOS
+        incorrectly sets the IRQs on the two channels of the 7895 to two
+        different values even though the motherboard hardware doesn't support
+        this mode of operation.  The valid values for x are: 0 to force
+        both channels to use the IRQ assigned to Channel A, 1 to force both
+        channels to use the IRQ assigned to Channel B, and -1 will disable
+        this horrible abomination of a hack.  The default is disabled (-1).
+    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to enable
+        tagged queueing on specific devices.  As of driver version 5.0.6, we
+        now globally enable tagged queueing by default, but we also disable
+        tagged queueing on all individual devices by default.  In order to
+        enable tagged queueing for certian devices at boot time, a user may
+        use this boot param.  The driver will then parse this message out
+        and enable the specific device entries that are present based upon
+        the value given.  The param line is parsed in the following manner:
+
+          { - first instance indicates the start of this parameter values
+              second instance is the start of entries for a particular
+              device entry
+          } - end the entries for a particular host adapter, or end the entire
+              set of parameter entries
+          , - move to next entry.  Inside of a set of device entries, this
+              moves us to the next device on the list.  Outside of device
+              entries, this moves us to the next host adapter
+          . - Same effect as , but is safe to use with insmod.
+          x - the number to enter into the array at this position.  
+              0 = Enable tagged queueing on this device and use the default
+                  queue depth
+              1-254 = Enable tagged queueing on this device and use this
+                      number as the queue depth
+              255 = Disable tagged queueing on this device.
+              Note: anything above 32 for an actual queue depth is wasteful
+                    and not recommended.
+
+        A few examples of how this can be used:
+
+        tag_info:{{8,12,,0,,255,4}}
+          This line will only effect the first aic7xxx card registered.  It
+          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+          at the default, set id 3 to tagged queueing enabled and use the
+          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+          Any not specified entries stay at the default value, repeated
+          commas with no value specified will simply increment to the next id
+          without changing anything for the missing values.
+
+        tag_info:{{8,8},,{8,8}}
+          First adapter, scsi id 0 to 8, id 1 to 8, remainder stay at their
+          default.  Second adapter stays entirely at default.  Third
+          adapter, id 0 to 8, id 1 to 8, remainder at default (identical to
+          first adapter).
+
+        tag_info:{,,,{,,,64}}
+          First, second, and third adapters at default values.  Fourth
+          adapter, id 3 to 64.  Notice that leading commas simply increment
+          what the first number effects, and there are no need for trailing
+          commas.  When you close out an adapter, or the entire entry,
+          anything not explicitly set stays at the default value.
+
+        A final note on this option.  The scanner I used for this isn't
+        perfect or highly robust.  If you mess the line up, the worst that
+        should happen is that the line will get ignored.  If you don't
+        close out the entire entry with the final bracket, then any other
+        aic7xxx options after this will get ignored.  So, in general, be
+        sure of what you are entering, and after you have it right, just
+        add it to the lilo.conf file so there won't be any mistakes.  As
+        a means of checking this parser, the entire tag_info array for
+        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
+        can use that to verify that your options were parsed correctly. 
+        
+    Boot command line options may be combined to form the proper set of options
+    a user might need.  For example, the following is valid:
+    
+    aic7xxx=verbose,extended,irq_trigger:1
+    
+    The only requirement is that individual options be separated by a comma on
+    the command line.
+        
+  Module Loading command options
+  ------------------------------
+    When loading the aic7xxx driver as a module, the exact same options are
+    available to the user.  However, the syntax to specify the options changes
+    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
+    and replace all ',' with '.'.  So, for example, a valid insmod line
+    would be:
+
+    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+    This line should result in the *exact* same behaviour as if you typed
+    it in at the lilo prompt and the driver was compiled into the kernel
+    instead of being a module.  The reason for the single quote is so that
+    the shell won't try to interpret anything in the line, such as {. 
+    Insmod assumes any options starting with a letter instead of a number
+    is a character string (which is what we want) and by switching all of
+    the commas to periods, insmod won't interpret this as more than one
+    string and write junk into our binary image.  I consider it a bug in
+    the insmod program that even if you wrap your string in quotes (quotes
+    that pass the shell mind you and that insmod sees) it still treates
+    a comma inside of those quotes as starting a new variable, resulting
+    in memory scribbles if you don't switch the commas to periods.
+
+
+  Kernel Compile options
+  ------------------------------
+    The various kernel compile time options for this driver are now fairly
+    well documented in the file Documentation/Configure.help.  In order to
+    see this documentation, you need to use one of the advanced configuration
+    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
+    method of configuring your kernel, then you would simply highlight the
+    option in question and hit the F1 key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button next
+    to the option you have questions about.  The help information from the
+    Configure.help file will then get automatically displayed.
 
   /proc support
-  ------------------------
+  ------------------------------
     The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
     directory. That directory contains a file for each SCSI controller in
     the system. Each file presents the current configuration and transfer
@@ -98,12 +251,12 @@
     Matthew Jacob for statistics support.
 
   FTP sites
-  ------------------------
-    ftp://ftp.teleport.com/users/deang/Linux/aic7xxx/
-      - Main Linux AIC7xxx driver release/pre-release site
-      - Experimental/development patches and bootdisks
+  ------------------------------
     ftp://ftp.dialnet.net/pub/linux/aic7xxx/
+      - Primary site for Doug Ledford developed driver releases
       - US Linux mirror of Teleport site
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Dan Eischen's driver distribution area
     ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
       - European Linux mirror of Teleport site
 
@@ -113,3 +266,4 @@
 
 $Revision: 3.0 $
 
+Modified by Doug Ledford 1998
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/README.in2000 linux/drivers/scsi/README.in2000
--- v2.0.33/linux/drivers/scsi/README.in2000	Tue Aug  5 13:26:16 1997
+++ linux/drivers/scsi/README.in2000	Wed Jun  3 15:17:48 1998
@@ -1,4 +1,11 @@
 
+UPDATE NEWS: version 1.32 - 28 Mar 98
+
+   Removed the check for legal IN2000 hardware versions:
+   It appears that the driver works fine with serial
+   EPROMs (the 8-pin chip that defines hardware rev) as
+   old as 2.1, so we'll assume that all cards are OK.
+
 UPDATE NEWS: version 1.31 - 6 Jul 97
 
    Fixed a bug that caused incorrect SCSI status bytes to be
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.0.33/linux/drivers/scsi/README.ncr53c8xx	Thu Aug 14 10:30:08 1997
+++ linux/drivers/scsi/README.ncr53c8xx	Wed Jun  3 15:17:48 1998
@@ -4,7 +4,7 @@
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-19 June 1997
+2 January 1998
 ===============================================================================
 
 1.  Introduction
@@ -30,6 +30,7 @@
       10.3 Advised boot setup commands
       10.4 PCI configuration fix-up boot option
       10.5 Serial NVRAM support boot option
+      10.6 SCSI BUS checking boot option
 11. Some constants and flags of the ncr53c8xx.h header file
 12. Installation
       12.1 Provided files
@@ -38,6 +39,8 @@
 14. Known problems
       14.1 Tagged commands with Iomega Jaz device
       14.2 Device names change when another controller is added
+      14.3 Using only 8 bit devices with a WIDE SCSI controller.
+      14.4 Possible data corruption during a Memory Write and Invalidate
 15. SCSI problem troubleshooting
 16. Synchonous transfer negotiation tables
       16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
@@ -46,6 +49,9 @@
       17.1 Features
       17.2 Symbios NVRAM layout
       17.3 Tekram  NVRAM layout
+18. Support for Big Endian
+      18.1 Big Endian CPU
+      18.2 NCR chip in Big Endian mode of operations
 
 ===============================================================================
 
@@ -83,7 +89,7 @@
 driver, configuration parameters and control commands available
 through the proc SCSI file system read / write operations.
 
-This driver has been tested OK with linux/i386 and Linux/Alpha.
+This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC.
 
 Latest driver version and patches are available at:
 
@@ -429,7 +435,10 @@
 
 CONFIG_SCSI_NCR53C8XX_IOMAPPED       (default answer: n)
     Answer "y" if you suspect your mother board to not allow memory mapped I/O.
-    May slow down performance a little.
+    May slow down performance a little.  This option is required by
+    Linux/PPC and is used no matter what you select here.  Linux/PPC
+    suffers no performance loss with this option since all IO is memory
+    mapped anyway.
 
 CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE    (default answer: n)
     Answer "y" if you are sure that all your SCSI devices that are able to 
@@ -484,7 +493,9 @@
 
 10.1 Syntax
 
-Setup commands can be passed to the driver at boot time.
+Setup commands can be passed to the driver either at boot time or as a 
+string variable using 'insmod'.
+
 A boot setup command for the ncr53c8xx driver begins with the driver name 
 "ncr53c8xx=". The kernel syntax parser then expects an optionnal list of
 integers separated with comma followed by an optionnal list of  comma- 
@@ -496,7 +507,14 @@
 - set synchronous negotiation speed to 10 Mega-transfers / second.
 - set DEBUG_NEGO flag.
 
-For the moment, the integer list of arguments is disgarded by the driver. 
+Since comma seems not to be allowed when defining a string variable using  
+'insmod', the driver also accepts <space> as option separator. 
+The following command will install driver module with the same options as 
+above.
+
+insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
+
+For the moment, the integer list of arguments is discarded by the driver. 
 It will be used in the future in order to allow a per controller setup.
 
 Each string argument must be specified as "keyword:value". Only lower-case 
@@ -519,8 +537,12 @@
 Special features
    Only apply to 810A, 825A, 860 and 875 controllers.
    Have no effect with normal 810 and 825.
-      specf:y    enabled
-      specf:n    disabled
+      specf:y    (or 1) enabled
+      specf:n    (or 0) disabled
+      specf:3           enabled except Memory Write And Invalidate
+   The default driver setup is 'specf:3'. As a consequence, option 'specf:y' 
+   must be specified in the boot setup command to enable Memory Write And 
+   Invalidate.
 
 Ultra SCSI support
    Only apply to 860 and 875 controllers.
@@ -622,6 +644,7 @@
     pcifix:<option bits>
 
     Available option bits:
+        0x0:   No attempt to fix PCI configuration space registers values.
         0x1:   Set PCI cache-line size register if not set.
         0x2:   Set write and invalidate bit in PCI command register.
         0x4:   Increase if necessary PCI latency timer according to burst max.
@@ -632,6 +655,14 @@
     nvram:n     do not look for serial NVRAM
     nvram:y     test controllers for onboard serial NVRAM
 
+Check SCSI BUS 
+    buschk:<option bits>
+
+    Available option bits:
+        0x0:   No check.
+        0x1:   Check and donnot attach the controller on error.  
+        0x2:   Check and just warn on error.
+
 Boot fail safe
     safe:y	load the following assumed fail safe initial setup
 
@@ -654,13 +685,14 @@
   settle time			10 seconds		settle:10
   differential support		from BIOS settings	diff:1
   irq mode			from BIOS settings	irqm:1
+  SCSI BUS check		donnot attach on error	buschk:1
 
 10.3 Advised boot setup commands
 
 If the driver has been configured with default options, the equivalent 
 boot setup is:
 
-   ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
+   ncr53c8xx=mpar:y,spar:y,disc:y,specf:3,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
              tags:0,sync:50,debug:0,burst:7,led:0,wide:1,settle:2,diff:0,irqm:0
 
 For an installation diskette or a safe but not fast system,
@@ -673,7 +705,7 @@
 
 My personnal system works flawlessly with the following equivalent setup:
 
-   ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
+   ncr53c8xx=mpar:y,spar:y,disc:y,specf:1,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
              tags:8,sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0
 
 The driver prints its actual setup when verbosity level is 2. You can try 
@@ -759,6 +791,21 @@
 use its setup for synchronous and wide negotiations.
 
 
+10.6 SCSI BUS checking boot option.
+
+When this option is set to a non-zero value, the driver checks SCSI lines 
+logic state, 100 micro-seconds after having asserted the SCSI RESET line.
+The driver just reads SCSI lines and checks all lines read FALSE except RESET.
+Since SCSI devices shall release the BUS at most 800 nano-seconds after SCSI 
+RESET has been asserted, any signal to TRUE may indicate a SCSI BUS problem.
+Unfortunately, the following common SCSI BUS problems are not detected:
+- Only 1 terminator installed.
+- Misplaced terminators.
+- Bad quality terminators.
+On the other hand, either bad cabling, broken devices, not conformant 
+devices, ... may cause a SCSI signal to be wrong when te driver reads it.
+
+
 11. Some constants and flags of the ncr53c8xx.h header file
 
 Some of these are defined from the configuration parameters.  To
@@ -946,6 +993,50 @@
 - Make appropriate changes in the fstab.
 - Use the 'scsidev' tool from Eric Youngdale.
 
+14.3 Using only 8 bit devices with a WIDE SCSI controller.
+
+When only 8 bit NARROW devices are connected to a 16 bit WIDE SCSI controller, 
+you must ensure that lines of the wide part of the SCSI BUS are pulled-up.
+This can be achieved by ENABLING the WIDE TERMINATOR portion of the SCSI 
+controller card.
+The TYAN 1365 documentation revision 1.2 is not correct about such settings.
+(page 10, figure 3.3).
+
+14.4 Possible data corruption during a Memory Write and Invalidate
+
+This problem is described in SYMBIOS DEL 397, Part Number 69-039241, ITEM 4.
+
+In some complex situations, 53C875 chips revision <= 3 may start a PCI 
+Write and Invalidate Command at a not cache-line-aligned 4 DWORDS boundary.
+This is only possible when Cache Line Size is 8 DWORDS or greater.
+Pentium systems use a 8 DWORDS cache line size and so are concerned by 
+this chip bug, unlike i486 systems that use a 4 DWORDS cache line size.
+
+When this situation occurs, the chip may complete the Write and Invalidate 
+command after having only filled part of the last cache line involved in 
+the transfer, leaving to data corruption the remainder of this cache line.
+
+Not using Write And Invalidate obviously gets rid of this chip bug, and so 
+it is now the default setting of the driver.
+However, for people like me who want to enable this feature, I have added 
+part of a work-around suggested by SYMBIOS. This work-around resets the 
+addressing logic when the DATA IN phase is entered and so prevents the bug 
+from being triggered for the first SCSI MOVE of the phase. This work-around 
+should be enough according to the following:
+
+The only driver internal data structure that is greater than 8 DWORDS  and 
+that is moved by the SCRIPTS processor is the 'CCB header' that contains 
+the context of the SCSI transfer. This data structure is aligned on 8 DWORDS 
+boundary (Pentium Cache Line Size), and so is immune to this chip bug, at 
+least on Pentium systems.
+But the conditions of this bug can be met when a SCSI read command is 
+performed using a buffer that is 4 DWORDS but not cache-line aligned.
+This cannot happen under Linux when scatter/gather lists are used since 
+they only refer to system buffers that are well aligned. So, a work around 
+may only be needed under Linux when a scatter/gather list is not used and 
+when the SCSI DATA IN phase is reentered after a phase mismatch.
+
+ 
 15. SCSI problem troubleshooting
 
 Most SCSI problems are due to a non conformant SCSI bus or to buggy
@@ -1210,8 +1301,14 @@
 controller set up
 
 00 30 00 00 00 00 07 00 00 00 00 00 00 00 07 04 10 04 00 00
-                   |     |                 |
-                   |     |                  -- host ID
+                   |     |           |     |
+                   |     |           |      -- host ID
+                   |     |           |
+                   |     |            --Removable Media Support
+                   |     |               0x00 = none
+                   |     |               0x01 = Bootable Device
+                   |     |               0x02 = All with Media
+                   |     |
                    |      --flag bits 2
                    |        0x00000001= scan order hi->low
                    |            (default 0x00 - scan low->hi)
@@ -1224,6 +1321,7 @@
 current set up for any of the controllers.
 
 default set up is identical for 53c810a and 53c875 NVRAM
+(Removable Media added Symbios BIOS version 4.09)
 -----------------------------------------------------------
 boot configuration
 
@@ -1430,8 +1528,29 @@
 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0xfbbc
 
-===============================================================================
-End of NCR53C8XX driver README file
 
+18. Support for Big Endian
 
+The PCI local bus has been primarily designed for x86 architecture.
+As a consequence, PCI devices generally expect DWORDS using little endian 
+byte ordering.
+
+18.1 Big Endian CPU
+
+In order to support NCR chips on a Big Endian architecture the driver has to 
+perform byte reordering each time it is needed. This feature has been 
+added to the driver by Cort <cort@cs.nmt.edu> and is available in driver 
+version 2.5 and later ones. For the moment Big Endian support has only 
+been tested on Linux/PPC (PowerPC).
+
+18.2 NCR chip in Big Endian mode of operations
+
+It can be read in SYMBIOS documentation that some chips support a special 
+Big Endian mode, on paper: 53C815, 53C825A, 53C875, 53C875N, 53C895.
+This mode of operations is not software-selectable, but needs pin named 
+BigLit to be pulled-up. Using this mode, most of byte reorderings should 
+be avoided when the driver is running on a Big Endian CPU.
+Driver version 2.5 is also, in theory, ready for this feature.
 
+===============================================================================
+End of NCR53C8XX driver README file
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/README.ppa linux/drivers/scsi/README.ppa
--- v2.0.33/linux/drivers/scsi/README.ppa	Mon Apr  8 05:47:34 1996
+++ linux/drivers/scsi/README.ppa	Wed Jun  3 15:17:48 1998
@@ -1,4 +1,5 @@
 README.ppa (c) 1996   Grant R. Guenther,  grant@torque.net
+README.ppa (c) 1998   David J. Campbell,  campbell@torque.net
 
 
          The IOMEGA PPA3 parallel port SCSI Host Bus Adapter
@@ -37,83 +38,72 @@
 observation that the 'guest' driver loads under DOSemu.  His remark was
 the stimulus that began this project.
 
-The ppa driver can detect and adapt to 4- and 8-bit parallel ports, but 
-there is currently no support for EPP or ECP ports, as I have been unable 
-to make the DOS drivers work in these modes on my test rig.
-
-The driver may be built in to the kernel, or loaded as a module.  It
-may be configured on the command line in both cases, although the syntax
-is different.  It may also be configured by editing the source file.
+For information about using the ZIP drive, please read the generic
+instructions in the SCSI-HOWTO and the man pages for the normal disk
+management tools,  fdisk, mkfs, mount, umount, etc.  There is a mini-HOWTO
+circulating concerning the use of the normal SCSI version of the ZIP
+drive, most of its comments will apply to disks connected through the
+ppa driver as well.
 
-Built-in drivers accept parameters using this LILO/LOADLIN command line
-syntax (omitted parameters retain their default values):
+>------------------------------------------------------------------------<
+David Campbell writes:
 
-        ppa=base[,speed_high[,speed_low[,nybble]]]
+Since the original was released by Grant several people have made many minor
+modifications:
 
-For example:    ppa=0x378,0,3
+	a) Support for EPP
+	b) Autoprobing known parallel ports
+	c) Parallel port sharing with other devices (see notes)
 
-If a driver is loaded as a module the parameters may be set on the
-insmod command line, but each one must be specified by name:
+It has been found that the JAZ Traveller also uses the VPI0 interface chipset
+(a reworked ppa3). This driver will also support this device without
+modifications.
 
-For example:    insmod ppa.o ppa_base=0x378 ppa_nybble=1
+Please note that the ZIP Plus drive uses a VPI2 interface chipset (VPI1 never
+made it out of the Iomega development lab). A driver for this device exists,
+check my web page at http://www.torque.net/~campbell for further details.
 
-(Notice the ppa_ prefix on each of the parameters in the insmod form.)
-
-Here are the parameters and their functions:
-
-Variable        Default    Description
-
-ppa_base        0x378   The base address of PPA's parallel port.
-ppa_speed_high  1       Microsecond i/o delay used in data transfers
-ppa_speed_low   6       Microsecond delay used in other operations
-ppa_nybble      0       1 to force the driver to use 4-bit mode.
-
-A word about the timing parameters:  the ppa_speed_low parameter controls 
-the widths of a large number of pulses that are sent over the parallel bus, 
-the narrower the pulses, the faster things go, but the greater the risk of 
-distortion by noise damping circuits in the parallel ports.  The 
-ppa_speed_high parameter controls the same delays, but during the data 
-transfer phase only.   In this phase, there is a lot of handshaking going 
-on and the pulse shaping should not be so much of an issue, but if you 
-see data corruption, you can increase this parameter as well.
-
-You might also want to reduce the timing values to attempt to increase
-the transfer rates on your system.  Please be careful to watch for
-SCSI timeout errors in your log files.  If you are getting timeouts, you
-have set these parameters too low.  The default values appear to be
-safe on most machines.
-
-If you have both the lp and ppa drivers in your kernel, you must ensure
-that they access different parallel ports.  By default, the lp driver is
-initialised early in the booting process, and it claims all parallel
-ports that it can find.  You may control this behaviour with a LILO or
-LOADLIN command line argument of the form:
+                                 -<-->-
 
-        lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]]
+Built-in drivers accept parameters using this LILO/LOADLIN command line
+syntax (omitted parameters retain their default values):
 
-For example:    lp=0x278,7
+        ppa=base,mode[,sg_buffer_size]
 
-If you use this method, only the ports named will be adopted by the lp
-driver.  You can disable them all with lp=0 .
+For example:    ppa=0x378,1
 
-So, if you have a printer on 0x3bc and a ZIP drive on 0x278 you would
-give the following options on your boot command:
+The modes are as follows:
+	0       Autodetect mode
+	1       work in standard 4 bit mode
+	2       PS/2 byte mode
+	3       EPP mode, 8 bit
+	4       EPP mode, 16 bit
+	5       EPP mode, 32 bit
+
+If ppa is built as a module there is currently no method of changing the
+operation of the driver. Basically there is no need (unless you have a very
+strange parallel port address).
+
+                                 -<-->-
+
+Using the ZIP drive and a printer either requires two parallel ports (one
+for each device) or use of the parport driver (which can be found in the
+2.1.x kernels).
+
+In the first case compile the lp driver as a module and load it after ppa.
+Alternatively specify which ports the lp driver should use by the LILO/LOADLIN
+options:
+        lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]]
 
-        lp=0x3bc ppa=0x278
+                                 -<-->-
 
-In this case lp would use the polling driver, since an interrupt was not 
-specified.
+Mainboard buggy chipset hall of shame: [information courtesy of Iomega]
 
-If you want to share the same parallel port between a ZIP drive and a
-printer, you should build both the lp and ppa drivers as modules and
-load and unload one or the other as required.  This is clumsy but we
-currently have no protocol for synchronising access to shared parallel
-ports.
+	National Semiconductor PC87306 rev ID 0x70, 0x71
+	Winbond xx837
 
-For information about using the ZIP drive, please read the generic
-instructions in the SCSI-HOWTO and the man pages for the normal disk
-management tools,  fdisk, mkfs, mount, umount, etc.  There is a mini-HOWTO
-circulating concerning the use of the normal SCSI version of the ZIP
-drive, most of its comments will apply to disks connected through the
-ppa driver as well.
+The above chipsets are known to have problems using EPP. Note that the
+National Semicondutor problems only affect early batches of PC87306 which
+should really never made it to market (a run for mainboard developers).
+>------------------------------------------------------------------------<
 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.0.33/linux/drivers/scsi/advansys.c	Thu Nov 14 16:45:57 1996
+++ linux/drivers/scsi/advansys.c	Wed Jun  3 15:17:48 1998
@@ -1,8 +1,10 @@
-/* $Id: advansys.c,v 1.29 1996/11/15 00:45:07 bobf Exp bobf $ */
+/* $Id: advansys.c,v 1.49 1998/01/22 20:19:25 bobf Exp bobf $ */
+#define ASC_VERSION "3.1D"    /* AdvanSys Driver Version */
+
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
- * Copyright (c) 1995-1996 Advanced System Products, Inc.
+ * Copyright (c) 1995-1998 Advanced System Products, Inc.
  * All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -10,40 +12,50 @@
  * code retain the above copyright notice and this comment without
  * modification.
  *
- * The latest version of this driver is available at the AdvanSys
- * FTP and BBS sites listed below.
+ * There is an AdvanSys Linux WWW page at:
+ *  http://www.advansys.com/linux.html
+ *
+ * The latest version of the AdvanSys driver is available at:
+ *  ftp://ftp.advansys.com/pub/linux/linux.tgz
  *
  * Please send questions, comments, bug reports to:
- * bobf@advansys.com (Bob Frey)
- */
-
-/*
- * The driver has been used in the following kernels:
- *  v1.2.13, v1.3.57, v2.0.25, v2.1.9
+ *  bobf@advansys.com (Bob Frey)
  */
-#define ASC_VERSION "2.0"    /* AdvanSys Driver Version */
 
 /*
 
   Documentation for the AdvanSys Driver
 
-  A. Adapters Supported by this Driver
-  B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
-  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
-  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
-  E. Source Comments
-  F. Driver Compile Time Options and Debugging
-  G. Driver LILO Option
-  H. Release History
-  I. Known Problems or Issues
-  J. Credits
-  K. AdvanSys Contact Information
+  A. Linux Kernel Testing
+  B. Adapters Supported by this Driver
+  C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
+  D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
+  E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+  F. Source Comments
+  G. Driver Compile Time Options and Debugging
+  H. Driver LILO Option
+  I. Release History
+  J. Known Problems or Issues
+  K. Credits
+  L. AdvanSys Contact Information
+
+  A. Linux Kernel Testing
+
+     This driver has been tested in the following Linux kernels: v1.2.13,
+     v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases
+     of Linux or the latest Linux kernel versions available when this version
+     of the driver was released. The driver should also work in earlier
+     versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver
+     is included with all Linux kernels. Please refer to sections C, D, and
+     E for instructions on adding or upgrading the AdvanSys driver.
 
-  A. Adapters Supported by this Driver
+  B. Adapters Supported by this Driver
  
      AdvanSys (Advanced System Products, Inc.) manufactures the following
-     Bus-Mastering SCSI-2 Host Adapters for the ISA, EISA, VL, and PCI
-     buses. This Linux driver supports all of these adapters.
+     RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
+     (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
+     buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
+     transfer) SCSI Host Adapters for the PCI bus.
      
      The CDB counts below indicate the number of SCSI CDB (Command
      Descriptor Block) requests that can be stored in the RISC chip
@@ -59,8 +71,9 @@
         ABP920 - Bus-Master PCI (16 CDB)
         ABP930 - Bus-Master PCI (16 CDB) (Footnote 5)
         ABP930U - Bus-Master PCI Ultra (16 CDB)
+        ABP930UA - Bus-Master PCI Ultra (16 CDB)
         ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
-        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
+        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2)
      
      Single Channel Products:
         ABP542 - Bus-Master ISA with floppy (240 CDB)
@@ -70,11 +83,14 @@
         ABP940U - Bus-Master PCI Ultra (240 CDB)
         ABP970 - Bus-Master PCI MAC/PC (240 CDB)
         ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
+        ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB)
      
-     Dual Channel Products:
+     Multi Channel Products:
         ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
         ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
         ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+        ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
+        ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
      
      Footnotes:
        1. This board has been shipped by HP with the 4020i CD-R drive.
@@ -85,7 +101,7 @@
        4. This board has been sold by SIIG as the i542 SpeedMaster.
        5. This board has been sold by SIIG as the Fast SCSI Pro PCI.
 
-  B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
+  C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
      but precede v1.3.57 some of the changes for Linux v1.3.X listed
@@ -156,7 +172,7 @@
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
  
-  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
+  D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.3.57. For versions that precede v1.3.57
      some of these changes may need to be modified or eliminated. A patch
@@ -222,7 +238,7 @@
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
 
-  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+  E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
 
      To upgrade the AdvanSys driver in a Linux v1.3.58 and newer
      kernel, first check the version of the current driver. The
@@ -236,7 +252,7 @@
      copy the new advansys.c and advansys.h to drivers/scsi, rebuild
      the kernel, and install the new kernel. No other changes are needed.
 
-  E. Source Comments
+  F. Source Comments
  
      1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
  
@@ -250,8 +266,9 @@
            --- Linux Version
            --- Linux Include Files 
            --- Driver Options
-           --- Asc Library Constants and Macros
            --- Debugging Header
+           --- Asc Library Constants and Macros
+           --- Adv Library Constants and Macros
            --- Driver Constants and Macros
            --- Driver Structures
            --- Driver Data
@@ -260,28 +277,50 @@
            --- Loadable Driver Support
            --- Miscellaneous Driver Functions
            --- Functions Required by the Asc Library
+           --- Functions Required by the Adv Library
            --- Tracing and Debugging Functions
            --- Asc Library Functions
+           --- Adv Library Functions
  
      3. The string 'XXX' is used to flag code that needs to be re-written
         or that contains a problem that needs to be addressed.
  
      4. I have stripped comments from and reformatted the source for the
-        Asc Library which is included in this file. I haven't done this
-        to obfuscate the code. Actually I have done this to deobfuscate
-        the code. The Asc Library source can be found under the following
-        headings.
+        Asc Library and Adv Library to reduce the size of this file. This
+        source can be found under the following headings. The Asc Library
+        is used to support Narrow Boards. The Adv Library is used to
+        support Wide Boards.
  
            --- Asc Library Constants and Macros
+           --- Adv Library Constants and Macros
            --- Asc Library Functions
+           --- Adv Library Functions
  
-  F. Driver Compile Time Options and Debugging
+  G. Driver Compile Time Options and Debugging
  
      In this source file the following constants can be defined. They are
      defined in the source below. Both of these options are enabled by
      default.
  
-     1. ADVANSYS_DEBUG - enable for debugging and assertions
+     1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
+
+        Enabling this option adds assertion logic statements to the
+        driver. If an assertion fails a message will be displayed to
+        the console, but the system will continue to operate. Any
+        assertions encountered should be reported to the person
+        responsible for the driver. Assertion statements may proactively
+        detect problems with the driver and facilitate fixing these
+        problems. Enabling assertions will add a small overhead to the
+        execution of the driver.
+
+     2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
+
+        Enabling this option adds tracing functions to the driver and
+        the ability to set a driver tracing level at boot time. This
+        option will also export symbols not required outside the driver to
+        the kernel name space. This option is very useful for debugging
+        the driver, but it will add to the size of the driver execution
+        image and add overhead to the execution of the driver.
  
         The amount of debugging output can be controlled with the global
         variable 'asc_dbglvl'. The higher the number the more output. By
@@ -289,7 +328,7 @@
         
         If the driver is loaded at boot time and the LILO Driver Option
         is included in the system, the debug level can be changed by
-        specifying a 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. The
+        specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
         first three hex digits of the pseudo I/O Port must be set to
         'deb' and the fourth hex digit specifies the debug level: 0 - F.
         The following command line will look for an adapter at 0x330
@@ -319,9 +358,15 @@
  
         I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c
         prevents most level 1 debug messages from being lost.
+
+     3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
  
-     2. ADVANSYS_STATS - enable statistics
- 
+        Enabling this option adds statistics collection and display
+        through /proc to the driver. The information is useful for
+        monitoring driver and device performance. It will add to the
+        size of the driver execution image and add minor overhead to
+        the execution of the driver.
+
         Statistics are maintained on a per adapter basis. Driver entry
         point call counts and transfer size counts are maintained.
         Statistics are only available for kernels greater than or equal
@@ -338,8 +383,7 @@
         When ADVANSYS_STATS is not defined the AdvanSys /proc files only
         contain adapter and device configuration information.
 
-
-  G. Driver LILO Option
+  H. Driver LILO Option
  
      If init/main.c is modified as described in the 'Directions for Adding
      the AdvanSys Driver to Linux' section (B.4.) above, the driver will
@@ -365,12 +409,12 @@
 
            insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
 
-     If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_BOARD_SUPPORTED + 1)
+     If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
      I/O Port may be added to specify the driver debug level. Refer to
      the 'Driver Compile Time Options and Debugging' section above for
      more information.
 
-  H. Release History
+  I. Release History
 
      BETA-1.0 (12/23/95): 
          First Release
@@ -464,7 +508,7 @@
             repeat busy or QUEUE FULL status returned by a device.
          2. Incorporate miscellaneous Asc Library bug fixes.
          3. To allow the driver to work in kernels with broken module
-            support set 'cmd_per_lun' if the driver is compile as a
+            support set 'cmd_per_lun' if the driver is compiled as a
             module. This change affects kernels v1.3.89 to present.
          4. Remove PCI BIOS address from the driver banner. The PCI BIOS
             is relocated by the motherboard BIOS and its new address can
@@ -479,13 +523,70 @@
             structures might not have been in DMA-able memory, causing
             device initialization to fail.
 
-  I. Known Problems or Issues
+     2.1 (12/30/96):
+         1. In advansys_reset(), if the request is a synchronous reset
+            request, even if the request serial number has changed, then
+            complete the request.
+         2. Add Asc Library bug fixes including new microcode.
+         3. Clear inquiry buffer before using it.
+         4. Correct ifdef typo.
+
+     2.2 (1/15/97):
+         1. Add Asc Library bug fixes including new microcode.
+         2. Add synchronous data transfer rate information to the
+            adapter /proc file: /proc/scsi/advansys[0...].
+         3. Change ADVANSYS_DEBUG to be disabled by default. This
+            will reduce the size of the driver image, eliminate execution
+            overhead, and remove unneeded symbols from the kernel symbol
+            space that were previously added by the driver.
+         4. Add new compile-time option ADVANSYS_ASSERT for assertion
+            code that used to be defined within ADVANSYS_DEBUG. This
+            option is enabled by default.
+
+     2.8 (5/26/97):
+         1. Change version number to 2.8 to synchronize the Linux driver
+            version numbering with other AdvanSys drivers.
+         2. Reformat source files without tabs to present the same view
+            of the file to everyone regardless of the editor tab setting
+            being used.
+         3. Add Asc Library bug fixes.
+
+     3.1A (1/8/98):
+         1. Change version number to 3.1 to indicate that support for
+            Ultra-Wide adapters (ABP-940UW) is included in this release.
+         2. Add Asc Library (Narrow Board) bug fixes.
+         3. Report an underrun condition with the host status byte set
+            to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
+            causes the underrun condition to be ignored. When Linux defines
+            its own DID_UNDERRUN the constant defined in this file can be
+            removed.
+         4. Add patch to AscWaitTixISRDone().
+         5. Add support for up to 16 different AdvanSys host adapter SCSI
+            channels in one system. This allows four cards with four channels
+            to be used in one system.
+
+     3.1B (1/9/98):
+         1. Handle that PCI register base addresses are not always page
+            aligned even though ioremap() requires that the address argument
+            be page aligned.
+
+     3.1C (1/10/98):
+         1. Update latest BIOS version to 3.1E.
+         2. Don't set microcode SDTR variable at initialization. Instead
+            wait until device capabilities have been detected from an Inquiry
+            command.
+
+     3.1D (1/21/98):
+         1. Improve performance when the driver is compiled as module by
+            allowing up to 64 scatter-gather elements instead of 8.
+
+  J. Known Problems or Issues
 
          1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
             the queue depth flow control code when mid-level SCSI changes
             are included in Linux.
 
-  J. Credits
+  K. Credits
 
      Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
      basis for the Linux v1.3.X changes which were included in the
@@ -494,7 +595,17 @@
      Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
      in advansys_biosparam() which was fixed in the 1.3 release.
 
-  K. AdvanSys Contact Information
+     Erik Ratcliffe <erik@caldera.com> has done testing of the
+     AdvanSys driver in the Caldera releases.
+
+     Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
+     AscWaitTixISRDone() which he found necessary to make the
+     driver work with a SCSI-1 disk.
+
+     Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
+     support in the 3.1A driver.
+
+  L. AdvanSys Contact Information
  
      Mail:                   Advanced System Products, Inc.
                              1150 Ringwood Court
@@ -504,10 +615,11 @@
      Tech Support:           1-800-525-7440/1-408-467-2930
      BBS:                    1-408-383-9540 (14400,N,8,1)
      Interactive FAX:        1-408-383-9753
-     Customer Direct Sales:  1-800-883-1099/1-408-383-5777
+     Customer Direct Sales:  1-800-525-7443/1-408-383-5777
      Tech Support E-Mail:    support@advansys.com
      FTP Site:               ftp.advansys.com (login: anonymous)
      Web Site:               http://www.advansys.com
+
 */
 
 
@@ -516,7 +628,7 @@
  */
 
 /* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
-#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#define ASC_LINUX_VERSION(V, P, S)    (((V) * 65536) + ((P) * 256) + (S))
 
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
@@ -540,9 +652,13 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/malloc.h>
+#include <linux/mm.h>
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 #include <linux/proc_fs.h>
 #endif /* version >= v1.3.0 */
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,23)
+#include <linux/init.h>
+#endif /* version >= v2.1.23 */
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/dma.h>
@@ -557,15 +673,27 @@
 #include "sd.h"
 #include "advansys.h"
 
+/*
+ * If Linux eventually defines a DID_UNDERRUN, the constant here can be
+ * removed. The current value of zero for DID_UNDERRUN results in underrun
+ * conditions being ignored.
+ */
+#define DID_UNDERRUN 0
+
 
 /*
  * --- Driver Options
  */
 
-#define ADVANSYS_DEBUG /* Enable assertions and tracing. */
+/* Enable driver assertions. */
+#define ADVANSYS_ASSERT
+
+/* Enable driver tracing. */
+/*#define ADVANSYS_DEBUG*/
+
 /*
  * Because of no /proc to display them, statistics are disabled
- * for version prior to v1.3.0.
+ * for versions prior to v1.3.0.
  */
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
 #undef ADVANSYS_STATS /* Disable statistics */
@@ -575,12 +703,23 @@
 
 
 /*
+ * --- Debugging Header
+ */
+
+#ifdef ADVANSYS_DEBUG
+#define STATIC
+#else /* ADVANSYS_DEBUG */
+#define STATIC static
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
  * --- Asc Library Constants and Macros
  */
 
 #define ASC_LIB_VERSION_MAJOR  1
 #define ASC_LIB_VERSION_MINOR  22
-#define ASC_LIB_SERIAL_NUMBER  91
+#define ASC_LIB_SERIAL_NUMBER  111
 
 typedef unsigned char uchar;
 
@@ -602,23 +741,23 @@
 #define rushort  REG __u16
 #define ruint    REG __u32
 #define rulong   REG __u32
-#define NULLPTR   ( void *)0
-#define FNULLPTR  ( void dosfar *)0UL
+#define NULLPTR  (void *)0
+#define FNULLPTR (void *)0UL
 #define EOF      (-1)
 #define EOS      '\0'
 #define ERR      (-1)
 #define UB_ERR   (uchar)(0xFF)
 #define UW_ERR   (uint)(0xFFFF)
 #define UL_ERR   (ulong)(0xFFFFFFFFUL)
-#define iseven_word( val )  ( ( ( ( uint )val) & ( uint )0x0001 ) == 0 )
-#define isodd_word( val )   ( ( ( ( uint )val) & ( uint )0x0001 ) != 0 )
-#define toeven_word( val )  ( ( ( uint )val ) & ( uint )0xFFFE )
-#define biton( val, bits )   ((( uint )( val >> bits ) & (uint)0x0001 ) != 0 )
-#define bitoff( val, bits )  ((( uint )( val >> bits ) & (uint)0x0001 ) == 0 )
-#define lbiton( val, bits )  ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) != 0 )
-#define lbitoff( val, bits ) ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) == 0 )
-#define  absh( val )    ( ( val ) < 0 ? -( val ) : ( val ) )
-#define  swapbyte( ch )  ( ( ( (ch) << 4 ) | ( (ch) >> 4 ) ) )
+#define iseven_word(val)  ((((uint)val) & (uint)0x0001) == 0)
+#define isodd_word(val)   ((((uint)val) & (uint)0x0001) != 0)
+#define toeven_word(val)  (((uint)val) & (uint)0xFFFE)
+#define biton(val, bits)   (((uint)(val >> bits) & (uint)0x0001) != 0)
+#define bitoff(val, bits)  (((uint)(val >> bits) & (uint)0x0001) == 0)
+#define lbiton(val, bits)  (((ulong)(val >> bits) & (ulong)0x00000001UL) != 0)
+#define lbitoff(val, bits) (((ulong)(val >> bits) & (ulong)0x00000001UL) == 0)
+#define  absh(val)    ((val) < 0 ? -(val) : (val))
+#define  swapbyte(ch)  ((((ch) << 4) | ((ch) >> 4)))
 #ifndef GBYTE
 #define GBYTE       (0x40000000UL)
 #endif
@@ -628,10 +767,10 @@
 #ifndef KBYTE
 #define KBYTE       (0x400)
 #endif
-#define HI_BYTE(x) ( *( ( __u8 *)(&x)+1 ) )
-#define LO_BYTE(x) ( *( ( __u8 *)&x ) )
-#define HI_WORD(x) ( *( ( __u16 *)(&x)+1 ) )
-#define LO_WORD(x) ( *( ( __u16 *)&x ) )
+#define HI_BYTE(x) (*((__u8 *)(&x)+1))
+#define LO_BYTE(x) (*((__u8 *)&x))
+#define HI_WORD(x) (*((__u16 *)(&x)+1))
+#define LO_WORD(x) (*((__u16 *)&x))
 #ifndef MAKEWORD
 #define MAKEWORD(lo, hi)    ((__u16) (((__u16) lo) | ((__u16) hi << 8)))
 #endif
@@ -642,64 +781,40 @@
 #define SwapBytes(word)         ((__u16) ((word >> 8) | (word << 8)))
 #define BigToLittle(dWord) ((__u32) (SwapWords(MAKELONG(SwapBytes(LO_WORD(dWord)), SwapBytes(HI_WORD(dWord))))))
 #define LittleToBig(dWord)      BigToLittle(dWord)
-#define AscPCICmdRegBits_BusMastering     0x0007
 #define AscPCIConfigVendorIDRegister      0x0000
 #define AscPCIConfigDeviceIDRegister      0x0002
 #define AscPCIConfigCommandRegister       0x0004
 #define AscPCIConfigStatusRegister        0x0006
+#define AscPCIConfigRevisionIDRegister    0x0008
 #define AscPCIConfigCacheSize             0x000C
 #define AscPCIConfigLatencyTimer          0x000D
 #define AscPCIIOBaseRegister              0x0010
-#define ASC_PCI_ID2BUS( id )    ((id) & 0xFF)
-#define ASC_PCI_ID2DEV( id )    (((id) >> 11) & 0x1F)
-#define ASC_PCI_ID2FUNC( id )   (((id) >> 8) & 0x7)
-#define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
+#define AscPCICmdRegBits_IOMemBusMaster   0x0007
+#define ASC_PCI_ID2BUS(id)    ((id) & 0xFF)
+#define ASC_PCI_ID2DEV(id)    (((id) >> 11) & 0x1F)
+#define ASC_PCI_ID2FUNC(id)   (((id) >> 8) & 0x7)
+#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
+#define ASC_PCI_VENDORID                  0x10CD
+#define ASC_PCI_DEVICEID_1200A            0x1100
+#define ASC_PCI_DEVICEID_1200B            0x1200
+#define ASC_PCI_DEVICEID_ULTRA            0x1300 
+#define ASC_PCI_REVISION_3150             0x02
+#define ASC_PCI_REVISION_3050             0x03
 
 #define  ASC_DVCLIB_CALL_DONE     (1)
 #define  ASC_DVCLIB_CALL_FAILED   (0)
 #define  ASC_DVCLIB_CALL_ERROR    (-1)
 
-#define Lptr
-#define dosfar
-#define far
-#define PortAddr  unsigned short	/* port address size  */
-#define Ptr2Func	ulong
+#define PortAddr            unsigned short    /* port address size  */
+#define Ptr2Func            ulong
 #define inp(port)           inb(port)
 #define inpw(port)          inw(port)
-#define inpl(port)    		inl(port)
+#define inpl(port)          inl(port)
 #define outp(port, byte)    outb((byte), (port))
 #define outpw(port, word)   outw((word), (port))
 #define outpl(port, long)   outl((long), (port))
-#define ASC_MAX_SG_QUEUE	7
-#define ASC_MAX_SG_LIST		SG_ALL
-
-#define CC_INIT_INQ_DISPLAY     FALSE
-#define CC_CLEAR_LRAM_SRB_PTR   FALSE
-#define CC_VERIFY_LRAM_COPY     FALSE
-#define CC_DEBUG_SG_LIST        FALSE
-#define CC_FAST_STRING_IO       FALSE
-#define CC_WRITE_IO_COUNT       FALSE
-#define CC_CLEAR_DMA_REMAIN     FALSE
-#define CC_DISABLE_PCI_PARITY_INT TRUE
-#define CC_LINK_BUSY_Q         FALSE
-#define CC_LITTLE_ENDIAN_HOST  TRUE
-#define CC_STRUCT_ALIGNED      TRUE
-#define CC_MEMORY_MAPPED_IO    FALSE
-#define CC_INCLUDE_EEP_CONFIG  TRUE
-#define CC_PCI_ULTRA           TRUE
-#define CC_ASC_SCSI_Q_USRDEF         FALSE
-#define CC_ASC_SCSI_REQ_Q_USRDEF     FALSE
-#define CC_ASCISR_CHECK_INT_PENDING  TRUE
-#define CC_CHK_FIX_EEP_CONTENT       TRUE
-#define CC_CHK_AND_COALESCE_SG_LIST  FALSE
-#define CC_DISABLE_PCI_PARITY_INT    TRUE
-#define CC_INCLUDE_EEP_CONFIG        TRUE
-#define CC_INIT_INQ_DISPLAY          FALSE
-#define CC_PLEXTOR_VL                FALSE
-#define CC_TMP_USE_EEP_SDTR          FALSE
-#define CC_CHK_COND_REDO_SDTR        TRUE
-#define CC_SET_PCI_LATENCY_TIMER_ZERO  TRUE
-#define CC_DISABLE_ASYN_FIX_WANGTEK_TAPE  TRUE
+#define ASC_MAX_SG_QUEUE    7
+#define ASC_MAX_SG_LIST     SG_ALL
 
 #define ASC_CS_TYPE  unsigned short
 #ifndef asc_ptr_type
@@ -707,9 +822,9 @@
 #endif
 
 #ifndef ASC_GET_PTR2FUNC
-#define ASC_GET_PTR2FUNC( fun )  ( Ptr2Func )( fun )
+#define ASC_GET_PTR2FUNC(fun)  (Ptr2Func)(fun)
 #endif
-#define FLIP_BYTE_NIBBLE( x )    ( ((x<<4)& 0xFF) | (x>>4) )
+#define FLIP_BYTE_NIBBLE(x)    (((x<<4)& 0xFF) | (x>>4))
 #define ASC_IS_ISA          (0x0001)
 #define ASC_IS_ISAPNP       (0x0081)
 #define ASC_IS_EISA         (0x0002)
@@ -734,11 +849,13 @@
 #define ASC_CHIP_VER_ISA_BIT     (0x30)
 #define ASC_CHIP_VER_ISAPNP_BIT  (0x20)
 #define ASC_CHIP_VER_ASYN_BUG    (0x21)
-#define ASC_CHIP_VER_1ST_PCI_ULTRA   (0x0A)
+#define ASC_CHIP_VER_PCI             0x08
+#define ASC_CHIP_VER_PCI_ULTRA_3150  (ASC_CHIP_VER_PCI | 0x02)
+#define ASC_CHIP_VER_PCI_ULTRA_3050  (ASC_CHIP_VER_PCI | 0x03)
 #define ASC_CHIP_MIN_VER_EISA (0x41)
 #define ASC_CHIP_MAX_VER_EISA (0x47)
 #define ASC_CHIP_VER_EISA_BIT (0x40)
-#define ASC_CHIP_LATEST_VER_EISA   ( ( ASC_CHIP_MIN_VER_EISA - 1 ) + 3 )
+#define ASC_CHIP_LATEST_VER_EISA   ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
 #define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER   0x21
 #define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER   0x0A
 #define ASC_MAX_VL_DMA_ADDR     (0x07FFFFFFL)
@@ -749,32 +866,11 @@
 #define ASC_MAX_ISA_DMA_COUNT   (0x00FFFFFFL)
 #define ASC_MAX_EISA_DMA_ADDR   (0x07FFFFFFL)
 #define ASC_MAX_EISA_DMA_COUNT  (0x07FFFFFFL)
-#if !CC_STRUCT_ALIGNED
-#define DvcGetQinfo( iop_base, s_addr, outbuf, words)  \
-AscMemWordCopyFromLram(iop_base, s_addr, outbuf, words)
-#define DvcPutScsiQ( iop_base, s_addr, outbuf, words) \
-AscMemWordCopyToLram(iop_base, s_addr, outbuf, words)
-#endif
-#ifdef ASC_CHIP_VERSION
-#endif
-#if CC_MEMORY_MAPPED_IO
-#define inp( port )            *( (uchar *)(port) )
-#define outp( port, data )     *( (uchar *)(port) ) = ( uchar )( data )
-#if CC_LITTLE_ENDIAN_HOST
-#define inpw( port )              *( (ushort *)(port) )
-#define outpw( port, data )       *( (ushort *)(port) ) = ( ushort )( data )
-#else
-#define inpw( port )             EndianSwap16Bit( (*((ushort *)(port))) )
-#define outpw( port, data )      *( (ushort *)(port) ) = EndianSwap16Bit( (ushort)(data) )
-#define inpw_noswap( port )          *( (ushort *)(port) )
-#define outpw_noswap( port, data )   *( (ushort *)(port) ) = ( ushort )( data )
-#endif
-#endif
 #ifndef inpw_noswap
-#define inpw_noswap( port )         inpw( port )
+#define inpw_noswap(port)         inpw(port)
 #endif
 #ifndef outpw_noswap
-#define outpw_noswap( port, data )  outpw( port, data )
+#define outpw_noswap(port, data)  outpw(port, data)
 #endif
 #define ASC_SCSI_ID_BITS  3
 #define ASC_SCSI_TIX_TYPE     uchar
@@ -810,6 +906,7 @@
 #define ASC_MAX_SENSE_LEN   32
 #define ASC_MIN_SENSE_LEN   14
 #define ASC_MAX_CDB_LEN     12
+#define ASC_SCSI_RESET_HOLD_TIME_US  60
 #define SCSICMD_TestUnitReady     0x00
 #define SCSICMD_Rewind            0x01
 #define SCSICMD_Rezero            0x01
@@ -872,10 +969,11 @@
 #define SCSI_SENKEY_VOL_OVERFLOW  0x0D
 #define SCSI_SENKEY_MISCOMP       0x0E
 #define SCSI_SENKEY_RESERVED      0x0F
-#define ASC_SRB_HOST( x )  ( ( uchar )( ( uchar )( x ) >> 4 ) )
-#define ASC_SRB_TID( x )   ( ( uchar )( ( uchar )( x ) & ( uchar )0x0F ) )
-#define ASC_SRB_LUN( x )   ( ( uchar )( ( uint )( x ) >> 13 ) )
-#define PUT_CDB1( x )   ( ( uchar )( ( uint )( x ) >> 8 ) )
+#define SCSI_ASC_NOMEDIA          0x3A
+#define ASC_SRB_HOST(x)  ((uchar)((uchar)(x) >> 4))
+#define ASC_SRB_TID(x)   ((uchar)((uchar)(x) & (uchar)0x0F))
+#define ASC_SRB_LUN(x)   ((uchar)((uint)(x) >> 13))
+#define PUT_CDB1(x)   ((uchar)((uint)(x) >> 8))
 #define SS_GOOD              0x00
 #define SS_CHK_CONDITION     0x02
 #define SS_CONDITION_MET     0x04
@@ -889,6 +987,10 @@
 #define MS_EXTEND      0x01
 #define MS_SDTR_LEN    0x03
 #define MS_SDTR_CODE   0x01
+#define MS_WDTR_LEN    0x02
+#define MS_WDTR_CODE   0x03
+#define MS_MDP_LEN    0x05
+#define MS_MDP_CODE   0x00
 #define M1_SAVE_DATA_PTR        0x02
 #define M1_RESTORE_PTRS         0x03
 #define M1_DISCONNECT           0x04
@@ -909,152 +1011,78 @@
 #define M2_QTAG_MSG_HEAD        0x21
 #define M2_QTAG_MSG_ORDERED     0x22
 #define M2_IGNORE_WIDE_RESIDUE  0x23
-#if CC_LITTLE_ENDIAN_HOST
-typedef struct {
-	uchar               peri_dvc_type:5;
-	uchar               peri_qualifier:3;
-} ASC_SCSI_INQ0;
 
-#else
 typedef struct {
-	uchar               peri_qualifier:3;
-	uchar               peri_dvc_type:5;
+    uchar               peri_dvc_type:5;
+    uchar               peri_qualifier:3;
 } ASC_SCSI_INQ0;
 
-#endif
-#if CC_LITTLE_ENDIAN_HOST
-typedef struct {
-	uchar               dvc_type_modifier:7;
-	uchar               rmb:1;
-} ASC_SCSI_INQ1;
-
-#else
 typedef struct {
-	uchar               rmb:1;
-	uchar               dvc_type_modifier:7;
+    uchar               dvc_type_modifier:7;
+    uchar               rmb:1;
 } ASC_SCSI_INQ1;
 
-#endif
-#if CC_LITTLE_ENDIAN_HOST
-typedef struct {
-	uchar               ansi_apr_ver:3;
-	uchar               ecma_ver:3;
-	uchar               iso_ver:2;
-} ASC_SCSI_INQ2;
-
-#else
 typedef struct {
-	uchar               iso_ver:2;
-	uchar               ecma_ver:3;
-	uchar               ansi_apr_ver:3;
+    uchar               ansi_apr_ver:3;
+    uchar               ecma_ver:3;
+    uchar               iso_ver:2;
 } ASC_SCSI_INQ2;
 
-#endif
-#if CC_LITTLE_ENDIAN_HOST
-typedef struct {
-	uchar               rsp_data_fmt:4;
-	uchar               res:2;
-	uchar               TemIOP:1;
-	uchar               aenc:1;
-} ASC_SCSI_INQ3;
-
-#else
 typedef struct {
-	uchar               aenc:1;
-	uchar               TemIOP:1;
-	uchar               res:2;
-	uchar               rsp_data_fmt:4;
+    uchar               rsp_data_fmt:4;
+    uchar               res:2;
+    uchar               TemIOP:1;
+    uchar               aenc:1;
 } ASC_SCSI_INQ3;
 
-#endif
-#if CC_LITTLE_ENDIAN_HOST
-typedef struct {
-	uchar               StfRe:1;
-	uchar               CmdQue:1;
-	uchar               Reserved:1;
-	uchar               Linked:1;
-	uchar               Sync:1;
-	uchar               WBus16:1;
-	uchar               WBus32:1;
-	uchar               RelAdr:1;
-} ASC_SCSI_INQ7;
-
-#else
 typedef struct {
-	uchar               RelAdr:1;
-	uchar               WBus32:1;
-	uchar               WBus16:1;
-	uchar               Sync:1;
-	uchar               Linked:1;
-	uchar               Reserved:1;
-	uchar               CmdQue:1;
-	uchar               StfRe:1;
+    uchar               StfRe:1;
+    uchar               CmdQue:1;
+    uchar               Reserved:1;
+    uchar               Linked:1;
+    uchar               Sync:1;
+    uchar               WBus16:1;
+    uchar               WBus32:1;
+    uchar               RelAdr:1;
 } ASC_SCSI_INQ7;
 
-#endif
 typedef struct {
-	ASC_SCSI_INQ0       byte0;
-	ASC_SCSI_INQ1       byte1;
-	ASC_SCSI_INQ2       byte2;
-	ASC_SCSI_INQ3       byte3;
-	uchar               add_len;
-	uchar               res1;
-	uchar               res2;
-	ASC_SCSI_INQ7       byte7;
-	uchar               vendor_id[8];
-	uchar               product_id[16];
-	uchar               product_rev_level[4];
+    ASC_SCSI_INQ0       byte0;
+    ASC_SCSI_INQ1       byte1;
+    ASC_SCSI_INQ2       byte2;
+    ASC_SCSI_INQ3       byte3;
+    uchar               add_len;
+    uchar               res1;
+    uchar               res2;
+    ASC_SCSI_INQ7       byte7;
+    uchar               vendor_id[8];
+    uchar               product_id[16];
+    uchar               product_rev_level[4];
 } ASC_SCSI_INQUIRY;
 
-#if CC_LITTLE_ENDIAN_HOST
 typedef struct asc_req_sense {
-	uchar               err_code:7;
-	uchar               info_valid:1;
-	uchar               segment_no;
-	uchar               sense_key:4;
-	uchar               reserved_bit:1;
-	uchar               sense_ILI:1;
-	uchar               sense_EOM:1;
-	uchar               file_mark:1;
-	uchar               info1[4];
-	uchar               add_sense_len;
-	uchar               cmd_sp_info[4];
-	uchar               asc;
-	uchar               ascq;
-	uchar               fruc;
-	uchar               sks_byte0:7;
-	uchar               sks_valid:1;
-	uchar               sks_bytes[2];
-	uchar               notused[2];
-	uchar               ex_sense_code;
-	uchar               info2[4];
+    uchar               err_code:7;
+    uchar               info_valid:1;
+    uchar               segment_no;
+    uchar               sense_key:4;
+    uchar               reserved_bit:1;
+    uchar               sense_ILI:1;
+    uchar               sense_EOM:1;
+    uchar               file_mark:1;
+    uchar               info1[4];
+    uchar               add_sense_len;
+    uchar               cmd_sp_info[4];
+    uchar               asc;
+    uchar               ascq;
+    uchar               fruc;
+    uchar               sks_byte0:7;
+    uchar               sks_valid:1;
+    uchar               sks_bytes[2];
+    uchar               notused[2];
+    uchar               ex_sense_code;
+    uchar               info2[4];
 } ASC_REQ_SENSE;
 
-#else
-typedef struct asc_req_sense {
-	uchar               info_valid:1;
-	uchar               err_code:7;
-	uchar               segment_no;
-	uchar               file_mark:1;
-	uchar               sense_EOM:1;
-	uchar               sense_ILI:1;
-	uchar               reserved_bit:1;
-	uchar               sense_key:4;
-	uchar               info1[4];
-	uchar               add_sense_len;
-	uchar               cmd_sp_info[4];
-	uchar               asc;
-	uchar               ascq;
-	uchar               fruc;
-	uchar               sks_valid:1;
-	uchar               sks_byte0:7;
-	uchar               sks_bytes[2];
-	uchar               notused[2];
-	uchar               ex_sense_code;
-	uchar               info2[4];
-} ASC_REQ_SENSE;
-
-#endif
 #define ASC_SG_LIST_PER_Q   7
 #define QS_FREE        0x00
 #define QS_READY       0x01
@@ -1159,171 +1187,146 @@
 #define ASC_STOP_CLEAN_UP_BUSY_Q    0x10
 #define ASC_STOP_CLEAN_UP_DISC_Q    0x20
 #define ASC_STOP_HOST_REQ_RISC_HALT 0x40
-#define ASC_TIDLUN_TO_IX( tid, lun )  ( ASC_SCSI_TIX_TYPE )( (tid) + ((lun)<<ASC_SCSI_ID_BITS) )
-#define ASC_TID_TO_TARGET_ID( tid )   ( ASC_SCSI_BIT_ID_TYPE )( 0x01 << (tid) )
-#define ASC_TIX_TO_TARGET_ID( tix )   ( 0x01 << ( (tix) & ASC_MAX_TID ) )
-#define ASC_TIX_TO_TID( tix )         ( (tix) & ASC_MAX_TID )
-#define ASC_TID_TO_TIX( tid )         ( (tid) & ASC_MAX_TID )
-#define ASC_TIX_TO_LUN( tix )         ( ( (tix) >> ASC_SCSI_ID_BITS ) & ASC_MAX_LUN )
-#define ASC_QNO_TO_QADDR( q_no )      ( (ASC_QADR_BEG)+( ( int )(q_no) << 6 ) )
+#define ASC_TIDLUN_TO_IX(tid, lun)  (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
+#define ASC_TID_TO_TARGET_ID(tid)   (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
+#define ASC_TIX_TO_TARGET_ID(tix)   (0x01 << ((tix) & ASC_MAX_TID))
+#define ASC_TIX_TO_TID(tix)         ((tix) & ASC_MAX_TID)
+#define ASC_TID_TO_TIX(tid)         ((tid) & ASC_MAX_TID)
+#define ASC_TIX_TO_LUN(tix)         (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
+#define ASC_QNO_TO_QADDR(q_no)      ((ASC_QADR_BEG)+((int)(q_no) << 6))
 
 typedef struct asc_scisq_1 {
-	uchar               status;
-	uchar               q_no;
-	uchar               cntl;
-	uchar               sg_queue_cnt;
-	uchar               target_id;
-	uchar               target_lun;
-	ulong               data_addr;
-	ulong               data_cnt;
-	ulong               sense_addr;
-	uchar               sense_len;
-	uchar               extra_bytes;
+    uchar               status;
+    uchar               q_no;
+    uchar               cntl;
+    uchar               sg_queue_cnt;
+    uchar               target_id;
+    uchar               target_lun;
+    ulong               data_addr;
+    ulong               data_cnt;
+    ulong               sense_addr;
+    uchar               sense_len;
+    uchar               extra_bytes;
 } ASC_SCSIQ_1;
 
 typedef struct asc_scisq_2 {
-	ulong               srb_ptr;
-	uchar               target_ix;
-	uchar               flag;
-	uchar               cdb_len;
-	uchar               tag_code;
-	ushort              vm_id;
+    ulong               srb_ptr;
+    uchar               target_ix;
+    uchar               flag;
+    uchar               cdb_len;
+    uchar               tag_code;
+    ushort              vm_id;
 } ASC_SCSIQ_2;
 
 typedef struct asc_scsiq_3 {
-	uchar               done_stat;
-	uchar               host_stat;
-	uchar               scsi_stat;
-	uchar               scsi_msg;
+    uchar               done_stat;
+    uchar               host_stat;
+    uchar               scsi_stat;
+    uchar               scsi_msg;
 } ASC_SCSIQ_3;
 
 typedef struct asc_scsiq_4 {
-	uchar               cdb[ASC_MAX_CDB_LEN];
-	uchar               y_first_sg_list_qp;
-	uchar               y_working_sg_qp;
-	uchar               y_working_sg_ix;
-	uchar               y_res;
-	ushort              x_req_count;
-	ushort              x_reconnect_rtn;
-	ulong               x_saved_data_addr;
-	ulong               x_saved_data_cnt;
+    uchar               cdb[ASC_MAX_CDB_LEN];
+    uchar               y_first_sg_list_qp;
+    uchar               y_working_sg_qp;
+    uchar               y_working_sg_ix;
+    uchar               y_res;
+    ushort              x_req_count;
+    ushort              x_reconnect_rtn;
+    ulong               x_saved_data_addr;
+    ulong               x_saved_data_cnt;
 } ASC_SCSIQ_4;
 
 typedef struct asc_q_done_info {
-	ASC_SCSIQ_2         d2;
-	ASC_SCSIQ_3         d3;
-	uchar               q_status;
-	uchar               q_no;
-	uchar               cntl;
-	uchar               sense_len;
-	uchar               extra_bytes;
-	uchar               res;
-	ulong               remain_bytes;
+    ASC_SCSIQ_2         d2;
+    ASC_SCSIQ_3         d3;
+    uchar               q_status;
+    uchar               q_no;
+    uchar               cntl;
+    uchar               sense_len;
+    uchar               extra_bytes;
+    uchar               res;
+    ulong               remain_bytes;
 } ASC_QDONE_INFO;
 
 typedef struct asc_sg_list {
-	ulong               addr;
-	ulong               bytes;
+    ulong               addr;
+    ulong               bytes;
 } ASC_SG_LIST;
 
 typedef struct asc_sg_head {
-	ushort              entry_cnt;
-	ushort              queue_cnt;
-	ushort              entry_to_copy;
-	ushort              res;
-	ASC_SG_LIST         sg_list[ASC_MAX_SG_LIST];
+    ushort              entry_cnt;
+    ushort              queue_cnt;
+    ushort              entry_to_copy;
+    ushort              res;
+    ASC_SG_LIST         sg_list[ASC_MAX_SG_LIST];
 } ASC_SG_HEAD;
 
 #define ASC_MIN_SG_LIST   2
 
 typedef struct asc_min_sg_head {
-	ushort              entry_cnt;
-	ushort              queue_cnt;
-	ushort              entry_to_copy;
-	ushort              res;
-	ASC_SG_LIST         sg_list[ASC_MIN_SG_LIST];
+    ushort              entry_cnt;
+    ushort              queue_cnt;
+    ushort              entry_to_copy;
+    ushort              res;
+    ASC_SG_LIST         sg_list[ASC_MIN_SG_LIST];
 } ASC_MIN_SG_HEAD;
 
 #define QCX_SORT        (0x0001)
 #define QCX_COALEASE    (0x0002)
 
-#if CC_LINK_BUSY_Q
-typedef struct asc_ext_scsi_q {
-	ulong               lba;
-	ushort              lba_len;
-	struct asc_scsi_q dosfar *next;
-	struct asc_scsi_q dosfar *join;
-	ushort              cntl;
-	ushort              buffer_id;
-	uchar               q_required;
-	uchar               res;
-} ASC_EXT_SCSI_Q;
-#endif
-
 typedef struct asc_scsi_q {
-	ASC_SCSIQ_1         q1;
-	ASC_SCSIQ_2         q2;
-	uchar dosfar       *cdbptr;
-	ASC_SG_HEAD dosfar *sg_head;
-#if CC_LINK_BUSY_Q
-	ASC_EXT_SCSI_Q      ext;
-#endif
-#if CC_ASC_SCSI_Q_USRDEF
-	ASC_SCSI_Q_USR      usr;
-#endif
+    ASC_SCSIQ_1         q1;
+    ASC_SCSIQ_2         q2;
+    uchar               *cdbptr;
+    ASC_SG_HEAD         *sg_head;
 } ASC_SCSI_Q;
 
 typedef struct asc_scsi_req_q {
-	ASC_SCSIQ_1         r1;
-	ASC_SCSIQ_2         r2;
-	uchar dosfar       *cdbptr;
-	ASC_SG_HEAD dosfar *sg_head;
-#if CC_LINK_BUSY_Q
-	ASC_EXT_SCSI_Q      ext;
-#endif
-	uchar dosfar       *sense_ptr;
-	ASC_SCSIQ_3         r3;
-	uchar               cdb[ASC_MAX_CDB_LEN];
-	uchar               sense[ASC_MIN_SENSE_LEN];
-#if CC_ASC_SCSI_REQ_Q_USRDEF
-	ASC_SCSI_REQ_Q_USR  usr;
-#endif
+    ASC_SCSIQ_1         r1;
+    ASC_SCSIQ_2         r2;
+    uchar       *cdbptr;
+    ASC_SG_HEAD *sg_head;
+    uchar               *sense_ptr;
+    ASC_SCSIQ_3         r3;
+    uchar               cdb[ASC_MAX_CDB_LEN];
+    uchar               sense[ASC_MIN_SENSE_LEN];
 } ASC_SCSI_REQ_Q;
 
 typedef struct asc_scsi_bios_req_q {
-	ASC_SCSIQ_1         r1;
-	ASC_SCSIQ_2         r2;
-	uchar dosfar       *cdbptr;
-	ASC_SG_HEAD dosfar *sg_head;
-	uchar dosfar       *sense_ptr;
-	ASC_SCSIQ_3         r3;
-	uchar               cdb[ASC_MAX_CDB_LEN];
-	uchar               sense[ASC_MIN_SENSE_LEN];
+    ASC_SCSIQ_1         r1;
+    ASC_SCSIQ_2         r2;
+    uchar               *cdbptr;
+    ASC_SG_HEAD         *sg_head;
+    uchar               *sense_ptr;
+    ASC_SCSIQ_3         r3;
+    uchar               cdb[ASC_MAX_CDB_LEN];
+    uchar               sense[ASC_MIN_SENSE_LEN];
 } ASC_SCSI_BIOS_REQ_Q;
 
 typedef struct asc_risc_q {
-	uchar               fwd;
-	uchar               bwd;
-	ASC_SCSIQ_1         i1;
-	ASC_SCSIQ_2         i2;
-	ASC_SCSIQ_3         i3;
-	ASC_SCSIQ_4         i4;
+    uchar               fwd;
+    uchar               bwd;
+    ASC_SCSIQ_1         i1;
+    ASC_SCSIQ_2         i2;
+    ASC_SCSIQ_3         i3;
+    ASC_SCSIQ_4         i4;
 } ASC_RISC_Q;
 
 typedef struct asc_sg_list_q {
-	uchar               seq_no;
-	uchar               q_no;
-	uchar               cntl;
-	uchar               sg_head_qp;
-	uchar               sg_list_cnt;
-	uchar               sg_cur_list_cnt;
+    uchar               seq_no;
+    uchar               q_no;
+    uchar               cntl;
+    uchar               sg_head_qp;
+    uchar               sg_list_cnt;
+    uchar               sg_cur_list_cnt;
 } ASC_SG_LIST_Q;
 
 typedef struct asc_risc_sg_list_q {
-	uchar               fwd;
-	uchar               bwd;
-	ASC_SG_LIST_Q       sg;
-	ASC_SG_LIST         sg_list[7];
+    uchar               fwd;
+    uchar               bwd;
+    ASC_SG_LIST_Q       sg;
+    ASC_SG_LIST         sg_list[7];
 } ASC_RISC_SG_LIST_Q;
 
 #define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP  0x1000000UL
@@ -1396,7 +1399,7 @@
 #define ASC_MIN_TAG_Q_PER_DVC   (0x04)
 #define ASC_DEF_TAG_Q_PER_DVC   (0x04)
 #define ASC_MIN_FREE_Q        ASC_MIN_REMAIN_Q
-#define ASC_MIN_TOTAL_QNG     (( ASC_MAX_SG_QUEUE )+( ASC_MIN_FREE_Q ))
+#define ASC_MIN_TOTAL_QNG     ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
 #define ASC_MAX_TOTAL_QNG 240
 #define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
 #define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG   8
@@ -1405,16 +1408,16 @@
 #define ASC_IOADR_TABLE_MAX_IX  11
 #define ASC_IOADR_GAP   0x10
 #define ASC_SEARCH_IOP_GAP 0x10
-#define ASC_MIN_IOP_ADDR   ( PortAddr )0x0100
-#define ASC_MAX_IOP_ADDR   ( PortAddr )0x3F0
-#define ASC_IOADR_1     ( PortAddr )0x0110
-#define ASC_IOADR_2     ( PortAddr )0x0130
-#define ASC_IOADR_3     ( PortAddr )0x0150
-#define ASC_IOADR_4     ( PortAddr )0x0190
-#define ASC_IOADR_5     ( PortAddr )0x0210
-#define ASC_IOADR_6     ( PortAddr )0x0230
-#define ASC_IOADR_7     ( PortAddr )0x0250
-#define ASC_IOADR_8     ( PortAddr )0x0330
+#define ASC_MIN_IOP_ADDR   (PortAddr)0x0100
+#define ASC_MAX_IOP_ADDR   (PortAddr)0x3F0
+#define ASC_IOADR_1     (PortAddr)0x0110
+#define ASC_IOADR_2     (PortAddr)0x0130
+#define ASC_IOADR_3     (PortAddr)0x0150
+#define ASC_IOADR_4     (PortAddr)0x0190
+#define ASC_IOADR_5     (PortAddr)0x0210
+#define ASC_IOADR_6     (PortAddr)0x0230
+#define ASC_IOADR_7     (PortAddr)0x0250
+#define ASC_IOADR_8     (PortAddr)0x0330
 #define ASC_IOADR_DEF   ASC_IOADR_8
 #define ASC_LIB_SCSIQ_WK_SP        256
 #define ASC_MAX_SYN_XFER_NO        16
@@ -1446,35 +1449,56 @@
 #define SYN_ULTRA_XFER_NS_13   94
 #define SYN_ULTRA_XFER_NS_14  100
 #define SYN_ULTRA_XFER_NS_15  107
-#define SYN_XMSG_WLEN  3
 
-typedef struct sdtr_xmsg {
-	uchar               msg_type;
-	uchar               msg_len;
-	uchar               msg_req;
-	uchar               xfer_period;
-	uchar               req_ack_offset;
-	uchar               res;
-} SDTR_XMSG;
+typedef struct ext_msg {
+    uchar               msg_type;
+    uchar               msg_len;
+    uchar               msg_req;
+    union {
+        struct {
+            uchar               sdtr_xfer_period;
+            uchar               sdtr_req_ack_offset;
+        } sdtr;
+        struct {
+            uchar               wdtr_width;
+        } wdtr;
+        struct {
+            uchar               mdp_b3;
+            uchar               mdp_b2;
+            uchar               mdp_b1;
+            uchar               mdp_b0;
+        } mdp;
+    } u_ext_msg;
+    uchar               res;
+} EXT_MSG;
+
+#define xfer_period     u_ext_msg.sdtr.sdtr_xfer_period
+#define req_ack_offset  u_ext_msg.sdtr.sdtr_req_ack_offset
+#define wdtr_width      u_ext_msg.wdtr.wdtr_width
+#define mdp_b3          u_ext_msg.mdp_b3
+#define mdp_b2          u_ext_msg.mdp_b2
+#define mdp_b1          u_ext_msg.mdp_b1
+#define mdp_b0          u_ext_msg.mdp_b0
 
 typedef struct asc_dvc_cfg {
-	ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
-	ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
-	ASC_SCSI_BIT_ID_TYPE disc_enable;
-	uchar               res;
-	uchar               chip_scsi_id:4;
-	uchar               isa_dma_speed:4;
-	uchar               isa_dma_channel;
-	uchar               chip_version;
-	ushort              pci_device_id;
-	ushort              lib_serial_no;
-	ushort              lib_version;
-	ushort              mcode_date;
-	ushort              mcode_version;
-	uchar               max_tag_qng[ASC_MAX_TID + 1];
-	uchar dosfar       *overrun_buf;
-	uchar               sdtr_period_offset[ASC_MAX_TID + 1];
-	ushort              pci_slot_info;
+    ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
+    ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
+    ASC_SCSI_BIT_ID_TYPE disc_enable;
+    uchar               res;
+    uchar               chip_scsi_id:4;
+    uchar               isa_dma_speed:4;
+    uchar               isa_dma_channel;
+    uchar               chip_version;
+    ushort              pci_device_id;
+    ushort              lib_serial_no;
+    ushort              lib_version;
+    ushort              mcode_date;
+    ushort              mcode_version;
+    uchar               max_tag_qng[ASC_MAX_TID + 1];
+    uchar               *overrun_buf;
+    uchar               sdtr_period_offset[ASC_MAX_TID + 1];
+    ushort              pci_slot_info;
+    uchar               adapter_info[6];
 } ASC_DVC_CFG;
 
 #define ASC_DEF_DVC_CNTL       0xFFFF
@@ -1500,82 +1524,82 @@
 #define ASC_MAX_SCSI_RESET_WAIT      30
 
 typedef struct asc_dvc_var {
-	PortAddr            iop_base;
-	ushort              err_code;
-	ushort              dvc_cntl;
-	ushort              bug_fix_cntl;
-	ushort              bus_type;
-	Ptr2Func            isr_callback;
-	Ptr2Func            exe_callback;
-	ASC_SCSI_BIT_ID_TYPE init_sdtr;
-	ASC_SCSI_BIT_ID_TYPE sdtr_done;
-	ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
-	ASC_SCSI_BIT_ID_TYPE unit_not_ready;
-	ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
-	ASC_SCSI_BIT_ID_TYPE start_motor;
-	uchar               scsi_reset_wait;
-	uchar               chip_no;
-	char                is_in_int;
-	uchar               max_total_qng;
-	uchar               cur_total_qng;
-	uchar               in_critical_cnt;
-	uchar               irq_no;
-	uchar               last_q_shortage;
-	ushort              init_state;
-	uchar               cur_dvc_qng[ASC_MAX_TID + 1];
-	uchar               max_dvc_qng[ASC_MAX_TID + 1];
-	ASC_SCSI_Q dosfar  *scsiq_busy_head[ASC_MAX_TID + 1];
-	ASC_SCSI_Q dosfar  *scsiq_busy_tail[ASC_MAX_TID + 1];
-	uchar               sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
-	ASC_DVC_CFG dosfar *cfg;
-	Ptr2Func            saved_ptr2func;
-	ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
-	char                redo_scam;
-	ushort              res2;
-	uchar               dos_int13_table[ASC_MAX_TID + 1];
-	ulong               max_dma_count;
-	ASC_SCSI_BIT_ID_TYPE no_scam;
-	ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
-	uchar               max_sdtr_index;
-	uchar               host_init_sdtr_index;
-	ulong               drv_ptr;
-	ulong               uc_break;
-	ulong               res7;
-	ulong               res8;
+    PortAddr            iop_base;
+    ushort              err_code;
+    ushort              dvc_cntl;
+    ushort              bug_fix_cntl;
+    ushort              bus_type;
+    Ptr2Func            isr_callback;
+    Ptr2Func            exe_callback;
+    ASC_SCSI_BIT_ID_TYPE init_sdtr;
+    ASC_SCSI_BIT_ID_TYPE sdtr_done;
+    ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
+    ASC_SCSI_BIT_ID_TYPE unit_not_ready;
+    ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
+    ASC_SCSI_BIT_ID_TYPE start_motor;
+    uchar               scsi_reset_wait;
+    uchar               chip_no;
+    char                is_in_int;
+    uchar               max_total_qng;
+    uchar               cur_total_qng;
+    uchar               in_critical_cnt;
+    uchar               irq_no;
+    uchar               last_q_shortage;
+    ushort              init_state;
+    uchar               cur_dvc_qng[ASC_MAX_TID + 1];
+    uchar               max_dvc_qng[ASC_MAX_TID + 1];
+    ASC_SCSI_Q  *scsiq_busy_head[ASC_MAX_TID + 1];
+    ASC_SCSI_Q  *scsiq_busy_tail[ASC_MAX_TID + 1];
+    uchar               sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
+    ASC_DVC_CFG *cfg;
+    Ptr2Func            saved_ptr2func;
+    ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
+    char                redo_scam;
+    ushort              res2;
+    uchar               dos_int13_table[ASC_MAX_TID + 1];
+    ulong               max_dma_count;
+    ASC_SCSI_BIT_ID_TYPE no_scam;
+    ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+    uchar               max_sdtr_index;
+    uchar               host_init_sdtr_index;
+    ulong               drv_ptr;
+    ulong               uc_break;
+    ulong               res7;
+    ulong               res8;
 } ASC_DVC_VAR;
 
-typedef int         (dosfar * ASC_ISR_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO dosfar *);
-typedef int         (dosfar * ASC_EXE_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
+typedef int (* ASC_ISR_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO *);
+typedef int (* ASC_EXE_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q *);
 
 typedef struct asc_dvc_inq_info {
-	uchar               type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+    uchar               type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
 } ASC_DVC_INQ_INFO;
 
 typedef struct asc_cap_info {
-	ulong               lba;
-	ulong               blk_size;
+    ulong               lba;
+    ulong               blk_size;
 } ASC_CAP_INFO;
 
 typedef struct asc_cap_info_array {
-	ASC_CAP_INFO        cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+    ASC_CAP_INFO        cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
 } ASC_CAP_INFO_ARRAY;
 
-#define ASC_MCNTL_NO_SEL_TIMEOUT  ( ushort )0x0001
-#define ASC_MCNTL_NULL_TARGET     ( ushort )0x0002
-#define ASC_CNTL_INITIATOR         ( ushort )0x0001
-#define ASC_CNTL_BIOS_GT_1GB       ( ushort )0x0002
-#define ASC_CNTL_BIOS_GT_2_DISK    ( ushort )0x0004
-#define ASC_CNTL_BIOS_REMOVABLE    ( ushort )0x0008
-#define ASC_CNTL_NO_SCAM           ( ushort )0x0010
-#define ASC_CNTL_INT_MULTI_Q       ( ushort )0x0080
-#define ASC_CNTL_NO_LUN_SUPPORT    ( ushort )0x0040
-#define ASC_CNTL_NO_VERIFY_COPY    ( ushort )0x0100
-#define ASC_CNTL_RESET_SCSI        ( ushort )0x0200
-#define ASC_CNTL_INIT_INQUIRY      ( ushort )0x0400
-#define ASC_CNTL_INIT_VERBOSE      ( ushort )0x0800
-#define ASC_CNTL_SCSI_PARITY       ( ushort )0x1000
-#define ASC_CNTL_BURST_MODE        ( ushort )0x2000
-#define ASC_CNTL_SDTR_ENABLE_ULTRA ( ushort )0x4000
+#define ASC_MCNTL_NO_SEL_TIMEOUT  (ushort)0x0001
+#define ASC_MCNTL_NULL_TARGET     (ushort)0x0002
+#define ASC_CNTL_INITIATOR         (ushort)0x0001
+#define ASC_CNTL_BIOS_GT_1GB       (ushort)0x0002
+#define ASC_CNTL_BIOS_GT_2_DISK    (ushort)0x0004
+#define ASC_CNTL_BIOS_REMOVABLE    (ushort)0x0008
+#define ASC_CNTL_NO_SCAM           (ushort)0x0010
+#define ASC_CNTL_INT_MULTI_Q       (ushort)0x0080
+#define ASC_CNTL_NO_LUN_SUPPORT    (ushort)0x0040
+#define ASC_CNTL_NO_VERIFY_COPY    (ushort)0x0100
+#define ASC_CNTL_RESET_SCSI        (ushort)0x0200
+#define ASC_CNTL_INIT_INQUIRY      (ushort)0x0400
+#define ASC_CNTL_INIT_VERBOSE      (ushort)0x0800
+#define ASC_CNTL_SCSI_PARITY       (ushort)0x1000
+#define ASC_CNTL_BURST_MODE        (ushort)0x2000
+#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
 #define ASC_EEP_DVC_CFG_BEG_VL    2
 #define ASC_EEP_MAX_DVC_ADDR_VL   15
 #define ASC_EEP_DVC_CFG_BEG      32
@@ -1588,25 +1612,29 @@
 #define ASC_EEP_ISA_PNP_WSIZE    16
 
 typedef struct asceep_config {
-	ushort              cfg_lsw;
-	ushort              cfg_msw;
-	uchar               init_sdtr;
-	uchar               disc_enable;
-	uchar               use_cmd_qng;
-	uchar               start_motor;
-	uchar               max_total_qng;
-	uchar               max_tag_qng;
-	uchar               bios_scan;
-	uchar               power_up_wait;
-	uchar               no_scam;
-	uchar               chip_scsi_id:4;
-	uchar               isa_dma_speed:4;
-	uchar               dos_int13_table[ASC_MAX_TID + 1];
-	uchar               adapter_info[6];
-	ushort              cntl;
-	ushort              chksum;
+    ushort              cfg_lsw;
+    ushort              cfg_msw;
+    uchar               init_sdtr;
+    uchar               disc_enable;
+    uchar               use_cmd_qng;
+    uchar               start_motor;
+    uchar               max_total_qng;
+    uchar               max_tag_qng;
+    uchar               bios_scan;
+    uchar               power_up_wait;
+    uchar               no_scam;
+    uchar               chip_scsi_id:4;
+    uchar               isa_dma_speed:4;
+    uchar               dos_int13_table[ASC_MAX_TID + 1];
+    uchar               adapter_info[6];
+    ushort              cntl;
+    ushort              chksum;
 } ASCEEP_CONFIG;
 
+#define ASC_PCI_CFG_LSW_SCSI_PARITY  0x0800
+#define ASC_PCI_CFG_LSW_BURST_MODE   0x0080
+#define ASC_PCI_CFG_LSW_INTR_ABLE    0x0020
+
 #define ASC_EEP_CMD_READ          0x80
 #define ASC_EEP_CMD_WRITE         0x40
 #define ASC_EEP_CMD_WRITE_ABLE    0x30
@@ -1617,54 +1645,54 @@
 #define ASCV_MSGOUT_BEG         0x0000
 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
 #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
-#define ASCV_BREAK_SAVED_CODE   ( ushort )0x0006
+#define ASCV_BREAK_SAVED_CODE   (ushort)0x0006
 #define ASCV_MSGIN_BEG          (ASCV_MSGOUT_BEG+8)
 #define ASCV_MSGIN_SDTR_PERIOD  (ASCV_MSGIN_BEG+3)
 #define ASCV_MSGIN_SDTR_OFFSET  (ASCV_MSGIN_BEG+4)
 #define ASCV_SDTR_DATA_BEG      (ASCV_MSGIN_BEG+8)
 #define ASCV_SDTR_DONE_BEG      (ASCV_SDTR_DATA_BEG+8)
-#define ASCV_MAX_DVC_QNG_BEG    ( ushort )0x0020
-#define ASCV_BREAK_ADDR           ( ushort )0x0028
-#define ASCV_BREAK_NOTIFY_COUNT   ( ushort )0x002A
-#define ASCV_BREAK_CONTROL        ( ushort )0x002C
-#define ASCV_BREAK_HIT_COUNT      ( ushort )0x002E
-
-#define ASCV_ASCDVC_ERR_CODE_W  ( ushort )0x0030
-#define ASCV_MCODE_CHKSUM_W   ( ushort )0x0032
-#define ASCV_MCODE_SIZE_W     ( ushort )0x0034
-#define ASCV_STOP_CODE_B      ( ushort )0x0036
-#define ASCV_DVC_ERR_CODE_B   ( ushort )0x0037
-#define ASCV_OVERRUN_PADDR_D  ( ushort )0x0038
-#define ASCV_OVERRUN_BSIZE_D  ( ushort )0x003C
-#define ASCV_HALTCODE_W       ( ushort )0x0040
-#define ASCV_CHKSUM_W         ( ushort )0x0042
-#define ASCV_MC_DATE_W        ( ushort )0x0044
-#define ASCV_MC_VER_W         ( ushort )0x0046
-#define ASCV_NEXTRDY_B        ( ushort )0x0048
-#define ASCV_DONENEXT_B       ( ushort )0x0049
-#define ASCV_USE_TAGGED_QNG_B ( ushort )0x004A
-#define ASCV_SCSIBUSY_B       ( ushort )0x004B
-#define ASCV_Q_DONE_IN_PROGRESS_B  ( ushort )0x004C
-#define ASCV_CURCDB_B         ( ushort )0x004D
-#define ASCV_RCLUN_B          ( ushort )0x004E
-#define ASCV_BUSY_QHEAD_B     ( ushort )0x004F
-#define ASCV_DISC1_QHEAD_B    ( ushort )0x0050
-#define ASCV_DISC_ENABLE_B    ( ushort )0x0052
-#define ASCV_CAN_TAGGED_QNG_B ( ushort )0x0053
-#define ASCV_HOSTSCSI_ID_B    ( ushort )0x0055
-#define ASCV_MCODE_CNTL_B     ( ushort )0x0056
-#define ASCV_NULL_TARGET_B    ( ushort )0x0057
-#define ASCV_FREE_Q_HEAD_W    ( ushort )0x0058
-#define ASCV_DONE_Q_TAIL_W    ( ushort )0x005A
-#define ASCV_FREE_Q_HEAD_B    ( ushort )(ASCV_FREE_Q_HEAD_W+1)
-#define ASCV_DONE_Q_TAIL_B    ( ushort )(ASCV_DONE_Q_TAIL_W+1)
-#define ASCV_HOST_FLAG_B      ( ushort )0x005D
-#define ASCV_TOTAL_READY_Q_B  ( ushort )0x0064
-#define ASCV_VER_SERIAL_B     ( ushort )0x0065
-#define ASCV_HALTCODE_SAVED_W ( ushort )0x0066
-#define ASCV_WTM_FLAG_B       ( ushort )0x0068
-#define ASCV_RISC_FLAG_B      ( ushort )0x006A
-#define ASCV_REQ_SG_LIST_QP   ( ushort )0x006B
+#define ASCV_MAX_DVC_QNG_BEG    (ushort)0x0020
+#define ASCV_BREAK_ADDR           (ushort)0x0028
+#define ASCV_BREAK_NOTIFY_COUNT   (ushort)0x002A
+#define ASCV_BREAK_CONTROL        (ushort)0x002C
+#define ASCV_BREAK_HIT_COUNT      (ushort)0x002E
+
+#define ASCV_ASCDVC_ERR_CODE_W  (ushort)0x0030
+#define ASCV_MCODE_CHKSUM_W   (ushort)0x0032
+#define ASCV_MCODE_SIZE_W     (ushort)0x0034
+#define ASCV_STOP_CODE_B      (ushort)0x0036
+#define ASCV_DVC_ERR_CODE_B   (ushort)0x0037
+#define ASCV_OVERRUN_PADDR_D  (ushort)0x0038
+#define ASCV_OVERRUN_BSIZE_D  (ushort)0x003C
+#define ASCV_HALTCODE_W       (ushort)0x0040
+#define ASCV_CHKSUM_W         (ushort)0x0042
+#define ASCV_MC_DATE_W        (ushort)0x0044
+#define ASCV_MC_VER_W         (ushort)0x0046
+#define ASCV_NEXTRDY_B        (ushort)0x0048
+#define ASCV_DONENEXT_B       (ushort)0x0049
+#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
+#define ASCV_SCSIBUSY_B       (ushort)0x004B
+#define ASCV_Q_DONE_IN_PROGRESS_B  (ushort)0x004C
+#define ASCV_CURCDB_B         (ushort)0x004D
+#define ASCV_RCLUN_B          (ushort)0x004E
+#define ASCV_BUSY_QHEAD_B     (ushort)0x004F
+#define ASCV_DISC1_QHEAD_B    (ushort)0x0050
+#define ASCV_DISC_ENABLE_B    (ushort)0x0052
+#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
+#define ASCV_HOSTSCSI_ID_B    (ushort)0x0055
+#define ASCV_MCODE_CNTL_B     (ushort)0x0056
+#define ASCV_NULL_TARGET_B    (ushort)0x0057
+#define ASCV_FREE_Q_HEAD_W    (ushort)0x0058
+#define ASCV_DONE_Q_TAIL_W    (ushort)0x005A
+#define ASCV_FREE_Q_HEAD_B    (ushort)(ASCV_FREE_Q_HEAD_W+1)
+#define ASCV_DONE_Q_TAIL_B    (ushort)(ASCV_DONE_Q_TAIL_W+1)
+#define ASCV_HOST_FLAG_B      (ushort)0x005D
+#define ASCV_TOTAL_READY_Q_B  (ushort)0x0064
+#define ASCV_VER_SERIAL_B     (ushort)0x0065
+#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
+#define ASCV_WTM_FLAG_B       (ushort)0x0068
+#define ASCV_RISC_FLAG_B      (ushort)0x006A
+#define ASCV_REQ_SG_LIST_QP   (ushort)0x006B
 #define ASC_HOST_FLAG_IN_ISR        0x01
 #define ASC_HOST_FLAG_ACK_INT       0x02
 #define ASC_RISC_FLAG_GEN_INT      0x01
@@ -1707,32 +1735,34 @@
 #define IFC_SLEW_RATE     (0x20)
 #define IFC_ACT_NEG       (0x40)
 #define IFC_INP_FILTER    (0x80)
-#define IFC_INIT_DEFAULT  ( IFC_ACT_NEG | IFC_REG_UNLOCK )
-#define SC_SEL   ( uchar )(0x80)
-#define SC_BSY   ( uchar )(0x40)
-#define SC_ACK   ( uchar )(0x20)
-#define SC_REQ   ( uchar )(0x10)
-#define SC_ATN   ( uchar )(0x08)
-#define SC_IO    ( uchar )(0x04)
-#define SC_CD    ( uchar )(0x02)
-#define SC_MSG   ( uchar )(0x01)
-#define SEC_ACTIVE_NEGATE    ( uchar )( 0x40 )
-#define SEC_SLEW_RATE        ( uchar )( 0x20 )
-#define ASC_HALT_EXTMSG_IN     ( ushort )0x8000
-#define ASC_HALT_CHK_CONDITION ( ushort )0x8100
-#define ASC_HALT_SS_QUEUE_FULL ( ushort )0x8200
-#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX  ( ushort )0x8300
-#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX   ( ushort )0x8400
-#define ASC_HALT_SDTR_REJECTED ( ushort )0x4000
+#define IFC_INIT_DEFAULT  (IFC_ACT_NEG | IFC_REG_UNLOCK)
+#define SC_SEL   (uchar)(0x80)
+#define SC_BSY   (uchar)(0x40)
+#define SC_ACK   (uchar)(0x20)
+#define SC_REQ   (uchar)(0x10)
+#define SC_ATN   (uchar)(0x08)
+#define SC_IO    (uchar)(0x04)
+#define SC_CD    (uchar)(0x02)
+#define SC_MSG   (uchar)(0x01)
+#define SEC_SCSI_CTL         (uchar)(0x80)
+#define SEC_ACTIVE_NEGATE    (uchar)(0x40)
+#define SEC_SLEW_RATE        (uchar)(0x20)
+#define SEC_ENABLE_FILTER    (uchar)(0x10)
+#define ASC_HALT_EXTMSG_IN     (ushort)0x8000
+#define ASC_HALT_CHK_CONDITION (ushort)0x8100
+#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
+#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX  (ushort)0x8300
+#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX   (ushort)0x8400
+#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
 #define ASC_MAX_QNO        0xF8
-#define ASC_DATA_SEC_BEG   ( ushort )0x0080
-#define ASC_DATA_SEC_END   ( ushort )0x0080
-#define ASC_CODE_SEC_BEG   ( ushort )0x0080
-#define ASC_CODE_SEC_END   ( ushort )0x0080
+#define ASC_DATA_SEC_BEG   (ushort)0x0080
+#define ASC_DATA_SEC_END   (ushort)0x0080
+#define ASC_CODE_SEC_BEG   (ushort)0x0080
+#define ASC_CODE_SEC_END   (ushort)0x0080
 #define ASC_QADR_BEG       (0x4000)
-#define ASC_QADR_USED      ( ushort )( ASC_MAX_QNO * 64 )
-#define ASC_QADR_END       ( ushort )0x7FFF
-#define ASC_QLAST_ADR      ( ushort )0x7FC0
+#define ASC_QADR_USED      (ushort)(ASC_MAX_QNO * 64)
+#define ASC_QADR_END       (ushort)0x7FFF
+#define ASC_QLAST_ADR      (ushort)0x7FC0
 #define ASC_QBLK_SIZE      0x40
 #define ASC_BIOS_DATA_QBEG 0xF8
 #define ASC_MIN_ACTIVE_QNO 0x01
@@ -1753,37 +1783,37 @@
 #define ASC_CFG0_SCSI_PARITY_ON 0x0800
 #define ASC_CFG1_SCSI_TARGET_ON 0x0080
 #define ASC_CFG1_LRAM_8BITS_ON  0x0800
-#define ASC_CFG_MSW_CLR_MASK    0x30C0
-#define CSW_TEST1             ( ASC_CS_TYPE )0x8000
-#define CSW_AUTO_CONFIG       ( ASC_CS_TYPE )0x4000
-#define CSW_RESERVED1         ( ASC_CS_TYPE )0x2000
-#define CSW_IRQ_WRITTEN       ( ASC_CS_TYPE )0x1000
-#define CSW_33MHZ_SELECTED    ( ASC_CS_TYPE )0x0800
-#define CSW_TEST2             ( ASC_CS_TYPE )0x0400
-#define CSW_TEST3             ( ASC_CS_TYPE )0x0200
-#define CSW_RESERVED2         ( ASC_CS_TYPE )0x0100
-#define CSW_DMA_DONE          ( ASC_CS_TYPE )0x0080
-#define CSW_FIFO_RDY          ( ASC_CS_TYPE )0x0040
-#define CSW_EEP_READ_DONE     ( ASC_CS_TYPE )0x0020
-#define CSW_HALTED            ( ASC_CS_TYPE )0x0010
-#define CSW_SCSI_RESET_ACTIVE ( ASC_CS_TYPE )0x0008
-#define CSW_PARITY_ERR        ( ASC_CS_TYPE )0x0004
-#define CSW_SCSI_RESET_LATCH  ( ASC_CS_TYPE )0x0002
-#define CSW_INT_PENDING       ( ASC_CS_TYPE )0x0001
-#define CIW_CLR_SCSI_RESET_INT ( ASC_CS_TYPE )0x1000
-#define CIW_INT_ACK      ( ASC_CS_TYPE )0x0100
-#define CIW_TEST1        ( ASC_CS_TYPE )0x0200
-#define CIW_TEST2        ( ASC_CS_TYPE )0x0400
-#define CIW_SEL_33MHZ    ( ASC_CS_TYPE )0x0800
-#define CIW_IRQ_ACT      ( ASC_CS_TYPE )0x1000
-#define CC_CHIP_RESET   ( uchar )0x80
-#define CC_SCSI_RESET   ( uchar )0x40
-#define CC_HALT         ( uchar )0x20
-#define CC_SINGLE_STEP  ( uchar )0x10
-#define CC_DMA_ABLE     ( uchar )0x08
-#define CC_TEST         ( uchar )0x04
-#define CC_BANK_ONE     ( uchar )0x02
-#define CC_DIAG         ( uchar )0x01
+#define ASC_CFG_MSW_CLR_MASK    0x3080
+#define CSW_TEST1             (ASC_CS_TYPE)0x8000
+#define CSW_AUTO_CONFIG       (ASC_CS_TYPE)0x4000
+#define CSW_RESERVED1         (ASC_CS_TYPE)0x2000
+#define CSW_IRQ_WRITTEN       (ASC_CS_TYPE)0x1000
+#define CSW_33MHZ_SELECTED    (ASC_CS_TYPE)0x0800
+#define CSW_TEST2             (ASC_CS_TYPE)0x0400
+#define CSW_TEST3             (ASC_CS_TYPE)0x0200
+#define CSW_RESERVED2         (ASC_CS_TYPE)0x0100
+#define CSW_DMA_DONE          (ASC_CS_TYPE)0x0080
+#define CSW_FIFO_RDY          (ASC_CS_TYPE)0x0040
+#define CSW_EEP_READ_DONE     (ASC_CS_TYPE)0x0020
+#define CSW_HALTED            (ASC_CS_TYPE)0x0010
+#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
+#define CSW_PARITY_ERR        (ASC_CS_TYPE)0x0004
+#define CSW_SCSI_RESET_LATCH  (ASC_CS_TYPE)0x0002
+#define CSW_INT_PENDING       (ASC_CS_TYPE)0x0001
+#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
+#define CIW_INT_ACK      (ASC_CS_TYPE)0x0100
+#define CIW_TEST1        (ASC_CS_TYPE)0x0200
+#define CIW_TEST2        (ASC_CS_TYPE)0x0400
+#define CIW_SEL_33MHZ    (ASC_CS_TYPE)0x0800
+#define CIW_IRQ_ACT      (ASC_CS_TYPE)0x1000
+#define CC_CHIP_RESET   (uchar)0x80
+#define CC_SCSI_RESET   (uchar)0x40
+#define CC_HALT         (uchar)0x20
+#define CC_SINGLE_STEP  (uchar)0x10
+#define CC_DMA_ABLE     (uchar)0x08
+#define CC_TEST         (uchar)0x04
+#define CC_BANK_ONE     (uchar)0x02
+#define CC_DIAG         (uchar)0x01
 #define ASC_1000_ID0W      0x04C1
 #define ASC_1000_ID0W_FIX  0x00C1
 #define ASC_1000_ID1B      0x25
@@ -1794,385 +1824,1427 @@
 #define ASC_EISA_REV_IOP_MASK  (0x0C83)
 #define ASC_EISA_PID_IOP_MASK  (0x0C80)
 #define ASC_EISA_CFG_IOP_MASK  (0x0C86)
-#define ASC_GET_EISA_SLOT( iop )  ( PortAddr )( (iop) & 0xF000 )
+#define ASC_GET_EISA_SLOT(iop)  (PortAddr)((iop) & 0xF000)
 #define ASC_EISA_ID_740    0x01745004UL
 #define ASC_EISA_ID_750    0x01755004UL
-#define INS_HALTINT        ( ushort )0x6281
-#define INS_HALT           ( ushort )0x6280
-#define INS_SINT           ( ushort )0x6200
-#define INS_RFLAG_WTM      ( ushort )0x7380
+#define INS_HALTINT        (ushort)0x6281
+#define INS_HALT           (ushort)0x6280
+#define INS_SINT           (ushort)0x6200
+#define INS_RFLAG_WTM      (ushort)0x7380
 #define ASC_MC_SAVE_CODE_WSIZE  0x500
 #define ASC_MC_SAVE_DATA_WSIZE  0x40
 
 typedef struct asc_mc_saved {
-	ushort              data[ASC_MC_SAVE_DATA_WSIZE];
-	ushort              code[ASC_MC_SAVE_CODE_WSIZE];
+    ushort              data[ASC_MC_SAVE_DATA_WSIZE];
+    ushort              code[ASC_MC_SAVE_CODE_WSIZE];
 } ASC_MC_SAVED;
 
-#define AscGetQDoneInProgress( port )         AscReadLramByte( (port), ASCV_Q_DONE_IN_PROGRESS_B )
-#define AscPutQDoneInProgress( port, val )    AscWriteLramByte( (port), ASCV_Q_DONE_IN_PROGRESS_B, val )
-#define AscGetVarFreeQHead( port )            AscReadLramWord( (port), ASCV_FREE_Q_HEAD_W )
-#define AscGetVarDoneQTail( port )            AscReadLramWord( (port), ASCV_DONE_Q_TAIL_W )
-#define AscPutVarFreeQHead( port, val )       AscWriteLramWord( (port), ASCV_FREE_Q_HEAD_W, val )
-#define AscPutVarDoneQTail( port, val )       AscWriteLramWord( (port), ASCV_DONE_Q_TAIL_W, val )
-#define AscGetRiscVarFreeQHead( port )        AscReadLramByte( (port), ASCV_NEXTRDY_B )
-#define AscGetRiscVarDoneQTail( port )        AscReadLramByte( (port), ASCV_DONENEXT_B )
-#define AscPutRiscVarFreeQHead( port, val )   AscWriteLramByte( (port), ASCV_NEXTRDY_B, val )
-#define AscPutRiscVarDoneQTail( port, val )   AscWriteLramByte( (port), ASCV_DONENEXT_B, val )
-#define AscPutMCodeSDTRDoneAtID( port, id, data )  AscWriteLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DONE_BEG+( ushort )id ), (data) ) ;
-#define AscGetMCodeSDTRDoneAtID( port, id )        AscReadLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DONE_BEG+( ushort )id ) ) ;
-#define AscPutMCodeInitSDTRAtID( port, id, data )  AscWriteLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DATA_BEG+( ushort )id ), data ) ;
-#define AscGetMCodeInitSDTRAtID( port, id )        AscReadLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DATA_BEG+( ushort )id ) ) ;
-#define AscSynIndexToPeriod( index )        ( uchar )( asc_dvc->sdtr_period_tbl[ (index) ] )
-#define AscGetChipSignatureByte( port )     ( uchar )inp( (port)+IOP_SIG_BYTE )
-#define AscGetChipSignatureWord( port )     ( ushort )inpw( (port)+IOP_SIG_WORD )
-#define AscGetChipVerNo( port )             ( uchar )inp( (port)+IOP_VERSION )
-#define AscGetChipCfgLsw( port )            ( ushort )inpw( (port)+IOP_CONFIG_LOW )
-#define AscGetChipCfgMsw( port )            ( ushort )inpw( (port)+IOP_CONFIG_HIGH )
-#define AscSetChipCfgLsw( port, data )      outpw( (port)+IOP_CONFIG_LOW, data )
-#define AscSetChipCfgMsw( port, data )      outpw( (port)+IOP_CONFIG_HIGH, data )
-#define AscGetChipEEPCmd( port )            ( uchar )inp( (port)+IOP_EEP_CMD )
-#define AscSetChipEEPCmd( port, data )      outp( (port)+IOP_EEP_CMD, data )
-#define AscGetChipEEPData( port )           ( ushort )inpw( (port)+IOP_EEP_DATA )
-#define AscSetChipEEPData( port, data )     outpw( (port)+IOP_EEP_DATA, data )
-#define AscGetChipLramAddr( port )          ( ushort )inpw( ( PortAddr )((port)+IOP_RAM_ADDR) )
-#define AscSetChipLramAddr( port, addr )    outpw( ( PortAddr )( (port)+IOP_RAM_ADDR ), addr )
-#define AscGetChipLramData( port )          ( ushort )inpw( (port)+IOP_RAM_DATA )
-#define AscSetChipLramData( port, data )    outpw( (port)+IOP_RAM_DATA, data )
-#define AscGetChipLramDataNoSwap( port )         ( ushort )inpw_noswap( (port)+IOP_RAM_DATA )
-#define AscSetChipLramDataNoSwap( port, data )   outpw_noswap( (port)+IOP_RAM_DATA, data )
-#define AscGetChipIFC( port )               ( uchar )inp( (port)+IOP_REG_IFC )
-#define AscSetChipIFC( port, data )          outp( (port)+IOP_REG_IFC, data )
-#define AscGetChipStatus( port )            ( ASC_CS_TYPE )inpw( (port)+IOP_STATUS )
-#define AscSetChipStatus( port, cs_val )    outpw( (port)+IOP_STATUS, cs_val )
-#define AscGetChipControl( port )           ( uchar )inp( (port)+IOP_CTRL )
-#define AscSetChipControl( port, cc_val )   outp( (port)+IOP_CTRL, cc_val )
-#define AscGetChipSyn( port )               ( uchar )inp( (port)+IOP_SYN_OFFSET )
-#define AscSetChipSyn( port, data )         outp( (port)+IOP_SYN_OFFSET, data )
-#define AscSetPCAddr( port, data )          outpw( (port)+IOP_REG_PC, data )
-#define AscGetPCAddr( port )                ( ushort )inpw( (port)+IOP_REG_PC )
-#define AscIsIntPending( port )             ( AscGetChipStatus(port) & ( CSW_INT_PENDING | CSW_SCSI_RESET_LATCH ) )
-#define AscGetChipScsiID( port )            ( ( AscGetChipCfgLsw(port) >> 8 ) & ASC_MAX_TID )
-#define AscGetExtraControl( port )          ( uchar )inp( (port)+IOP_EXTRA_CONTROL )
-#define AscSetExtraControl( port, data )    outp( (port)+IOP_EXTRA_CONTROL, data )
-#define AscReadChipAX( port )               ( ushort )inpw( (port)+IOP_REG_AX )
-#define AscWriteChipAX( port, data )        outpw( (port)+IOP_REG_AX, data )
-#define AscReadChipIX( port )               ( uchar )inp( (port)+IOP_REG_IX )
-#define AscWriteChipIX( port, data )        outp( (port)+IOP_REG_IX, data )
-#define AscReadChipIH( port )               ( ushort )inpw( (port)+IOP_REG_IH )
-#define AscWriteChipIH( port, data )        outpw( (port)+IOP_REG_IH, data )
-#define AscReadChipQP( port )               ( uchar )inp( (port)+IOP_REG_QP )
-#define AscWriteChipQP( port, data )        outp( (port)+IOP_REG_QP, data )
-#define AscReadChipFIFO_L( port )           ( ushort )inpw( (port)+IOP_REG_FIFO_L )
-#define AscWriteChipFIFO_L( port, data )    outpw( (port)+IOP_REG_FIFO_L, data )
-#define AscReadChipFIFO_H( port )           ( ushort )inpw( (port)+IOP_REG_FIFO_H )
-#define AscWriteChipFIFO_H( port, data )    outpw( (port)+IOP_REG_FIFO_H, data )
-#define AscReadChipDmaSpeed( port )         ( uchar )inp( (port)+IOP_DMA_SPEED )
-#define AscWriteChipDmaSpeed( port, data )  outp( (port)+IOP_DMA_SPEED, data )
-#define AscReadChipDA0( port )              ( ushort )inpw( (port)+IOP_REG_DA0 )
-#define AscWriteChipDA0( port )             outpw( (port)+IOP_REG_DA0, data )
-#define AscReadChipDA1( port )              ( ushort )inpw( (port)+IOP_REG_DA1 )
-#define AscWriteChipDA1( port )             outpw( (port)+IOP_REG_DA1, data )
-#define AscReadChipDC0( port )              ( ushort )inpw( (port)+IOP_REG_DC0 )
-#define AscWriteChipDC0( port )             outpw( (port)+IOP_REG_DC0, data )
-#define AscReadChipDC1( port )              ( ushort )inpw( (port)+IOP_REG_DC1 )
-#define AscWriteChipDC1( port )             outpw( (port)+IOP_REG_DC1, data )
-#define AscReadChipDvcID( port )            ( uchar )inp( (port)+IOP_REG_ID )
-#define AscWriteChipDvcID( port, data )     outp( (port)+IOP_REG_ID, data )
-int                 AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
-int                 AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
-void                AscWaitEEPRead(void);
-void                AscWaitEEPWrite(void);
-ushort              AscReadEEPWord(PortAddr, uchar);
-ushort              AscWriteEEPWord(PortAddr, uchar, ushort);
-ushort              AscGetEEPConfig(PortAddr, ASCEEP_CONFIG dosfar *, ushort);
-int                 AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG dosfar *, ushort);
-int                 AscSetEEPConfig(PortAddr, ASCEEP_CONFIG dosfar *, ushort);
-ushort              AscEEPSum(PortAddr, uchar, uchar);
-int                 AscStartChip(PortAddr);
-int                 AscStopChip(PortAddr);
-void                AscSetChipIH(PortAddr, ushort);
-int                 AscIsChipHalted(PortAddr);
-void                AscResetScsiBus(PortAddr);
-int                 AscResetChip(PortAddr);
-void                AscSetChipCfgDword(PortAddr, ulong);
-ulong               AscGetChipCfgDword(PortAddr);
-void                AscAckInterrupt(PortAddr);
-void                AscDisableInterrupt(PortAddr);
-void                AscEnableInterrupt(PortAddr);
-void                AscSetBank(PortAddr, uchar);
-uchar               AscGetBank(PortAddr);
-int                 AscResetChipAndScsiBus(PortAddr);
-ushort              AscGetIsaDmaChannel(PortAddr);
-ushort              AscSetIsaDmaChannel(PortAddr, ushort);
-uchar               AscSetIsaDmaSpeed(PortAddr, uchar);
-uchar               AscGetIsaDmaSpeed(PortAddr);
-uchar               AscReadLramByte(PortAddr, ushort);
-ushort              AscReadLramWord(PortAddr, ushort);
-ulong               AscReadLramDWord(PortAddr, ushort);
-void                AscWriteLramWord(PortAddr, ushort, ushort);
-void                AscWriteLramDWord(PortAddr, ushort, ulong);
-void                AscWriteLramByte(PortAddr, ushort, uchar);
-int                 AscVerWriteLramDWord(PortAddr, ushort, ulong);
-int                 AscVerWriteLramWord(PortAddr, ushort, ushort);
-int                 AscVerWriteLramByte(PortAddr, ushort, uchar);
-ulong               AscMemSumLramWord(PortAddr, ushort, rint);
-void                AscMemWordSetLram(PortAddr, ushort, ushort, rint);
-void                AscMemWordCopyToLram(PortAddr, ushort, ushort dosfar *, int);
-void                AscMemDWordCopyToLram(PortAddr, ushort, ulong dosfar *, int);
-void                AscMemWordCopyFromLram(PortAddr, ushort, ushort dosfar *, int);
-int                 AscMemWordCmpToLram(PortAddr, ushort, ushort dosfar *, int);
-ushort              AscInitAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscInitFromEEP(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscInitWithoutEEP(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscInitFromAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscInitMicroCodeVar(ASC_DVC_VAR asc_ptr_type * asc_dvc);
-void dosfar         AscInitPollIsrCallBack(ASC_DVC_VAR asc_ptr_type *,
-										   ASC_QDONE_INFO dosfar *);
-int                 AscTestExternalLram(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscTestLramEndian(PortAddr);
-uchar               AscMsgOutSDTR(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
-uchar               AscCalSDTRData(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
-void                AscSetChipSDTR(PortAddr, uchar, uchar);
-int                 AscInitChipAllSynReg(ASC_DVC_VAR asc_ptr_type *, uchar);
-uchar               AscGetSynPeriodIndex(ASC_DVC_VAR asc_ptr_type *, ruchar);
-uchar               AscAllocFreeQueue(PortAddr, uchar);
-uchar               AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-int                 AscRiscHaltedAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
-int                 AscRiscHaltedAbortTIX(ASC_DVC_VAR asc_ptr_type *, uchar);
-int                 AscRiscHaltedAbortALL(ASC_DVC_VAR asc_ptr_type *);
-int                 AscHostReqRiscHalt(PortAddr);
-int                 AscStopQueueExe(PortAddr);
-int                 AscStartQueueExe(PortAddr);
-int                 AscCleanUpDiscQueue(PortAddr);
-int                 AscCleanUpBusyQueue(PortAddr);
-int                 _AscAbortTidBusyQueue(ASC_DVC_VAR asc_ptr_type *,
-										  ASC_QDONE_INFO dosfar *, uchar);
-int                 _AscAbortSrbBusyQueue(ASC_DVC_VAR asc_ptr_type *,
-										  ASC_QDONE_INFO dosfar *, ulong);
-int                 AscWaitTixISRDone(ASC_DVC_VAR asc_ptr_type *, uchar);
-int                 AscWaitISRDone(ASC_DVC_VAR asc_ptr_type *);
-ulong               AscGetOnePhyAddr(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong);
-int                 AscSendScsiQueue(ASC_DVC_VAR asc_ptr_type * asc_dvc,
-									 ASC_SCSI_Q dosfar * scsiq,
-									 uchar n_q_required);
-int                 AscPutReadyQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *, uchar);
-int                 AscPutReadySgListQueue(ASC_DVC_VAR asc_ptr_type *,
-										   ASC_SCSI_Q dosfar *, uchar);
-int                 AscAbortScsiIO(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
-void                AscExeScsiIO(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
-int                 AscSetChipSynRegAtID(PortAddr, uchar, uchar);
-int                 AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
-ushort              AscInitLram(ASC_DVC_VAR asc_ptr_type *);
-int                 AscReInitLram(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscInitQLinkVar(ASC_DVC_VAR asc_ptr_type *);
-int                 AscSetLibErrorCode(ASC_DVC_VAR asc_ptr_type *, ushort);
-int                 _AscWaitQDone(PortAddr, ASC_SCSI_Q dosfar *);
-int                 AscEnterCritical(void);
-void                AscLeaveCritical(int);
-int                 AscIsrChipHalted(ASC_DVC_VAR asc_ptr_type *);
-uchar               _AscCopyLramScsiDoneQ(PortAddr, ushort,
-										  ASC_QDONE_INFO dosfar *, ulong);
-int                 AscIsrQDone(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscIsrExeBusyQueue(ASC_DVC_VAR asc_ptr_type *, uchar);
-int                 AscScsiSetupCmdQ(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *,
-									 uchar dosfar *, ulong);
-int                 AscScsiInquiry(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *,
-								   uchar dosfar *, int);
-int                 AscScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *);
-int                 AscScsiStartStopUnit(ASC_DVC_VAR asc_ptr_type *,
-										 ASC_SCSI_REQ_Q dosfar *, uchar);
-int                 AscScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *,
-										ASC_SCSI_REQ_Q dosfar *,
-										uchar dosfar *);
-ulong dosfar       *swapfarbuf4(uchar dosfar *);
-int                 PollQueueDone(ASC_DVC_VAR asc_ptr_type *,
-								  ASC_SCSI_REQ_Q dosfar *,
-								  int);
-int                 PollScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *,
-										 ASC_SCSI_REQ_Q dosfar *,
-										 ASC_CAP_INFO dosfar *);
-int                 PollScsiInquiry(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *,
-									uchar dosfar *, int);
-int                 PollScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *,
-										  ASC_SCSI_REQ_Q dosfar *);
-int                 PollScsiStartUnit(ASC_DVC_VAR asc_ptr_type *,
-									  ASC_SCSI_REQ_Q dosfar *);
-int                 InitTestUnitReady(ASC_DVC_VAR asc_ptr_type *,
-									  ASC_SCSI_REQ_Q dosfar *);
-void                AscDispInquiry(uchar, uchar, ASC_SCSI_INQUIRY dosfar *);
-int                 AscPollQDone(ASC_DVC_VAR asc_ptr_type *,
-								 ASC_SCSI_REQ_Q dosfar *, int);
-int                 AscCompareString(uchar *, uchar *, int);
-int                 AscSetBIOSBank(PortAddr, int, ushort);
-int                 AscSetVlBIOSBank(PortAddr, int);
-int                 AscSetEisaBIOSBank(PortAddr, int);
-int                 AscSetIsaBIOSBank(PortAddr, int);
-ushort              AscGetEisaChipCfg(PortAddr);
-ushort              AscGetEisaChipGpReg(PortAddr);
-ushort              AscSetEisaChipCfg(PortAddr, ushort);
-ushort              AscSetEisaChipGpReg(PortAddr, ushort);
-ulong               AscGetEisaProductID(PortAddr);
-PortAddr            AscSearchIOPortAddrEISA(PortAddr);
-void                AscClrResetScsiBus(PortAddr);
-uchar               AscGetChipScsiCtrl(PortAddr);
-uchar               AscSetChipScsiID(PortAddr, uchar);
-uchar               AscGetChipVersion(PortAddr, ushort);
-ushort              AscGetChipBusType(PortAddr);
-ulong               AscLoadMicroCode(PortAddr, ushort,
-									 ushort dosfar *, ushort);
-int                 AscFindSignature(PortAddr);
-PortAddr            AscSearchIOPortAddr11(PortAddr);
-PortAddr            AscSearchIOPortAddr100(PortAddr);
-void                AscToggleIRQAct(PortAddr);
-void                AscClrResetChip(PortAddr);
-short               itos(ushort, uchar dosfar *, short, short);
-int                 insnchar(uchar dosfar *, short, short, ruchar, short);
-void                itoh(ushort, ruchar dosfar *);
-void                btoh(uchar, ruchar dosfar *);
-void                ltoh(ulong, ruchar dosfar *);
-uchar dosfar       *todstr(ushort, uchar dosfar *);
-uchar dosfar       *tohstr(ushort, uchar dosfar *);
-uchar dosfar       *tobhstr(uchar, uchar dosfar *);
-uchar dosfar       *tolhstr(ulong, uchar dosfar *);
-void                AscSetISAPNPWaitForKey(void);
-uchar               AscGetChipIRQ(PortAddr, ushort);
-uchar               AscSetChipIRQ(PortAddr, uchar, ushort);
-int                 AscIsBiosEnabled(PortAddr, ushort);
-int                 AscEnableBios(PortAddr, ushort);
-ushort              AscGetChipBiosAddress(PortAddr, ushort);
-ushort              AscSetChipBiosAddress(PortAddr, ushort, ushort);
-void                AscSingleStepChip(PortAddr);
-int                 AscPollQTailSync(PortAddr);
-int                 AscPollQHeadSync(PortAddr);
-int                 AscWaitQTailSync(PortAddr);
-int                 _AscRestoreMicroCode(PortAddr, ASC_MC_SAVED dosfar *);
-int                 AscSCAM(ASC_DVC_VAR asc_ptr_type *);
-ushort              SwapByteOfWord(ushort word_val);
-ulong               SwapWordOfDWord(ulong dword_val);
-ulong               AdjEndianDword(ulong dword_val);
-int                 AscAdjEndianScsiQ(ASC_SCSI_Q dosfar *);
-int                 AscAdjEndianQDoneInfo(ASC_QDONE_INFO dosfar *);
-int                 AscCoalesceSgList(ASC_SCSI_Q dosfar *);
-extern int          DvcEnterCritical(void);
-extern void         DvcLeaveCritical(int);
-extern void         DvcSetMemory(uchar dosfar *, uint, uchar);
-extern void         DvcCopyMemory(uchar dosfar *, uchar dosfar *, uint);
-extern void         DvcInPortWords(PortAddr, ushort dosfar *, int);
-extern void         DvcOutPortWords(PortAddr, ushort dosfar *, int);
-extern void         DvcOutPortDWords(PortAddr, ulong dosfar *, int);
-extern uchar        DvcReadPCIConfigByte(ASC_DVC_VAR asc_ptr_type *, ushort);
-extern void         DvcWritePCIConfigByte(ASC_DVC_VAR asc_ptr_type *, ushort, uchar);
-ushort 				AscGetChipBiosAddress(PortAddr, ushort);
-extern void         DvcSleepMilliSecond(ulong);
-extern void         DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type *, ulong);
-extern void         DvcDisplayString(uchar dosfar *);
-extern ulong        DvcGetPhyAddr(uchar dosfar * buf_addr, ulong buf_len);
-extern ulong        DvcGetSGList(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong,
-								 ASC_SG_HEAD dosfar *);
-extern void         DvcSCAMDelayMS(ulong);
-extern int          DvcDisableCPUInterrupt(void);
-extern void         DvcRestoreCPUInterrupt(int);
-void                DvcPutScsiQ(PortAddr, ushort, ushort dosfar *, int);
-void                DvcGetQinfo(PortAddr, ushort, ushort dosfar *, int);
-PortAddr            AscSearchIOPortAddr(PortAddr, ushort);
-ushort              AscInitGetConfig(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscInitSetConfig(ASC_DVC_VAR asc_ptr_type *);
-ushort              AscInitAsc1000Driver(ASC_DVC_VAR asc_ptr_type *);
-int                 AscInitScsiTarget(ASC_DVC_VAR asc_ptr_type *,
-									  ASC_DVC_INQ_INFO dosfar *,
-									  uchar dosfar *,
-									  ASC_CAP_INFO_ARRAY dosfar *,
-									  ushort);
-int                 AscInitPollBegin(ASC_DVC_VAR asc_ptr_type *);
-int                 AscInitPollEnd(ASC_DVC_VAR asc_ptr_type *);
-int                 AscInitPollTarget(ASC_DVC_VAR asc_ptr_type *,
-									  ASC_SCSI_REQ_Q dosfar *,
-									  ASC_SCSI_INQUIRY dosfar *,
-									  ASC_CAP_INFO dosfar *);
-int                 AscExeScsiQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
-int                 AscISR(ASC_DVC_VAR asc_ptr_type *);
-void                AscISR_AckInterrupt(ASC_DVC_VAR asc_ptr_type *);
-int                 AscISR_CheckQDone(ASC_DVC_VAR asc_ptr_type *,
-									  ASC_QDONE_INFO dosfar *,
-									  uchar dosfar *);
-int                 AscStartUnit(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_TIX_TYPE);
-int                 AscStopUnit(
-								   ASC_DVC_VAR asc_ptr_type * asc_dvc,
-								   ASC_SCSI_TIX_TYPE target_ix
-);
-uint                AscGetNumOfFreeQueue(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
-int                 AscSgListToQueue(int);
-int                 AscQueueToSgList(int);
-int                 AscSetDvcErrorCode(ASC_DVC_VAR asc_ptr_type *, uchar);
-int                 AscAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
-int                 AscResetDevice(ASC_DVC_VAR asc_ptr_type *, uchar);
-int                 AscResetSB(ASC_DVC_VAR asc_ptr_type *);
-void                AscEnableIsaDma(uchar);
-void                AscDisableIsaDma(uchar);
-ulong               AscGetMaxDmaAddress(ushort);
-ulong               AscGetMaxDmaCount(ushort);
-int                 AscSaveMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *);
-int                 AscRestoreOldMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *);
-int                 AscRestoreNewMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *);
+#define AscGetQDoneInProgress(port)         AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
+#define AscPutQDoneInProgress(port, val)    AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
+#define AscGetVarFreeQHead(port)            AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
+#define AscGetVarDoneQTail(port)            AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
+#define AscPutVarFreeQHead(port, val)       AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
+#define AscPutVarDoneQTail(port, val)       AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
+#define AscGetRiscVarFreeQHead(port)        AscReadLramByte((port), ASCV_NEXTRDY_B)
+#define AscGetRiscVarDoneQTail(port)        AscReadLramByte((port), ASCV_DONENEXT_B)
+#define AscPutRiscVarFreeQHead(port, val)   AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
+#define AscPutRiscVarDoneQTail(port, val)   AscWriteLramByte((port), ASCV_DONENEXT_B, val)
+#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)) ;
+#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)) ;
+#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data) ;
+#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)) ;
+#define AscSynIndexToPeriod(index)        (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
+#define AscGetChipSignatureByte(port)     (uchar)inp((port)+IOP_SIG_BYTE)
+#define AscGetChipSignatureWord(port)     (ushort)inpw((port)+IOP_SIG_WORD)
+#define AscGetChipVerNo(port)             (uchar)inp((port)+IOP_VERSION)
+#define AscGetChipCfgLsw(port)            (ushort)inpw((port)+IOP_CONFIG_LOW)
+#define AscGetChipCfgMsw(port)            (ushort)inpw((port)+IOP_CONFIG_HIGH)
+#define AscSetChipCfgLsw(port, data)      outpw((port)+IOP_CONFIG_LOW, data)
+#define AscSetChipCfgMsw(port, data)      outpw((port)+IOP_CONFIG_HIGH, data)
+#define AscGetChipEEPCmd(port)            (uchar)inp((port)+IOP_EEP_CMD)
+#define AscSetChipEEPCmd(port, data)      outp((port)+IOP_EEP_CMD, data)
+#define AscGetChipEEPData(port)           (ushort)inpw((port)+IOP_EEP_DATA)
+#define AscSetChipEEPData(port, data)     outpw((port)+IOP_EEP_DATA, data)
+#define AscGetChipLramAddr(port)          (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
+#define AscSetChipLramAddr(port, addr)    outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
+#define AscGetChipLramData(port)          (ushort)inpw((port)+IOP_RAM_DATA)
+#define AscSetChipLramData(port, data)    outpw((port)+IOP_RAM_DATA, data)
+#define AscGetChipLramDataNoSwap(port)         (ushort)inpw_noswap((port)+IOP_RAM_DATA)
+#define AscSetChipLramDataNoSwap(port, data)   outpw_noswap((port)+IOP_RAM_DATA, data)
+#define AscGetChipIFC(port)               (uchar)inp((port)+IOP_REG_IFC)
+#define AscSetChipIFC(port, data)          outp((port)+IOP_REG_IFC, data)
+#define AscGetChipStatus(port)            (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
+#define AscSetChipStatus(port, cs_val)    outpw((port)+IOP_STATUS, cs_val)
+#define AscGetChipControl(port)           (uchar)inp((port)+IOP_CTRL)
+#define AscSetChipControl(port, cc_val)   outp((port)+IOP_CTRL, cc_val)
+#define AscGetChipSyn(port)               (uchar)inp((port)+IOP_SYN_OFFSET)
+#define AscSetChipSyn(port, data)         outp((port)+IOP_SYN_OFFSET, data)
+#define AscSetPCAddr(port, data)          outpw((port)+IOP_REG_PC, data)
+#define AscGetPCAddr(port)                (ushort)inpw((port)+IOP_REG_PC)
+#define AscIsIntPending(port)             (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
+#define AscGetChipScsiID(port)            ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
+#define AscGetExtraControl(port)          (uchar)inp((port)+IOP_EXTRA_CONTROL)
+#define AscSetExtraControl(port, data)    outp((port)+IOP_EXTRA_CONTROL, data)
+#define AscReadChipAX(port)               (ushort)inpw((port)+IOP_REG_AX)
+#define AscWriteChipAX(port, data)        outpw((port)+IOP_REG_AX, data)
+#define AscReadChipIX(port)               (uchar)inp((port)+IOP_REG_IX)
+#define AscWriteChipIX(port, data)        outp((port)+IOP_REG_IX, data)
+#define AscReadChipIH(port)               (ushort)inpw((port)+IOP_REG_IH)
+#define AscWriteChipIH(port, data)        outpw((port)+IOP_REG_IH, data)
+#define AscReadChipQP(port)               (uchar)inp((port)+IOP_REG_QP)
+#define AscWriteChipQP(port, data)        outp((port)+IOP_REG_QP, data)
+#define AscReadChipFIFO_L(port)           (ushort)inpw((port)+IOP_REG_FIFO_L)
+#define AscWriteChipFIFO_L(port, data)    outpw((port)+IOP_REG_FIFO_L, data)
+#define AscReadChipFIFO_H(port)           (ushort)inpw((port)+IOP_REG_FIFO_H)
+#define AscWriteChipFIFO_H(port, data)    outpw((port)+IOP_REG_FIFO_H, data)
+#define AscReadChipDmaSpeed(port)         (uchar)inp((port)+IOP_DMA_SPEED)
+#define AscWriteChipDmaSpeed(port, data)  outp((port)+IOP_DMA_SPEED, data)
+#define AscReadChipDA0(port)              (ushort)inpw((port)+IOP_REG_DA0)
+#define AscWriteChipDA0(port)             outpw((port)+IOP_REG_DA0, data)
+#define AscReadChipDA1(port)              (ushort)inpw((port)+IOP_REG_DA1)
+#define AscWriteChipDA1(port)             outpw((port)+IOP_REG_DA1, data)
+#define AscReadChipDC0(port)              (ushort)inpw((port)+IOP_REG_DC0)
+#define AscWriteChipDC0(port)             outpw((port)+IOP_REG_DC0, data)
+#define AscReadChipDC1(port)              (ushort)inpw((port)+IOP_REG_DC1)
+#define AscWriteChipDC1(port)             outpw((port)+IOP_REG_DC1, data)
+#define AscReadChipDvcID(port)            (uchar)inp((port)+IOP_REG_ID)
+#define AscWriteChipDvcID(port, data)     outp((port)+IOP_REG_ID, data)
+
+STATIC int       AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
+STATIC int       AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
+STATIC void      AscWaitEEPRead(void);
+STATIC void      AscWaitEEPWrite(void);
+STATIC ushort    AscReadEEPWord(PortAddr, uchar);
+STATIC ushort    AscWriteEEPWord(PortAddr, uchar, ushort);
+STATIC ushort    AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC int       AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC int       AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC int       AscStartChip(PortAddr);
+STATIC int       AscStopChip(PortAddr);
+STATIC void      AscSetChipIH(PortAddr, ushort);
+STATIC int       AscIsChipHalted(PortAddr);
+STATIC void      AscAckInterrupt(PortAddr);
+STATIC void      AscDisableInterrupt(PortAddr);
+STATIC void      AscEnableInterrupt(PortAddr);
+STATIC void      AscSetBank(PortAddr, uchar);
+STATIC int       AscResetChipAndScsiBus(ASC_DVC_VAR *);
+STATIC ushort    AscGetIsaDmaChannel(PortAddr);
+STATIC ushort    AscSetIsaDmaChannel(PortAddr, ushort);
+STATIC uchar     AscSetIsaDmaSpeed(PortAddr, uchar);
+STATIC uchar     AscGetIsaDmaSpeed(PortAddr);
+STATIC uchar     AscReadLramByte(PortAddr, ushort);
+STATIC ushort    AscReadLramWord(PortAddr, ushort);
+STATIC ulong     AscReadLramDWord(PortAddr, ushort);
+STATIC void      AscWriteLramWord(PortAddr, ushort, ushort);
+STATIC void      AscWriteLramDWord(PortAddr, ushort, ulong);
+STATIC void      AscWriteLramByte(PortAddr, ushort, uchar);
+STATIC ulong     AscMemSumLramWord(PortAddr, ushort, rint);
+STATIC void      AscMemWordSetLram(PortAddr, ushort, ushort, rint);
+STATIC void      AscMemWordCopyToLram(PortAddr, ushort, ushort *, int);
+STATIC void      AscMemDWordCopyToLram(PortAddr, ushort, ulong *, int);
+STATIC void      AscMemWordCopyFromLram(PortAddr, ushort, ushort *, int);
+STATIC ushort    AscInitAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
+STATIC ushort    AscInitFromEEP(ASC_DVC_VAR asc_ptr_type *);
+STATIC ushort    AscInitFromAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
+STATIC ushort    AscInitMicroCodeVar(ASC_DVC_VAR asc_ptr_type * asc_dvc);
+STATIC void      AscInitPollIsrCallBack(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_QDONE_INFO *);
+STATIC int       AscTestExternalLram(ASC_DVC_VAR asc_ptr_type *);
+STATIC uchar     AscMsgOutSDTR(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
+STATIC uchar     AscCalSDTRData(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
+STATIC void      AscSetChipSDTR(PortAddr, uchar, uchar);
+STATIC uchar     AscGetSynPeriodIndex(ASC_DVC_VAR asc_ptr_type *, ruchar);
+STATIC uchar     AscAllocFreeQueue(PortAddr, uchar);
+STATIC uchar     AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
+STATIC int       AscRiscHaltedAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int       AscRiscHaltedAbortTIX(ASC_DVC_VAR asc_ptr_type *, uchar);
+#endif /* version >= v1.3.89 */
+STATIC int       AscHostReqRiscHalt(PortAddr);
+STATIC int       AscStopQueueExe(PortAddr);
+STATIC int       AscStartQueueExe(PortAddr);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int       AscCleanUpDiscQueue(PortAddr);
+#endif /* version >= v1.3.89 */
+STATIC int       AscCleanUpBusyQueue(PortAddr);
+STATIC int       AscWaitTixISRDone(ASC_DVC_VAR asc_ptr_type *, uchar);
+STATIC int       AscWaitISRDone(ASC_DVC_VAR asc_ptr_type *);
+STATIC ulong     AscGetOnePhyAddr(ASC_DVC_VAR asc_ptr_type *, uchar *,
+                    ulong);
+STATIC int       AscSendScsiQueue(ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                    ASC_SCSI_Q * scsiq,
+                    uchar n_q_required);
+STATIC int       AscPutReadyQueue(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_Q *, uchar);
+STATIC int       AscPutReadySgListQueue(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_Q *, uchar);
+STATIC int       AscSetChipSynRegAtID(PortAddr, uchar, uchar);
+STATIC int       AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
+STATIC ushort    AscInitLram(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscReInitLram(ASC_DVC_VAR asc_ptr_type *);
+STATIC ushort    AscInitQLinkVar(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscSetLibErrorCode(ASC_DVC_VAR asc_ptr_type *, ushort);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int       _AscWaitQDone(PortAddr, ASC_SCSI_Q *);
+#endif /* version >= v1.3.89 */
+STATIC int       AscIsrChipHalted(ASC_DVC_VAR asc_ptr_type *);
+STATIC uchar     _AscCopyLramScsiDoneQ(PortAddr, ushort,
+                    ASC_QDONE_INFO *, ulong);
+STATIC int       AscIsrQDone(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscScsiSetupCmdQ(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, uchar *, ulong);
+STATIC int       AscScsiInquiry(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, uchar *, int);
+STATIC int       AscScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *);
+STATIC int       AscScsiStartStopUnit(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, uchar);
+STATIC int       AscScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, uchar *);
+STATIC ulong     *swapfarbuf4(uchar *);
+STATIC int       PollQueueDone(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, int);
+STATIC int       PollScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, ASC_CAP_INFO *);
+STATIC int       PollScsiInquiry(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, uchar *, int);
+STATIC int       PollScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *);
+STATIC int       PollScsiStartUnit(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *);
+STATIC int       InitTestUnitReady(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *);
+STATIC int       AscPollQDone(ASC_DVC_VAR asc_ptr_type *,
+                    ASC_SCSI_REQ_Q *, int);
+STATIC int       AscCompareString(uchar *, uchar *, int);
+STATIC ushort    AscGetEisaChipCfg(PortAddr);
+STATIC ulong     AscGetEisaProductID(PortAddr);
+STATIC PortAddr  AscSearchIOPortAddrEISA(PortAddr);
+STATIC uchar     AscGetChipScsiCtrl(PortAddr);
+STATIC uchar     AscSetChipScsiID(PortAddr, uchar);
+STATIC uchar     AscGetChipVersion(PortAddr, ushort);
+STATIC ushort    AscGetChipBusType(PortAddr);
+STATIC ulong     AscLoadMicroCode(PortAddr, ushort, ushort *, ushort);
+STATIC int       AscFindSignature(PortAddr);
+STATIC PortAddr  AscSearchIOPortAddr11(PortAddr);
+STATIC void      AscToggleIRQAct(PortAddr);
+STATIC void      AscSetISAPNPWaitForKey(void);
+STATIC uchar     AscGetChipIRQ(PortAddr, ushort);
+STATIC uchar     AscSetChipIRQ(PortAddr, uchar, ushort);
+STATIC ushort    AscGetChipBiosAddress(PortAddr, ushort);
+STATIC int       DvcEnterCritical(void);
+STATIC void      DvcLeaveCritical(int);
+STATIC void      DvcInPortWords(PortAddr, ushort *, int);
+STATIC void      DvcOutPortWords(PortAddr, ushort *, int);
+STATIC void      DvcOutPortDWords(PortAddr, ulong *, int);
+STATIC uchar     DvcReadPCIConfigByte(ASC_DVC_VAR asc_ptr_type *, ushort);
+STATIC void      DvcWritePCIConfigByte(ASC_DVC_VAR asc_ptr_type *,
+                    ushort, uchar);
+STATIC ushort      AscGetChipBiosAddress(PortAddr, ushort);
+STATIC void      DvcSleepMilliSecond(ulong);
+STATIC void      DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type *, ulong);
+STATIC ulong     DvcGetSGList(ASC_DVC_VAR asc_ptr_type *, uchar *,
+                    ulong, ASC_SG_HEAD *);
+STATIC void      DvcPutScsiQ(PortAddr, ushort, ushort *, int);
+STATIC void      DvcGetQinfo(PortAddr, ushort, ushort *, int);
+STATIC PortAddr  AscSearchIOPortAddr(PortAddr, ushort);
+STATIC ushort    AscInitGetConfig(ASC_DVC_VAR asc_ptr_type *);
+STATIC ushort    AscInitSetConfig(ASC_DVC_VAR asc_ptr_type *);
+STATIC ushort    AscInitAsc1000Driver(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscInitPollBegin(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscInitPollEnd(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscInitPollTarget(ASC_DVC_VAR asc_ptr_type *,
+                     ASC_SCSI_REQ_Q *, ASC_SCSI_INQUIRY *, ASC_CAP_INFO *);
+STATIC int       AscExeScsiQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q *);
+STATIC int       AscISR(ASC_DVC_VAR asc_ptr_type *);
+STATIC uint      AscGetNumOfFreeQueue(ASC_DVC_VAR asc_ptr_type *, uchar,
+                    uchar);
+STATIC int       AscSgListToQueue(int);
+STATIC int       AscAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int       AscResetDevice(ASC_DVC_VAR asc_ptr_type *, uchar);
+#endif /* version >= v1.3.89 */
+STATIC int       AscResetSB(ASC_DVC_VAR asc_ptr_type *);
+STATIC void      AscEnableIsaDma(uchar);
+STATIC ulong     AscGetMaxDmaCount(ushort);
+
 
 /*
- * --- Debugging Header
+ * --- Adv Library Constants and Macros
  */
 
-#ifdef ADVANSYS_DEBUG
-#define STATIC
-#else /* ADVANSYS_DEBUG */
-#define STATIC static
-#endif /* ADVANSYS_DEBUG */
+#define ADV_LIB_VERSION_MAJOR  3
+#define ADV_LIB_VERSION_MINOR  34
+
+/* d_os_dep.h */
+#define ADV_OS_LINUX
+
+/*
+ * Define Adv Library required special types.
+ */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+#define AdvPortAddr  unsigned short     /* I/O Port address size */
+#else /* version >= v1,3,0 */
+#define AdvPortAddr  unsigned long      /* Virtual memory address size */
+#endif /* version >= v1,3,0 */
+
+/*
+ * Define Adv Library required memory access macros.
+ */
+#define ADV_MEM_READB(addr) readb(addr)
+#define ADV_MEM_READW(addr) readw(addr)
+#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
+#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
+
+/*
+ * The I/O memory mapping function names changed in 2.1.X.
+ */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#define ioremap vremap
+#define iounmap vfree
+#endif /* version < v2.1.0 */
+
+/*
+ * Define total number of simultaneous maximum element scatter-gather
+ * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number
+ * of simultaneous scatter-gather elements supported per wide adapter.
+ */
+#define ADV_TOT_SG_LIST         64
+
+/*
+ * Define Adv Library required per request scatter-gather element limit.
+ */
+#define ADV_MAX_SG_LIST         64
+
+/*
+ * Scatter-Gather Definitions per request.
+ *
+ * Because SG block memory is allocated in virtual memory but is
+ * referenced by the microcode as physical memory, we need to do
+ * calculations to insure there will be enough physically contiguous
+ * memory to support ADV_MAX_SG_LIST SG entries.
+ */
+
+/* Number of SG blocks needed. */
+#define ADV_NUM_SG_BLOCK \
+     ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
+
+/* Total contiguous memory needed for SG blocks. */
+#define ADV_SG_TOTAL_MEM_SIZE \
+    (sizeof(ADV_SG_BLOCK) *  ADV_NUM_SG_BLOCK)
+
+#define ASC_PAGE_SIZE PAGE_SIZE
+
+/*
+ * Number of page crossings possible for the total contiguous virtual memory
+ * needed for SG blocks.
+ *
+ * We need to allocate this many additional SG blocks in virtual memory to
+ * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous
+ * scatter-gather blocks.
+ */
+#define ADV_NUM_PAGE_CROSSING \
+    ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE)
+
+/*
+ * Define Adv Library Assertion Macro.
+ */
+
+#define ADV_ASSERT(a) ASC_ASSERT(a)
+
+/* a_condor.h */
+#define ADV_PCI_VENDOR_ID               0x10CD
+#define ADV_PCI_DEVICE_ID_REV_A         0x2300
+
+#define ASC_EEP_DVC_CFG_BEGIN           (0x00)
+#define ASC_EEP_DVC_CFG_END             (0x15)
+#define ASC_EEP_DVC_CTL_BEGIN           (0x16)  /* location of OEM name */
+#define ASC_EEP_MAX_WORD_ADDR           (0x1E)
+
+#define ASC_EEP_DELAY_MS                100
+
+/*
+ * EEPROM bits reference by the RISC after initialization.
+ */
+#define ADV_EEPROM_BIG_ENDIAN          0x8000   /* EEPROM Bit 15 */
+#define ADV_EEPROM_BIOS_ENABLE         0x4000   /* EEPROM Bit 14 */
+#define ADV_EEPROM_TERM_POL            0x2000   /* EEPROM Bit 13 */
+
+/*
+ * EEPROM configuration format
+ *
+ * Field naming convention: 
+ *
+ *  *_enable indicates the field enables or disables the feature. The
+ *  value is never reset.
+ *
+ *  *_able indicates both whether a feature should be enabled or disabled
+ *  and whether a device isi capable of the feature. At initialization
+ *  this field may be set, but later if a device is found to be incapable
+ *  of the feature, the field is cleared.
+ *
+ * Default values are maintained in a_init.c in the structure
+ * Default_EEPROM_Config.
+ */
+typedef struct adveep_config
+{                              
+                                /* Word Offset, Description */
+
+  ushort cfg_lsw;               /* 00 power up initialization */
+                                /*  bit 13 set - Term Polarity Control */
+                                /*  bit 14 set - BIOS Enable */
+                                /*  bit 15 set - Big Endian Mode */
+  ushort cfg_msw;               /* 01 unused      */
+  ushort disc_enable;           /* 02 disconnect enable */         
+  ushort wdtr_able;             /* 03 Wide DTR able */
+  ushort sdtr_able;             /* 04 Synchronous DTR able */
+  ushort start_motor;           /* 05 send start up motor */      
+  ushort tagqng_able;           /* 06 tag queuing able */
+  ushort bios_scan;             /* 07 BIOS device control */   
+  ushort scam_tolerant;         /* 08 no scam */  
+ 
+  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
+  uchar  bios_boot_delay;       /*    power up wait */
+ 
+  uchar  scsi_reset_delay;      /* 10 reset delay */
+  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
+                                /*    high nibble is lun */  
+                                /*    low nibble is scsi id */
+
+  uchar  termination;           /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  uchar  reserved1;             /*    reserved byte (not used) */                                  
+
+  ushort bios_ctrl;             /* 12 BIOS control bits */
+                                /*  bit 0  set: BIOS don't act as initiator. */
+                                /*  bit 1  set: BIOS > 1 GB support */
+                                /*  bit 2  set: BIOS > 2 Disk Support */
+                                /*  bit 3  set: BIOS don't support removables */
+                                /*  bit 4  set: BIOS support bootable CD */
+                                /*  bit 5  set: */
+                                /*  bit 6  set: BIOS support multiple LUNs */
+                                /*  bit 7  set: BIOS display of message */
+                                /*  bit 8  set: */
+                                /*  bit 9  set: Reset SCSI bus during init. */
+                                /*  bit 10 set: */
+                                /*  bit 11 set: No verbose initialization. */
+                                /*  bit 12 set: SCSI parity enabled */
+                                /*  bit 13 set: */
+                                /*  bit 14 set: */
+                                /*  bit 15 set: */
+  ushort  ultra_able;           /* 13 ULTRA speed able */ 
+  ushort  reserved2;            /* 14 reserved */
+  uchar   max_host_qng;         /* 15 maximum host queuing */
+  uchar   max_dvc_qng;          /*    maximum per device queuing */
+  ushort  dvc_cntl;             /* 16 control bit for driver */
+  ushort  bug_fix;              /* 17 control bit for bug fix */
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */  
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */  
+  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
+  ushort  check_sum;            /* 21 EEP check sum */
+  uchar   oem_name[16];         /* 22 OEM name */
+  ushort  dvc_err_code;         /* 30 last device driver error code */
+  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
+  ushort  adv_err_addr;         /* 32 last uc error address */
+  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
+  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */  
+  ushort  num_of_err;           /* 36 number of error */
+} ADVEEP_CONFIG; 
+
+/*
+ * EEPROM Commands
+ */
+#define ASC_EEP_CMD_DONE             0x0200
+#define ASC_EEP_CMD_DONE_ERR         0x0001
+
+/* cfg_word */
+#define EEP_CFG_WORD_BIG_ENDIAN      0x8000
+
+/* bios_ctrl */
+#define BIOS_CTRL_BIOS               0x0001
+#define BIOS_CTRL_EXTENDED_XLAT      0x0002
+#define BIOS_CTRL_GT_2_DISK          0x0004
+#define BIOS_CTRL_BIOS_REMOVABLE     0x0008
+#define BIOS_CTRL_BOOTABLE_CD        0x0010
+#define BIOS_CTRL_MULTIPLE_LUN       0x0040
+#define BIOS_CTRL_DISPLAY_MSG        0x0080
+#define BIOS_CTRL_NO_SCAM            0x0100
+#define BIOS_CTRL_RESET_SCSI_BUS     0x0200
+#define BIOS_CTRL_INIT_VERBOSE       0x0800
+#define BIOS_CTRL_SCSI_PARITY        0x1000
+
+/*
+ * ASC 3550 Internal Memory Size - 8KB
+ */
+#define ADV_CONDOR_MEMSIZE   0x2000     /* 8 KB Internal Memory */
+
+/*
+ * ASC 3550 I/O Length - 64 bytes
+ */
+#define ADV_CONDOR_IOLEN     0x40       /* I/O Port Range in bytes */
+
+/*
+ * Byte I/O register address from base of 'iop_base'.
+ */
+#define IOPB_INTR_STATUS_REG    0x00
+#define IOPB_CHIP_ID_1          0x01
+#define IOPB_INTR_ENABLES       0x02
+#define IOPB_CHIP_TYPE_REV      0x03
+#define IOPB_RES_ADDR_4         0x04
+#define IOPB_RES_ADDR_5         0x05
+#define IOPB_RAM_DATA           0x06
+#define IOPB_RES_ADDR_7         0x07
+#define IOPB_FLAG_REG           0x08
+#define IOPB_RES_ADDR_9         0x09
+#define IOPB_RISC_CSR           0x0A
+#define IOPB_RES_ADDR_B         0x0B
+#define IOPB_RES_ADDR_C         0x0C
+#define IOPB_RES_ADDR_D         0x0D
+#define IOPB_RES_ADDR_E         0x0E
+#define IOPB_RES_ADDR_F         0x0F
+#define IOPB_MEM_CFG            0x10
+#define IOPB_RES_ADDR_11        0x11
+#define IOPB_RES_ADDR_12        0x12
+#define IOPB_RES_ADDR_13        0x13
+#define IOPB_FLASH_PAGE         0x14
+#define IOPB_RES_ADDR_15        0x15
+#define IOPB_RES_ADDR_16        0x16
+#define IOPB_RES_ADDR_17        0x17
+#define IOPB_FLASH_DATA         0x18
+#define IOPB_RES_ADDR_19        0x19
+#define IOPB_RES_ADDR_1A        0x1A
+#define IOPB_RES_ADDR_1B        0x1B
+#define IOPB_RES_ADDR_1C        0x1C
+#define IOPB_RES_ADDR_1D        0x1D
+#define IOPB_RES_ADDR_1E        0x1E
+#define IOPB_RES_ADDR_1F        0x1F
+#define IOPB_DMA_CFG0           0x20
+#define IOPB_DMA_CFG1           0x21
+#define IOPB_TICKLE             0x22
+#define IOPB_DMA_REG_WR         0x23
+#define IOPB_SDMA_STATUS        0x24
+#define IOPB_SCSI_BYTE_CNT      0x25
+#define IOPB_HOST_BYTE_CNT      0x26
+#define IOPB_BYTE_LEFT_TO_XFER  0x27
+#define IOPB_BYTE_TO_XFER_0     0x28
+#define IOPB_BYTE_TO_XFER_1     0x29
+#define IOPB_BYTE_TO_XFER_2     0x2A
+#define IOPB_BYTE_TO_XFER_3     0x2B
+#define IOPB_ACC_GRP            0x2C
+#define IOPB_RES_ADDR_2D        0x2D
+#define IOPB_DEV_ID             0x2E
+#define IOPB_RES_ADDR_2F        0x2F
+#define IOPB_SCSI_DATA          0x30
+#define IOPB_RES_ADDR_31        0x31
+#define IOPB_RES_ADDR_32        0x32
+#define IOPB_SCSI_DATA_HSHK     0x33
+#define IOPB_SCSI_CTRL          0x34
+#define IOPB_RES_ADDR_35        0x35
+#define IOPB_RES_ADDR_36        0x36
+#define IOPB_RES_ADDR_37        0x37
+#define IOPB_RES_ADDR_38        0x38
+#define IOPB_RES_ADDR_39        0x39
+#define IOPB_RES_ADDR_3A        0x3A
+#define IOPB_RES_ADDR_3B        0x3B
+#define IOPB_RFIFO_CNT          0x3C
+#define IOPB_RES_ADDR_3D        0x3D
+#define IOPB_RES_ADDR_3E        0x3E
+#define IOPB_RES_ADDR_3F        0x3F
+
+/*
+ * Word I/O register address from base of 'iop_base'.
+ */
+#define IOPW_CHIP_ID_0          0x00  /* CID0  */
+#define IOPW_CTRL_REG           0x02  /* CC    */
+#define IOPW_RAM_ADDR           0x04  /* LA    */
+#define IOPW_RAM_DATA           0x06  /* LD    */
+#define IOPW_RES_ADDR_08        0x08
+#define IOPW_RISC_CSR           0x0A  /* CSR   */
+#define IOPW_SCSI_CFG0          0x0C  /* CFG0  */
+#define IOPW_SCSI_CFG1          0x0E  /* CFG1  */
+#define IOPW_RES_ADDR_10        0x10
+#define IOPW_SEL_MASK           0x12  /* SM    */
+#define IOPW_RES_ADDR_14        0x14
+#define IOPW_FLASH_ADDR         0x16  /* FA    */
+#define IOPW_RES_ADDR_18        0x18
+#define IOPW_EE_CMD             0x1A  /* EC    */
+#define IOPW_EE_DATA            0x1C  /* ED    */
+#define IOPW_SFIFO_CNT          0x1E  /* SFC   */
+#define IOPW_RES_ADDR_20        0x20
+#define IOPW_Q_BASE             0x22  /* QB    */
+#define IOPW_QP                 0x24  /* QP    */
+#define IOPW_IX                 0x26  /* IX    */
+#define IOPW_SP                 0x28  /* SP    */
+#define IOPW_PC                 0x2A  /* PC    */
+#define IOPW_RES_ADDR_2C        0x2C
+#define IOPW_RES_ADDR_2E        0x2E
+#define IOPW_SCSI_DATA          0x30  /* SD    */
+#define IOPW_SCSI_DATA_HSHK     0x32  /* SDH   */
+#define IOPW_SCSI_CTRL          0x34  /* SC    */
+#define IOPW_HSHK_CFG           0x36  /* HCFG  */
+#define IOPW_SXFR_STATUS        0x36  /* SXS   */
+#define IOPW_SXFR_CNTL          0x38  /* SXL   */
+#define IOPW_SXFR_CNTH          0x3A  /* SXH   */
+#define IOPW_RES_ADDR_3C        0x3C
+#define IOPW_RFIFO_DATA         0x3E  /* RFD   */
+
+/*
+ * Doubleword I/O register address from base of 'iop_base'.
+ */
+#define IOPDW_RES_ADDR_0         0x00
+#define IOPDW_RAM_DATA           0x04
+#define IOPDW_RES_ADDR_8         0x08
+#define IOPDW_RES_ADDR_C         0x0C
+#define IOPDW_RES_ADDR_10        0x10
+#define IOPDW_RES_ADDR_14        0x14
+#define IOPDW_RES_ADDR_18        0x18
+#define IOPDW_RES_ADDR_1C        0x1C
+#define IOPDW_SDMA_ADDR0         0x20
+#define IOPDW_SDMA_ADDR1         0x24
+#define IOPDW_SDMA_COUNT         0x28
+#define IOPDW_SDMA_ERROR         0x2C
+#define IOPDW_RDMA_ADDR0         0x30
+#define IOPDW_RDMA_ADDR1         0x34
+#define IOPDW_RDMA_COUNT         0x38
+#define IOPDW_RDMA_ERROR         0x3C
+
+#define ADV_CHIP_ID_BYTE         0x25
+#define ADV_CHIP_ID_WORD         0x04C1
+
+#define ADV_SC_SCSI_BUS_RESET    0x2000
+
+#define ADV_INTR_ENABLE_HOST_INTR                   0x01
+#define ADV_INTR_ENABLE_SEL_INTR                    0x02
+#define ADV_INTR_ENABLE_DPR_INTR                    0x04
+#define ADV_INTR_ENABLE_RTA_INTR                    0x08
+#define ADV_INTR_ENABLE_RMA_INTR                    0x10
+#define ADV_INTR_ENABLE_RST_INTR                    0x20
+#define ADV_INTR_ENABLE_DPE_INTR                    0x40
+#define ADV_INTR_ENABLE_GLOBAL_INTR                 0x80
+
+#define ADV_INTR_STATUS_INTRA            0x01
+#define ADV_INTR_STATUS_INTRB            0x02
+#define ADV_INTR_STATUS_INTRC            0x04
+
+#define ADV_RISC_CSR_STOP           (0x0000)
+#define ADV_RISC_TEST_COND          (0x2000)
+#define ADV_RISC_CSR_RUN            (0x4000)
+#define ADV_RISC_CSR_SINGLE_STEP    (0x8000)
+
+#define ADV_CTRL_REG_HOST_INTR      0x0100
+#define ADV_CTRL_REG_SEL_INTR       0x0200
+#define ADV_CTRL_REG_DPR_INTR       0x0400
+#define ADV_CTRL_REG_RTA_INTR       0x0800
+#define ADV_CTRL_REG_RMA_INTR       0x1000
+#define ADV_CTRL_REG_RES_BIT14      0x2000
+#define ADV_CTRL_REG_DPE_INTR       0x4000
+#define ADV_CTRL_REG_POWER_DONE     0x8000
+#define ADV_CTRL_REG_ANY_INTR       0xFF00
+
+#define ADV_CTRL_REG_CMD_RESET             0x00C6
+#define ADV_CTRL_REG_CMD_WR_IO_REG         0x00C5
+#define ADV_CTRL_REG_CMD_RD_IO_REG         0x00C4
+#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE  0x00C3
+#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE  0x00C2
+
+#define ADV_SCSI_CTRL_RSTOUT        0x2000
+
+#define AdvIsIntPending(port)  \
+    (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
+
+/*
+ * SCSI_CFG0 Register bit definitions
+ */
+#define TIMER_MODEAB    0xC000  /* Watchdog, Second, and Select. Timer Ctrl. */
+#define PARITY_EN       0x2000  /* Enable SCSI Parity Error detection */
+#define EVEN_PARITY     0x1000  /* Select Even Parity */
+#define WD_LONG         0x0800  /* Watchdog Interval, 1: 57 min, 0: 13 sec */
+#define QUEUE_128       0x0400  /* Queue Size, 1: 128 byte, 0: 64 byte */
+#define PRIM_MODE       0x0100  /* Primitive SCSI mode */
+#define SCAM_EN         0x0080  /* Enable SCAM selection */
+#define SEL_TMO_LONG    0x0040  /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
+#define CFRM_ID         0x0020  /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
+#define OUR_ID_EN       0x0010  /* Enable OUR_ID bits */
+#define OUR_ID          0x000F  /* SCSI ID */
+
+/*
+ * SCSI_CFG1 Register bit definitions
+ */
+#define BIG_ENDIAN      0x8000  /* Enable Big Endian Mode MIO:15, EEP:15 */
+#define TERM_POL        0x2000  /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
+#define SLEW_RATE       0x1000  /* SCSI output buffer slew rate */
+#define FILTER_SEL      0x0C00  /* Filter Period Selection */
+#define  FLTR_DISABLE    0x0000  /* Input Filtering Disabled */
+#define  FLTR_11_TO_20NS 0x0800  /* Input Filtering 11ns to 20ns */          
+#define  FLTR_21_TO_39NS 0x0C00  /* Input Filtering 21ns to 39ns */          
+#define ACTIVE_DBL      0x0200  /* Disable Active Negation */
+#define DIFF_MODE       0x0100  /* SCSI differential Mode (Read-Only) */
+#define DIFF_SENSE      0x0080  /* 1: No SE cables, 0: SE cable (Read-Only) */
+#define TERM_CTL_SEL    0x0040  /* Enable TERM_CTL_H and TERM_CTL_L */
+#define TERM_CTL        0x0030  /* External SCSI Termination Bits */
+#define  TERM_CTL_H      0x0020  /* Enable External SCSI Upper Termination */
+#define  TERM_CTL_L      0x0010  /* Enable External SCSI Lower Termination */
+#define CABLE_DETECT    0x000F  /* External SCSI Cable Connection Status */
+
+#define CABLE_ILLEGAL_A 0x7
+    /* x 0 0 0  | on  on | Illegal (all 3 connectors are used) */
+
+#define CABLE_ILLEGAL_B 0xB
+    /* 0 x 0 0  | on  on | Illegal (all 3 connectors are used) */
+
+/*
+   The following table details the SCSI_CFG1 Termination Polarity,
+   Termination Control and Cable Detect bits.
+
+   Cable Detect | Termination
+   Bit 3 2 1 0  | 5   4  | Notes
+   _____________|________|____________________
+       1 1 1 0  | on  on | Internal wide only
+       1 1 0 1  | on  on | Internal narrow only
+       1 0 1 1  | on  on | External narrow only
+       0 x 1 1  | on  on | External wide only
+       1 1 0 0  | on  off| Internal wide and internal narrow
+       1 0 1 0  | on  off| Internal wide and external narrow
+       0 x 1 0  | off off| Internal wide and external wide
+       1 0 0 1  | on  off| Internal narrow and external narrow
+       0 x 0 1  | on  off| Internal narrow and external wide
+       1 1 1 1  | on  on | No devices are attached
+       x 0 0 0  | on  on | Illegal (all 3 connectors are used)
+       0 x 0 0  | on  on | Illegal (all 3 connectors are used)
+  
+       x means don't-care (either '0' or '1')
+  
+       If term_pol (bit 13) is '0' (active-low terminator enable), then:
+           'on' is '0' and 'off' is '1'.
+  
+       If term_pol bit is '1' (meaning active-hi terminator enable), then:
+           'on' is '1' and 'off' is '0'.
+ */
+
+/*
+ * MEM_CFG Register bit definitions
+ */
+#define BIOS_EN         0x40    /* BIOS Enable MIO:14,EEP:14 */
+#define FAST_EE_CLK     0x20    /* Diagnostic Bit */
+#define RAM_SZ          0x1C    /* Specify size of RAM to RISC */
+#define  RAM_SZ_2KB      0x00    /* 2 KB */
+#define  RAM_SZ_4KB      0x04    /* 4 KB */
+#define  RAM_SZ_8KB      0x08    /* 8 KB */
+#define  RAM_SZ_16KB     0x0C    /* 16 KB */
+#define  RAM_SZ_32KB     0x10    /* 32 KB */
+#define  RAM_SZ_64KB     0x14    /* 64 KB */
+
+/*
+ * DMA_CFG0 Register bit definitions
+ *
+ * This register is only accessible to the host.
+ */
+#define BC_THRESH_ENB   0x80    /* PCI DMA Start Conditions */
+#define FIFO_THRESH     0x70    /* PCI DMA FIFO Threshold */
+#define  FIFO_THRESH_16B  0x00   /* 16 bytes */
+#define  FIFO_THRESH_32B  0x20   /* 32 bytes */
+#define  FIFO_THRESH_48B  0x30   /* 48 bytes */
+#define  FIFO_THRESH_64B  0x40   /* 64 bytes */
+#define  FIFO_THRESH_80B  0x50   /* 80 bytes (default) */
+#define  FIFO_THRESH_96B  0x60   /* 96 bytes */
+#define  FIFO_THRESH_112B 0x70   /* 112 bytes */
+#define START_CTL       0x0C    /* DMA start conditions */
+#define  START_CTL_TH    0x00    /* Wait threshold level (default) */
+#define  START_CTL_ID    0x04    /* Wait SDMA/SBUS idle */
+#define  START_CTL_THID  0x08    /* Wait threshold and SDMA/SBUS idle */
+#define  START_CTL_EMFU  0x0C    /* Wait SDMA FIFO empty/full */
+#define READ_CMD        0x03    /* Memory Read Method */
+#define  READ_CMD_MR     0x00    /* Memory Read */
+#define  READ_CMD_MRL    0x02    /* Memory Read Long */
+#define  READ_CMD_MRM    0x03    /* Memory Read Multiple (default) */
+
+/* a_advlib.h */
+
+/*
+ * Adv Library Status Definitions
+ */
+#define ADV_TRUE        1
+#define ADV_FALSE       0
+#define ADV_NOERROR     1
+#define ADV_SUCCESS     1
+#define ADV_BUSY        0
+#define ADV_ERROR       (-1)
+
+
+/*
+ * ASC_DVC_VAR 'warn_code' values
+ */
+#define ASC_WARN_EEPROM_CHKSUM          0x0002 /* EEP check sum error */
+#define ASC_WARN_EEPROM_TERMINATION     0x0004 /* EEP termination bad field */
+#define ASC_WARN_SET_PCI_CONFIG_SPACE   0x0080 /* PCI config space set error */
+#define ASC_WARN_ERROR                  0xFFFF /* ADV_ERROR return */
+
+#define ADV_MAX_TID                     15 /* max. target identifier */
+#define ADV_MAX_LUN                     7  /* max. logical unit number */
+
+
+/*
+ * AscInitGetConfig() and AscInitAsc1000Driver() Definitions
+ *
+ * Error code values are set in ASC_DVC_VAR 'err_code'.
+ */
+#define ASC_IERR_WRITE_EEPROM       0x0001 /* write EEPROM error */
+#define ASC_IERR_MCODE_CHKSUM       0x0002 /* micro code check sum error */
+#define ASC_IERR_START_STOP_CHIP    0x0008 /* start/stop chip failed */
+#define ASC_IERR_CHIP_VERSION       0x0040 /* wrong chip version */
+#define ASC_IERR_SET_SCSI_ID        0x0080 /* set SCSI ID failed */
+#define ASC_IERR_BAD_SIGNATURE      0x0200 /* signature not found */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE  0x0800 /* Single-end used w/differential */
+#define ASC_IERR_REVERSED_CABLE     0x1000 /* Narrow flat cable reversed */
+#define ASC_IERR_RW_LRAM            0x8000 /* read/write local RAM error */
+
+/*
+ * Fixed locations of microcode operating variables.
+ */
+#define ASC_MC_CODE_BEGIN_ADDR          0x0028 /* microcode start address */
+#define ASC_MC_CODE_END_ADDR            0x002A /* microcode end address */
+#define ASC_MC_CODE_CHK_SUM             0x002C /* microcode code checksum */
+#define ASC_MC_STACK_BEGIN              0x002E /* microcode stack begin */
+#define ASC_MC_STACK_END                0x0030 /* microcode stack end */
+#define ASC_MC_VERSION_DATE             0x0038 /* microcode version */
+#define ASC_MC_VERSION_NUM              0x003A /* microcode number */
+#define ASCV_VER_SERIAL_W               0x003C /* used in dos_init */
+#define ASC_MC_BIOSMEM                  0x0040 /* BIOS RISC Memory Start */
+#define ASC_MC_BIOSLEN                  0x0050 /* BIOS RISC Memory Length */
+#define ASC_MC_HALTCODE                 0x0094 /* microcode halt code */
+#define ASC_MC_CALLERPC                 0x0096 /* microcode halt caller PC */
+#define ASC_MC_ADAPTER_SCSI_ID          0x0098 /* one ID byte + reserved */
+#define ASC_MC_ULTRA_ABLE               0x009C
+#define ASC_MC_SDTR_ABLE                0x009E
+#define ASC_MC_TAGQNG_ABLE              0x00A0
+#define ASC_MC_DISC_ENABLE              0x00A2
+#define ASC_MC_IDLE_CMD                 0x00A6
+#define ASC_MC_IDLE_PARA_STAT           0x00A8
+#define ASC_MC_DEFAULT_SCSI_CFG0        0x00AC
+#define ASC_MC_DEFAULT_SCSI_CFG1        0x00AE
+#define ASC_MC_DEFAULT_MEM_CFG          0x00B0
+#define ASC_MC_DEFAULT_SEL_MASK         0x00B2
+#define ASC_MC_RISC_NEXT_READY          0x00B4
+#define ASC_MC_RISC_NEXT_DONE           0x00B5
+#define ASC_MC_SDTR_DONE                0x00B6
+#define ASC_MC_NUMBER_OF_QUEUED_CMD     0x00C0
+#define ASC_MC_NUMBER_OF_MAX_CMD        0x00D0
+#define ASC_MC_DEVICE_HSHK_CFG_TABLE    0x0100
+#define ASC_MC_WDTR_ABLE                0x0120 /* Wide Transfer TID bitmask. */
+#define ASC_MC_CONTROL_FLAG             0x0122 /* Microcode control flag. */
+#define ASC_MC_WDTR_DONE                0x0124
+#define ASC_MC_HOST_NEXT_READY          0x0128 /* Host Next Ready RQL Entry. */
+#define ASC_MC_HOST_NEXT_DONE           0x0129 /* Host Next Done RQL Entry. */
+
+/*
+ * BIOS LRAM variable absolute offsets.
+ */
+#define BIOS_CODESEG    0x54
+#define BIOS_CODELEN    0x56
+#define BIOS_SIGNATURE  0x58
+#define BIOS_VERSION    0x5A
+#define BIOS_SIGNATURE  0x58
+
+/*
+ * Microcode Control Flags
+ *
+ * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
+ * and handled by the microcode.
+ */
+#define CONTROL_FLAG_IGNORE_PERR        0x0001 /* Ignore DMA Parity Errors */
+
+/*
+ * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
+ */
+#define HSHK_CFG_WIDE_XFR       0x8000
+#define HSHK_CFG_RATE           0x0F00
+#define HSHK_CFG_OFFSET         0x001F
+
+/*
+ * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF)
+ *
+ * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes 
+ * starting at LRAM address 0x1200 is 8 bytes and has the following
+ * structure. Only 253 of these are actually used for command queues.
+ */
+
+#define ASC_MC_RISC_Q_LIST_BASE         0x1200
+#define ASC_MC_RISC_Q_LIST_SIZE         0x0008
+#define ASC_MC_RISC_Q_TOTAL_CNT         0x00FF /* Num. queue slots in LRAM. */
+#define ASC_MC_RISC_Q_FIRST             0x0001
+#define ASC_MC_RISC_Q_LAST              0x00FF
+
+#define ASC_DEF_MAX_HOST_QNG    0xFD /* Max. number of host commands (253) */
+#define ASC_DEF_MIN_HOST_QNG    0x10 /* Min. number of host commands (16) */
+#define ASC_DEF_MAX_DVC_QNG     0x3F /* Max. number commands per device (63) */
+#define ASC_DEF_MIN_DVC_QNG     0x04 /* Min. number commands per device (4) */
+
+/* RISC Queue List structure - 8 bytes */
+#define RQL_FWD     0     /* forward pointer (1 byte) */
+#define RQL_BWD     1     /* backward pointer (1 byte) */
+#define RQL_STATE   2     /* state byte - free, ready, done, aborted (1 byte) */
+#define RQL_TID     3     /* request target id (1 byte) */
+#define RQL_PHYADDR 4     /* request physical pointer (4 bytes) */
+     
+/* RISC Queue List state values */
+#define ASC_MC_QS_FREE                  0x00
+#define ASC_MC_QS_READY                 0x01
+#define ASC_MC_QS_DONE                  0x40
+#define ASC_MC_QS_ABORTED               0x80
+
+/* RISC Queue List pointer values */
+#define ASC_MC_NULL_Q                   0x00            /* NULL_Q == 0   */
+#define ASC_MC_BIOS_Q                   0xFF            /* BIOS_Q = 255  */
+
+/* ASC_SCSI_REQ_Q 'cntl' field values */
+#define ASC_MC_QC_START_MOTOR           0x02     /* Issue start motor. */
+#define ASC_MC_QC_NO_OVERRUN            0x04     /* Don't report overrun. */
+#define ASC_MC_QC_FIRST_DMA             0x08     /* Internal microcode flag. */
+#define ASC_MC_QC_ABORTED               0x10     /* Request aborted by host. */
+#define ASC_MC_QC_REQ_SENSE             0x20     /* Auto-Request Sense. */
+#define ASC_MC_QC_DOS_REQ               0x80     /* Request issued by DOS. */
+
+
+/*
+ * ASC_SCSI_REQ_Q 'a_flag' definitions
+ *
+ * The Adv Library should limit use to the lower nibble (4 bits) of
+ * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
+ */
+#define ADV_POLL_REQUEST                0x01   /* poll for request completion */
+#define ADV_SCSIQ_DONE                  0x02   /* request done */
+
+/*
+ * Adapter temporary configuration structure
+ *
+ * This structure can be discarded after initialization. Don't add
+ * fields here needed after initialization.
+ *
+ * Field naming convention: 
+ *
+ *  *_enable indicates the field enables or disables a feature. The
+ *  value of the field is never reset.
+ */
+typedef struct adv_dvc_cfg {
+  ushort disc_enable;       /* enable disconnection */
+  uchar  chip_version;      /* chip version */
+  uchar  termination;       /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
+  ushort pci_device_id;     /* PCI device code number */
+  ushort lib_version;       /* Adv Library version number */
+  ushort control_flag;      /* Microcode Control Flag */
+  ushort mcode_date;        /* Microcode date */
+  ushort mcode_version;     /* Microcode version */
+  ushort pci_slot_info;     /* high byte device/function number */
+                            /* bits 7-3 device num., bits 2-0 function num. */
+                            /* low byte bus num. */
+  ushort bios_boot_wait;    /* BIOS boot time delay */
+  ushort serial1;           /* EEPROM serial number word 1 */
+  ushort serial2;           /* EEPROM serial number word 2 */
+  ushort serial3;           /* EEPROM serial number word 3 */
+} ADV_DVC_CFG; 
+
+/*
+ * Adapter operation variable structure.
+ *
+ * One structure is required per host adapter.
+ *
+ * Field naming convention: 
+ *
+ *  *_able indicates both whether a feature should be enabled or disabled
+ *  and whether a device isi capable of the feature. At initialization
+ *  this field may be set, but later if a device is found to be incapable
+ *  of the feature, the field is cleared.
+ */
+typedef struct adv_dvc_var {
+  AdvPortAddr iop_base;   /* I/O port address */
+  ushort err_code;        /* fatal error code */
+  ushort bios_ctrl;       /* BIOS control word, EEPROM word 12 */
+  Ptr2Func isr_callback;  /* pointer to function, called in AdvISR() */
+  Ptr2Func sbreset_callback;  /* pointer to function, called in AdvISR() */
+  ushort wdtr_able;       /* try WDTR for a device */
+  ushort sdtr_able;       /* try SDTR for a device */
+  ushort ultra_able;      /* try SDTR Ultra speed for a device */
+  ushort tagqng_able;     /* try tagged queuing with a device */
+  uchar  max_dvc_qng;     /* maximum number of tagged commands per device */
+  ushort start_motor;     /* start motor command allowed */
+  uchar  scsi_reset_wait; /* delay in seconds after scsi bus reset */
+  uchar  chip_no;         /* should be assigned by caller */
+  uchar  max_host_qng;    /* maximum number of Q'ed command allowed */
+  uchar  cur_host_qng;    /* total number of queue command */
+  uchar  irq_no;          /* IRQ number */
+  ushort no_scam;         /* scam_tolerant of EEPROM */
+  ushort idle_cmd_done;   /* microcode idle command done set by AdvISR() */
+  ulong  drv_ptr;         /* driver pointer to private structure */
+  uchar  chip_scsi_id;    /* chip SCSI target ID */
+ /*
+  * Note: The following fields will not be used after initialization. The
+  * driver may discard the buffer after initialization is done.
+  */
+  ADV_DVC_CFG *cfg; /* temporary configuration structure  */
+} ADV_DVC_VAR; 
+
+#define NO_OF_SG_PER_BLOCK              15
+
+typedef struct asc_sg_block {
+    uchar reserved1; 
+    uchar reserved2; 
+    uchar first_entry_no;             /* starting entry number */
+    uchar last_entry_no;              /* last entry number */
+    struct asc_sg_block *sg_ptr; /* links to the next sg block */
+    struct  {
+        ulong sg_addr;                /* SG element address */
+        ulong sg_count;               /* SG element count */
+    } sg_list[NO_OF_SG_PER_BLOCK];
+} ADV_SG_BLOCK;
+
+/*
+ * ASC_SCSI_REQ_Q - microcode request structure
+ *
+ * All fields in this structure up to byte 60 are used by the microcode.
+ * The microcode makes assumptions about the size and ordering of fields
+ * in this structure. Do not change the structure definition here without
+ * coordinating the change with the microcode.
+ */
+typedef struct adv_scsi_req_q {
+    uchar       cntl;           /* Ucode flags and state (ASC_MC_QC_*). */
+    uchar       sg_entry_cnt;   /* SG element count. Zero for no SG. */
+    uchar       target_id;      /* Device target identifier. */
+    uchar       target_lun;     /* Device target logical unit number. */
+    ulong       data_addr;      /* Data buffer physical address. */
+    ulong       data_cnt;       /* Data count. Ucode sets to residual. */
+    ulong       sense_addr;     /* Sense buffer physical address. */
+    ulong       srb_ptr;        /* Driver request pointer. */
+    uchar       a_flag;         /* Adv Library flag field. */
+    uchar       sense_len;      /* Auto-sense length. Ucode sets to residual. */
+    uchar       cdb_len;        /* SCSI CDB length. */
+    uchar       tag_code;       /* SCSI-2 Tag Queue Code: 00, 20-22. */
+    uchar       done_status;    /* Completion status. */
+    uchar       scsi_status;    /* SCSI status byte. */
+    uchar       host_status;    /* Ucode host status. */
+    uchar       ux_sg_ix;       /* Ucode working SG variable. */
+    uchar       cdb[12];        /* SCSI command block. */
+    ulong       sg_real_addr;   /* SG list physical address. */
+    struct adv_scsi_req_q *free_scsiq_link;
+    ulong       ux_wk_data_cnt; /* Saved data count at disconnection. */
+    struct adv_scsi_req_q *scsiq_ptr;
+    ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+    /*
+     * End of microcode structure - 60 bytes. The rest of the structure
+     * is used by the Adv Library and ignored by the microcode.
+     */
+    ulong       vsense_addr;    /* Sense buffer virtual address. */
+    ulong       vdata_addr;     /* Data buffer virtual address. */
+    uchar       orig_sense_len; /* Original length of sense buffer. */
+} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */
+
+/*
+ * Microcode idle loop commands
+ */
+#define IDLE_CMD_COMPLETED           0
+#define IDLE_CMD_STOP_CHIP           0x0001
+#define IDLE_CMD_STOP_CHIP_SEND_INT  0x0002
+#define IDLE_CMD_SEND_INT            0x0004
+#define IDLE_CMD_ABORT               0x0008
+#define IDLE_CMD_DEVICE_RESET        0x0010
+#define IDLE_CMD_SCSI_RESET          0x0020
+
+/*
+ * AdvSendIdleCmd() flag definitions.
+ */
+#define ADV_NOWAIT     0x01
+
+/*
+ * Wait loop time out values.
+ */
+#define SCSI_WAIT_10_SEC             10         /* 10 seconds */
+#define SCSI_MS_PER_SEC              1000       /* milliseconds per second */
+
+/*
+ * Device drivers must define the following functions.
+ */
+STATIC int   DvcEnterCritical(void);
+STATIC void  DvcLeaveCritical(int);
+STATIC void  DvcSleepMilliSecond(ulong);
+STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
+STATIC void  DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
+STATIC ulong DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
+                uchar *, long *, int);
+STATIC void  DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
+
+/*
+ * Adv Library functions available to drivers.
+ */
+STATIC int     AdvExeScsiQueue(ADV_DVC_VAR *,
+                         ADV_SCSI_REQ_Q *);
+STATIC int     AdvISR(ADV_DVC_VAR *);
+STATIC int     AdvInitGetConfig(ADV_DVC_VAR *);
+STATIC int     AdvInitAsc3550Driver(ADV_DVC_VAR *);
+STATIC int     AdvResetSB(ADV_DVC_VAR *);
+
+/*
+ * Internal Adv Library functions.
+ */
+STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int);
+STATIC void   AdvResetChip(ADV_DVC_VAR *);
+STATIC int    AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC void   AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int    AdvInitFromEEP(ADV_DVC_VAR *);
+STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
+STATIC void   AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
+STATIC void   AdvWaitEEPCmd(AdvPortAddr);
+STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
+STATIC void   AdvResetSCSIBus(ADV_DVC_VAR *);
+
+/*
+ * PCI Bus Definitions
+ */
+#define AscPCICmdRegBits_BusMastering     0x0007
+#define AscPCICmdRegBits_ParErrRespCtrl   0x0040
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+
+/* Read byte from a register. */
+#define AdvReadByteRegister(iop_base, reg_off) \
+     (inp((iop_base) + (reg_off)))
+
+/* Write byte to a register. */
+#define AdvWriteByteRegister(iop_base, reg_off, byte) \
+     (outp((iop_base) + (reg_off), (byte)))
+
+/* Read word (2 bytes) from a register. */
+#define AdvReadWordRegister(iop_base, reg_off) \
+     (inpw((iop_base) + (reg_off)))
+
+/* Write word (2 bytes) to a register. */
+#define AdvWriteWordRegister(iop_base, reg_off, word) \
+     (outpw((iop_base) + (reg_off), (word)))
+
+/* Read byte from LRAM. */
+#define AdvReadByteLram(iop_base, addr, byte) \
+do { \
+    outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \
+    (byte) = inp((iop_base) + IOPB_RAM_DATA); \
+} while (0)
+
+/* Write byte to LRAM. */
+#define AdvWriteByteLram(iop_base, addr, byte) \
+    (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
+     outp((iop_base) + IOPB_RAM_DATA, (byte)))
+
+/* Read word (2 bytes) from LRAM. */
+#define AdvReadWordLram(iop_base, addr, word) \
+do { \
+    outpw((iop_base) + IOPW_RAM_ADDR, (addr));  \
+    (word) = inpw((iop_base) + IOPW_RAM_DATA); \
+} while (0)
+
+/* Write word (2 bytes) to LRAM. */
+#define AdvWriteWordLram(iop_base, addr, word) \
+    (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
+     outpw((iop_base) + IOPW_RAM_DATA, (word)))
+
+/* Write double word (4 bytes) to LRAM */
+/* Because of unspecified C language ordering don't use auto-increment. */
+#define AdvWriteDWordLram(iop_base, addr, dword) \
+    ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
+      outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword) & 0xFFFF))), \
+     (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
+      outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword >> 16) & 0xFFFF))))
+
+/* Read word (2 bytes) from LRAM assuming that the address is already set. */
+#define AdvReadWordAutoIncLram(iop_base) \
+     (inpw((iop_base) + IOPW_RAM_DATA))
+
+/* Write word (2 bytes) to LRAM assuming that the address is already set. */
+#define AdvWriteWordAutoIncLram(iop_base, word) \
+     (outpw((iop_base) + IOPW_RAM_DATA, (word)))
+
+#else /* version >= v1,3,0 */
+
+/* Read byte from a register. */
+#define AdvReadByteRegister(iop_base, reg_off) \
+     (ADV_MEM_READB((iop_base) + (reg_off)))
+
+/* Write byte to a register. */
+#define AdvWriteByteRegister(iop_base, reg_off, byte) \
+     (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
+
+/* Read word (2 bytes) from a register. */
+#define AdvReadWordRegister(iop_base, reg_off) \
+     (ADV_MEM_READW((iop_base) + (reg_off)))
+
+/* Write word (2 bytes) to a register. */
+#define AdvWriteWordRegister(iop_base, reg_off, word) \
+     (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
+
+/* Read byte from LRAM. */
+#define AdvReadByteLram(iop_base, addr, byte) \
+do { \
+    ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
+    (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
+} while (0)
+
+/* Write byte to LRAM. */
+#define AdvWriteByteLram(iop_base, addr, byte) \
+    (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+     ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
+
+/* Read word (2 bytes) from LRAM. */
+#define AdvReadWordLram(iop_base, addr, word) \
+do { \
+    ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
+    (word) = ADV_MEM_READW((iop_base) + IOPW_RAM_DATA); \
+} while (0)
+
+/* Write word (2 bytes) to LRAM. */
+#define AdvWriteWordLram(iop_base, addr, word) \
+    (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+
+/* Write double word (4 bytes) to LRAM */
+/* Because of unspecified C language ordering don't use auto-increment. */
+#define AdvWriteDWordLram(iop_base, addr, dword) \
+    ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+      ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
+                     (ushort) ((dword) & 0xFFFF))), \
+     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
+      ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
+                     (ushort) ((dword >> 16) & 0xFFFF))))
+
+/* Read word (2 bytes) from LRAM assuming that the address is already set. */
+#define AdvReadWordAutoIncLram(iop_base) \
+     (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
+
+/* Write word (2 bytes) to LRAM assuming that the address is already set. */
+#define AdvWriteWordAutoIncLram(iop_base, word) \
+     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+
+#endif /* version >= v1,3,0 */
+
+/*
+ * Define macro to check for Condor signature.
+ *
+ * Evaluate to ADV_TRUE if a Condor chip is found the specified port
+ * address 'iop_base'. Otherwise evalue to ADV_FALSE.
+ */
+#define AdvFindSignature(iop_base) \
+    (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
+    ADV_CHIP_ID_BYTE) && \
+     (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
+    ADV_CHIP_ID_WORD)) ?  ADV_TRUE : ADV_FALSE)
+
+/*
+ * Define macro to Return the version number of the chip at 'iop_base'.
+ *
+ * The second parameter 'bus_type' is currently unused.
+ */
+#define AdvGetChipVersion(iop_base, bus_type) \
+    AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
+
+/*
+ * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
+ * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
+ * 
+ * If the request has not yet been sent to the device it will simply be
+ * aborted from RISC memory. If the request is disconnected it will be
+ * aborted on reselection by sending an Abort Message to the target ID.
+ *
+ * Return value:
+ *      ADV_TRUE(1) - Queue was successfully aborted.
+ *      ADV_FALSE(0) - Queue was not found on the active queue list.
+ */
+#define AdvAbortSRB(asc_dvc, srb_ptr) \
+    AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
+                (ulong) (srb_ptr), 0)
+
+/*
+ * Send a Bus Device Reset Message to the specified target ID.
+ *
+ * All outstanding commands will be purged if sending the
+ * Bus Device Reset Message is successful.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) - All requests on the target are purged.
+ *      ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
+ *                     are not purged.
+ */
+#define AdvResetDevice(asc_dvc, target_id) \
+        AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
+                    (ulong) (target_id), 0)
+
+/*
+ * SCSI Wide Type definition.
+ */
+#define ADV_SCSI_BIT_ID_TYPE   ushort
+
+/*
+ * AdvInitScsiTarget() 'cntl_flag' options.
+ */
+#define ADV_SCAN_LUN           0x01
+#define ADV_CAPINFO_NOLUN      0x02
+
+/*
+ * Convert target id to target id bit mask.
+ */
+#define ADV_TID_TO_TIDMASK(tid)   (0x01 << ((tid) & ADV_MAX_TID))
+
+/*
+ * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
+ */
+
+#define QD_NO_STATUS         0x00       /* Request not completed yet. */
+#define QD_NO_ERROR          0x01
+#define QD_ABORTED_BY_HOST   0x02
+#define QD_WITH_ERROR        0x04
+
+#define QHSTA_NO_ERROR              0x00
+#define QHSTA_M_SEL_TIMEOUT         0x11
+#define QHSTA_M_DATA_OVER_RUN       0x12
+#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
+#define QHSTA_M_QUEUE_ABORTED       0x15
+#define QHSTA_M_SXFR_SDMA_ERR       0x16 /* SXFR_STATUS SCSI DMA Error */
+#define QHSTA_M_SXFR_SXFR_PERR      0x17 /* SXFR_STATUS SCSI Bus Parity Error */
+#define QHSTA_M_RDMA_PERR           0x18 /* RISC PCI DMA parity error */
+#define QHSTA_M_SXFR_OFF_UFLW       0x19 /* SXFR_STATUS Offset Underflow */
+#define QHSTA_M_SXFR_OFF_OFLW       0x20 /* SXFR_STATUS Offset Overflow */
+#define QHSTA_M_SXFR_WD_TMO         0x21 /* SXFR_STATUS Watchdog Timeout */
+#define QHSTA_M_SXFR_DESELECTED     0x22 /* SXFR_STATUS Deselected */
+/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
+#define QHSTA_M_SXFR_XFR_OFLW       0x12 /* SXFR_STATUS Transfer Overflow */
+#define QHSTA_M_SXFR_XFR_PH_ERR     0x24 /* SXFR_STATUS Transfer Phase Error */
+#define QHSTA_M_SXFR_UNKNOWN_ERROR  0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_WTM_TIMEOUT         0x41
+#define QHSTA_M_BAD_CMPL_STATUS_IN  0x42
+#define QHSTA_M_NO_AUTO_REQ_SENSE   0x43
+#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
+#define QHSTA_M_INVALID_DEVICE      0x45 /* Bad target ID */
+
+typedef int (* ADV_ISR_CALLBACK)
+    (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+
+typedef int (* ADV_SBRESET_CALLBACK)
+    (ADV_DVC_VAR *);
+
+/*
+ * Default EEPROM Configuration structure defined in a_init.c.
+ */
+extern ADVEEP_CONFIG Default_EEPROM_Config;
+
+/*
+ * DvcGetPhyAddr() flag arguments
+ */
+#define ADV_IS_SCSIQ_FLAG       0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
+#define ADV_ASCGETSGLIST_VADDR  0x02 /* 'addr' is AscGetSGList() virtual addr */
+#define ADV_IS_SENSE_FLAG       0x04 /* 'addr' is sense virtual pointer */
+#define ADV_IS_DATA_FLAG        0x08 /* 'addr' is data virtual pointer */
+#define ADV_IS_SGLIST_FLAG      0x10 /* 'addr' is sglist virtual pointer */
+
+/* 'IS_SCSIQ_FLAG is now obsolete; Instead use ADV_IS_SCSIQ_FLAG. */
+#define IS_SCSIQ_FLAG           ADV_IS_SCSIQ_FLAQ
+
+
+/* Return the address that is aligned at the next doubleword >= to 'addr'. */
+#define ADV_DWALIGN(addr)       (((ulong) (addr) + 0x3) & ~0x3)
+
+/*
+ * Total contiguous memory needed for driver SG blocks.
+ *
+ * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
+ * number of scatter-gather elements the driver supports in a
+ * single request.
+ */
+
+#ifndef ADV_MAX_SG_LIST
+Forced Error: Driver must define ADV_MAX_SG_LIST.
+#endif /* ADV_MAX_SG_LIST */
+
+#define ADV_SG_LIST_MAX_BYTE_SIZE \
+         (sizeof(ADV_SG_BLOCK) * \
+          ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
+
+/*
+ * A driver may optionally define the assertion macro ADV_ASSERT() in
+ * its d_os_dep.h file. If the macro has not already been defined,
+ * then define the macro to a no-op.
+ */
+#ifndef ADV_ASSERT
+#define ADV_ASSERT(a)
+#endif /* ADV_ASSERT */
 
 
 /*
  * --- Driver Constants and Macros
  */
 
-#define ASC_NUM_BOARD_SUPPORTED 4
-#define ASC_NUM_BUS				4
+#define ASC_NUM_BOARD_SUPPORTED 16
+#define ASC_NUM_IOPORT_PROBE    4
+#define ASC_NUM_BUS             4
 
 /* Reference Scsi_Host hostdata */
 #define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
 
 /* asc_board_t flags */
-#define ASC_HOST_IN_RESET		0x01
-#define ASC_HOST_IN_ABORT		0x02
-
-#define NO_ISA_DMA				0xff		/* No ISA DMA Channel Used */
+#define ASC_HOST_IN_RESET       0x01
+#define ASC_HOST_IN_ABORT       0x02
+#define ASC_IS_WIDE_BOARD       0x04    /* AdvanSys Wide Board */
+#define ASC_SELECT_QUEUE_DEPTHS 0x08
+
+#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
+#define ASC_WIDE_BOARD(boardp)   ((boardp)->flags & ASC_IS_WIDE_BOARD)
+
+#define NO_ISA_DMA              0xff        /* No ISA DMA Channel Used */
+
+/*
+ * If the Linux kernel version supports freeing initialization code
+ * and data after loading, define macros for this purpose. These macros
+ * are not used when the driver is built as a module, cf. linux/init.h.
+ */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23)
+#define ASC_INITFUNC(func)      func
+#define ASC_INITDATA
+#define ASC_INIT
+#else /* version >= v2.1.23 */
+#define ASC_INITFUNC(func)      __initfunc(func)
+#define ASC_INITDATA            __initdata
+#define ASC_INIT                __init
+#endif /* version >= v2.1.23 */
 
-#define ASC_INFO_SIZE			128			/* advansys_info() line size */
+#define ASC_INFO_SIZE           128            /* advansys_info() line size */
 
 /* /proc/scsi/advansys/[0...] related definitions */
-#define ASC_PRTBUF_SIZE			2048
-#define ASC_PRTLINE_SIZE		160
+#define ASC_PRTBUF_SIZE         2048
+#define ASC_PRTLINE_SIZE        160
 
 #define ASC_PRT_NEXT() \
-	if (cp) { \
-		totlen += len; \
-		leftlen -= len; \
-		if (leftlen == 0) { \
-			return totlen; \
-		} \
-		cp += len; \
-	}
+    if (cp) { \
+        totlen += len; \
+        leftlen -= len; \
+        if (leftlen == 0) { \
+            return totlen; \
+        } \
+        cp += len; \
+    }
 
 #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 
 /* Asc Library return codes */
-#define ASC_TRUE		1
-#define ASC_FALSE		0
-#define ASC_NOERROR		1
-#define ASC_BUSY		0
-#define ASC_ERROR		(-1)
+#define ASC_TRUE        1
+#define ASC_FALSE       0
+#define ASC_NOERROR     1
+#define ASC_BUSY        0
+#define ASC_ERROR       (-1)
 
 /* Scsi_Cmnd function return codes */
-#define STATUS_BYTE(byte)	(byte)
-#define MSG_BYTE(byte)		((byte) << 8)
-#define HOST_BYTE(byte)		((byte) << 16)
-#define DRIVER_BYTE(byte)	((byte) << 24)
+#define STATUS_BYTE(byte)   (byte)
+#define MSG_BYTE(byte)      ((byte) << 8)
+#define HOST_BYTE(byte)     ((byte) << 16)
+#define DRIVER_BYTE(byte)   ((byte) << 24)
 
 /*
  * The following definitions and macros are OS independent interfaces to
@@ -2185,195 +3257,197 @@
  *  REQPTIME(reqp) - reqp's time stamp value
  *  REQTIMESTAMP() - system time stamp value
  */
-typedef Scsi_Cmnd			REQ, *REQP;
-#define REQPNEXT(reqp)		((REQP) ((reqp)->host_scribble))
-#define REQPNEXTP(reqp)		((REQP *) &((reqp)->host_scribble))
-#define REQPTID(reqp)		((reqp)->target)
-#define REQPTIME(reqp)		((reqp)->SCp.this_residual)
-#define REQTIMESTAMP()		(jiffies)
+typedef Scsi_Cmnd            REQ, *REQP;
+#define REQPNEXT(reqp)       ((REQP) ((reqp)->host_scribble))
+#define REQPNEXTP(reqp)      ((REQP *) &((reqp)->host_scribble))
+#define REQPTID(reqp)        ((reqp)->target)
+#define REQPTIME(reqp)       ((reqp)->SCp.this_residual)
+#define REQTIMESTAMP()       (jiffies)
 
 #define REQTIMESTAT(function, ascq, reqp, tid) \
 { \
-	/*
-	 * If the request time stamp is less than the system time stamp, then \
-	 * maybe the system time stamp wrapped. Set the request time to zero.\
-	 */ \
-	if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
-		REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
-	} else { \
-		/* Indicate an error occurred with the assertion. */ \
-		ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
-		REQPTIME(reqp) = 0; \
-	} \
-	/* Handle first minimum time case without external initialization. */ \
-	if (((ascq)->q_tot_cnt[tid] == 1) ||  \
-		(REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
-			(ascq)->q_min_tim[tid] = REQPTIME(reqp); \
-			ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
-				(function), (tid), (ascq)->q_min_tim[tid]); \
-		} \
-	if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
-		(ascq)->q_max_tim[tid] = REQPTIME(reqp); \
-		ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
-			(function), tid, (ascq)->q_max_tim[tid]); \
-	} \
-	(ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
-	/* Reset the time stamp field. */ \
-	REQPTIME(reqp) = 0; \
+    /*
+     * If the request time stamp is less than the system time stamp, then \
+     * maybe the system time stamp wrapped. Set the request time to zero.\
+     */ \
+    if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
+        REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
+    } else { \
+        /* Indicate an error occurred with the assertion. */ \
+        ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
+        REQPTIME(reqp) = 0; \
+    } \
+    /* Handle first minimum time case without external initialization. */ \
+    if (((ascq)->q_tot_cnt[tid] == 1) ||  \
+        (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
+            (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
+            ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
+                (function), (tid), (ascq)->q_min_tim[tid]); \
+        } \
+    if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
+        (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
+        ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
+            (function), tid, (ascq)->q_max_tim[tid]); \
+    } \
+    (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
+    /* Reset the time stamp field. */ \
+    REQPTIME(reqp) = 0; \
 }
 
 /* asc_enqueue() flags */
-#define ASC_FRONT		1
-#define ASC_BACK		2
+#define ASC_FRONT       1
+#define ASC_BACK        2
 
 /* asc_dequeue_list() argument */
-#define ASC_TID_ALL		(-1)
+#define ASC_TID_ALL        (-1)
 
 /* Return non-zero, if the queue is empty. */
-#define ASC_QUEUE_EMPTY(ascq)	((ascq)->q_tidmask == 0)
+#define ASC_QUEUE_EMPTY(ascq)    ((ascq)->q_tidmask == 0)
 
 /* PCI configuration declarations */
 
-#define PCI_BASE_CLASS_PREDEFINED			0x00
-#define PCI_BASE_CLASS_MASS_STORAGE			0x01
-#define PCI_BASE_CLASS_NETWORK				0x02
-#define PCI_BASE_CLASS_DISPLAY				0x03
-#define PCI_BASE_CLASS_MULTIMEDIA			0x04
-#define PCI_BASE_CLASS_MEMORY_CONTROLLER	0x05
-#define PCI_BASE_CLASS_BRIDGE_DEVICE		0x06
+#define PCI_BASE_CLASS_PREDEFINED               0x00
+#define PCI_BASE_CLASS_MASS_STORAGE             0x01
+#define PCI_BASE_CLASS_NETWORK                  0x02
+#define PCI_BASE_CLASS_DISPLAY                  0x03
+#define PCI_BASE_CLASS_MULTIMEDIA               0x04
+#define PCI_BASE_CLASS_MEMORY_CONTROLLER        0x05
+#define PCI_BASE_CLASS_BRIDGE_DEVICE            0x06
 
 /* MASS STORAGE */
-#define PCI_SUB_CLASS_SCSI_CONTROLLER			0x00
-#define PCI_SUB_CLASS_IDE_CONTROLLER			0x01
-#define PCI_SUB_CLASS_FLOPPY_DISK_CONTROLLER	0x02
-#define PCI_SUB_CLASS_IPI_BUS_CONTROLLER		0x03
-#define PCI_SUB_CLASS_OTHER_MASS_CONTROLLER		0x80
+#define PCI_SUB_CLASS_SCSI_CONTROLLER           0x00
+#define PCI_SUB_CLASS_IDE_CONTROLLER            0x01
+#define PCI_SUB_CLASS_FLOPPY_DISK_CONTROLLER    0x02
+#define PCI_SUB_CLASS_IPI_BUS_CONTROLLER        0x03
+#define PCI_SUB_CLASS_OTHER_MASS_CONTROLLER     0x80
 
 /* NETWORK CONTROLLER */
-#define PCI_SUB_CLASS_ETHERNET_CONTROLLER		0x00
-#define PCI_SUB_CLASS_TOKEN_RING_CONTROLLER		0x01
-#define PCI_SUB_CLASS_FDDI_CONTROLLER			0x02
-#define PCI_SUB_CLASS_OTHER_NETWORK_CONTROLLER	0x80
+#define PCI_SUB_CLASS_ETHERNET_CONTROLLER       0x00
+#define PCI_SUB_CLASS_TOKEN_RING_CONTROLLER     0x01
+#define PCI_SUB_CLASS_FDDI_CONTROLLER           0x02
+#define PCI_SUB_CLASS_OTHER_NETWORK_CONTROLLER  0x80
 
 /* DISPLAY CONTROLLER */
-#define PCI_SUB_CLASS_VGA_CONTROLLER			0x00
-#define PCI_SUB_CLASS_XGA_CONTROLLER			0x01
-#define PCI_SUB_CLASS_OTHER_DISPLAY_CONTROLLER	0x80
+#define PCI_SUB_CLASS_VGA_CONTROLLER            0x00
+#define PCI_SUB_CLASS_XGA_CONTROLLER            0x01
+#define PCI_SUB_CLASS_OTHER_DISPLAY_CONTROLLER  0x80
 
 /* MULTIMEDIA CONTROLLER */
-#define PCI_SUB_CLASS_VIDEO_DEVICE				0x00
-#define PCI_SUB_CLASS_AUDIO_DEVICE				0x01
-#define PCI_SUB_CLASS_OTHER_MULTIMEDIA_DEVICE	0x80
+#define PCI_SUB_CLASS_VIDEO_DEVICE              0x00
+#define PCI_SUB_CLASS_AUDIO_DEVICE              0x01
+#define PCI_SUB_CLASS_OTHER_MULTIMEDIA_DEVICE   0x80
 
 /* MEMORY CONTROLLER */
-#define PCI_SUB_CLASS_RAM_CONTROLLER			0x00
-#define PCI_SUB_CLASS_FLASH_CONTROLLER			0x01
-#define PCI_SUB_CLASS_OTHER_MEMORY_CONTROLLER	0x80
+#define PCI_SUB_CLASS_RAM_CONTROLLER            0x00
+#define PCI_SUB_CLASS_FLASH_CONTROLLER          0x01
+#define PCI_SUB_CLASS_OTHER_MEMORY_CONTROLLER   0x80
 
 /* BRIDGE CONTROLLER */
-#define PCI_SUB_CLASS_HOST_BRIDGE_CONTROLLER		0x00
-#define PCI_SUB_CLASS_ISA_BRIDGE_CONTROLLER			0x01
-#define PCI_SUB_CLASS_EISA_BRIDGE_CONTROLLER		0x02
-#define PCI_SUB_CLASS_MC_BRIDGE_CONTROLLER			0x03
-#define PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER	0x04
-#define PCI_SUB_CLASS_PCMCIA_BRIDGE_CONTROLLER		0x05
-#define PCI_SUB_CLASS_OTHER_BRIDGE_CONTROLLER		0x80
-
-#define PCI_MAX_SLOT			0x1F
-#define PCI_MAX_BUS				0xFF
-#define PCI_IOADDRESS_MASK		0xFFFE
-#define ASC_PCI_VENDORID		0x10CD
-#define ASC_PCI_DEVICE_ID_1100	0x1100
-#define ASC_PCI_DEVICE_ID_1200	0x1200
-#define ASC_PCI_DEVICE_ID_1300	0x1300
+#define PCI_SUB_CLASS_HOST_BRIDGE_CONTROLLER    0x00
+#define PCI_SUB_CLASS_ISA_BRIDGE_CONTROLLER     0x01
+#define PCI_SUB_CLASS_EISA_BRIDGE_CONTROLLER    0x02
+#define PCI_SUB_CLASS_MC_BRIDGE_CONTROLLER      0x03
+#define PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER    0x04
+#define PCI_SUB_CLASS_PCMCIA_BRIDGE_CONTROLLER  0x05
+#define PCI_SUB_CLASS_OTHER_BRIDGE_CONTROLLER   0x80
+
+#define PCI_MAX_SLOT            0x1F
+#define PCI_MAX_BUS             0xFF
+#define PCI_IOADDRESS_MASK      0xFFFE
+#define ASC_PCI_VENDORID        0x10CD
+#define ASC_PCI_DEVICE_ID_1100  0x1100
+#define ASC_PCI_DEVICE_ID_1200  0x1200
+#define ASC_PCI_DEVICE_ID_1300  0x1300
+#define ASC_PCI_DEVICE_ID_2300  0x2300
 
 /* PCI IO Port Addresses to generate special cycle */
 
-#define PCI_CONFIG_ADDRESS_MECH1		0x0CF8
-#define PCI_CONFIG_DATA_MECH1			0x0CFC
+#define PCI_CONFIG_ADDRESS_MECH1          0x0CF8
+#define PCI_CONFIG_DATA_MECH1             0x0CFC
 
-#define PCI_CONFIG_FORWARD_REGISTER		0x0CFA	/* 0=type 0; 1=type 1; */
+#define PCI_CONFIG_FORWARD_REGISTER       0x0CFA    /* 0=type 0; 1=type 1; */
 
-#define PCI_CONFIG_BUS_NUMBER_MASK		0x00FF0000
-#define PCI_CONFIG_DEVICE_FUNCTION_MASK	0x0000FF00
-#define PCI_CONFIG_REGISTER_NUMBER_MASK	0x000000F8
-
-#define PCI_DEVICE_FOUND				0x0000
-#define PCI_DEVICE_NOT_FOUND			0xffff
-
-#define SUBCLASS_OFFSET 	0x0A
-#define CLASSCODE_OFFSET	0x0B
-#define VENDORID_OFFSET		0x00
-#define DEVICEID_OFFSET		0x02
+#define PCI_CONFIG_BUS_NUMBER_MASK        0x00FF0000
+#define PCI_CONFIG_DEVICE_FUNCTION_MASK   0x0000FF00
+#define PCI_CONFIG_REGISTER_NUMBER_MASK   0x000000F8
+
+#define PCI_DEVICE_FOUND                0x0000
+#define PCI_DEVICE_NOT_FOUND            0xffff
+
+#define SUBCLASS_OFFSET         0x0A
+#define CLASSCODE_OFFSET        0x0B
+#define VENDORID_OFFSET         0x00
+#define DEVICEID_OFFSET         0x02
 
 #ifndef ADVANSYS_STATS
 #define ASC_STATS(shp, counter)
 #define ASC_STATS_ADD(shp, counter, count)
 #else /* ADVANSYS_STATS */
 #define ASC_STATS(shp, counter) \
-	(ASC_BOARDP(shp)->asc_stats.counter++)
+    (ASC_BOARDP(shp)->asc_stats.counter++)
 
 #define ASC_STATS_ADD(shp, counter, count) \
-	(ASC_BOARDP(shp)->asc_stats.counter += (count))
+    (ASC_BOARDP(shp)->asc_stats.counter += (count))
 #endif /* ADVANSYS_STATS */
 
 #define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
 
 /* If the result wraps when calculating tenths, return 0. */
 #define ASC_TENTHS(num, den) \
-	(((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
-	0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
+    (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
+    0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
 
 /*
  * Display a message to the console.
  */
 #define ASC_PRINT(s) \
-	{ \
-		printk("advansys: "); \
-		printk(s); \
-	}
+    { \
+        printk("advansys: "); \
+        printk(s); \
+    }
 
 #define ASC_PRINT1(s, a1) \
-	{ \
-		printk("advansys: "); \
-		printk((s), (a1)); \
-	}
+    { \
+        printk("advansys: "); \
+        printk((s), (a1)); \
+    }
 
 #define ASC_PRINT2(s, a1, a2) \
-	{ \
-		printk("advansys: "); \
-		printk((s), (a1), (a2)); \
-	}
+    { \
+        printk("advansys: "); \
+        printk((s), (a1), (a2)); \
+    }
 
 #define ASC_PRINT3(s, a1, a2, a3) \
-	{ \
-		printk("advansys: "); \
-		printk((s), (a1), (a2), (a3)); \
-	}
+    { \
+        printk("advansys: "); \
+        printk((s), (a1), (a2), (a3)); \
+    }
 
 #define ASC_PRINT4(s, a1, a2, a3, a4) \
-	{ \
-		printk("advansys: "); \
-		printk((s), (a1), (a2), (a3), (a4)); \
-	}
+    { \
+        printk("advansys: "); \
+        printk((s), (a1), (a2), (a3), (a4)); \
+    }
 
 
 #ifndef ADVANSYS_DEBUG
 
-#define	ASC_DBG(lvl, s)
-#define	ASC_DBG1(lvl, s, a1)
-#define	ASC_DBG2(lvl, s, a1, a2)
-#define	ASC_DBG3(lvl, s, a1, a2, a3)
-#define	ASC_DBG4(lvl, s, a1, a2, a3, a4)
-#define	ASC_DBG_PRT_SCSI_HOST(lvl, s)
-#define	ASC_DBG_PRT_SCSI_CMND(lvl, s)
-#define	ASC_DBG_PRT_SCSI_Q(lvl, scsiqp)
-#define	ASC_DBG_PRT_QDONE_INFO(lvl, qdone)
-#define	ASC_DBG_PRT_HEX(lvl, name, start, length)
-#define	ASC_DBG_PRT_CDB(lvl, cdb, len)
-#define	ASC_DBG_PRT_SENSE(lvl, sense, len)
+#define ASC_DBG(lvl, s)
+#define ASC_DBG1(lvl, s, a1)
+#define ASC_DBG2(lvl, s, a1, a2)
+#define ASC_DBG3(lvl, s, a1, a2, a3)
+#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
+#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
+#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
+#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
+#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_HEX(lvl, name, start, length)
+#define ASC_DBG_PRT_CDB(lvl, cdb, len)
+#define ASC_DBG_PRT_SENSE(lvl, sense, len)
 #define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
-#define ASC_ASSERT(a)
 
 #else /* ADVANSYS_DEBUG */
 
@@ -2384,145 +3458,189 @@
  * 2-N: Verbose Tracing
  */
 
-#define	ASC_DBG(lvl, s) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			printk(s); \
-		} \
-	}
-
-#define	ASC_DBG1(lvl, s, a1) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			printk((s), (a1)); \
-		} \
-	}
-
-#define	ASC_DBG2(lvl, s, a1, a2) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			printk((s), (a1), (a2)); \
-		} \
-	}
-
-#define	ASC_DBG3(lvl, s, a1, a2, a3) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			printk((s), (a1), (a2), (a3)); \
-		} \
-	}
-
-#define	ASC_DBG4(lvl, s, a1, a2, a3, a4) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			printk((s), (a1), (a2), (a3), (a4)); \
-		} \
-	}
-
-#define	ASC_DBG_PRT_SCSI_HOST(lvl, s) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_scsi_host(s); \
-		} \
-	}
-
-#define	ASC_DBG_PRT_SCSI_CMND(lvl, s) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_scsi_cmnd(s); \
-		} \
-	}
-
-#define	ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_scsi_q(scsiqp); \
-		} \
-	}
-
-#define	ASC_DBG_PRT_QDONE_INFO(lvl, qdone) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_qdone_info(qdone); \
-		} \
-	}
-
-#define	ASC_DBG_PRT_HEX(lvl, name, start, length) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_hex((name), (start), (length)); \
-		} \
-	}
+#define ASC_DBG(lvl, s) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk(s); \
+        } \
+    }
 
-#define	ASC_DBG_PRT_CDB(lvl, cdb, len) \
-		ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
+#define ASC_DBG1(lvl, s, a1) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1)); \
+        } \
+    }
 
-#define	ASC_DBG_PRT_SENSE(lvl, sense, len) \
-		ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
+#define ASC_DBG2(lvl, s, a1, a2) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1), (a2)); \
+        } \
+    }
 
-#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
-		ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
+#define ASC_DBG3(lvl, s, a1, a2, a3) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1), (a2), (a3)); \
+        } \
+    }
 
-#define ASC_ASSERT(a) \
-	{ \
-		if (!(a)) { \
-			printk("ASC_ASSERT() Failure: file %s, line %d\n", \
-				__FILE__, __LINE__); \
-		} \
-	}
-#endif /* ADVANSYS_DEBUG */
+#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1), (a2), (a3), (a4)); \
+        } \
+    }
 
+#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_scsi_host(s); \
+        } \
+    }
 
-/*
- * --- Driver Structures
- */
+#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_scsi_cmnd(s); \
+        } \
+    }
 
-#ifdef ADVANSYS_STATS
+#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_asc_scsi_q(scsiqp); \
+        } \
+    }
+
+#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_asc_qdone_info(qdone); \
+        } \
+    }
+
+#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_adv_scsi_req_q(scsiqp); \
+        } \
+    }
+
+#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_hex((name), (start), (length)); \
+        } \
+    }
+
+#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
+        ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
+
+#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
+        ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
+
+#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
+        ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
+#endif /* ADVANSYS_DEBUG */
+
+#ifndef ADVANSYS_ASSERT
+#define ASC_ASSERT(a)
+#else /* ADVANSYS_ASSERT */
+
+#define ASC_ASSERT(a) \
+    { \
+        if (!(a)) { \
+            printk("ASC_ASSERT() Failure: file %s, line %d\n", \
+                __FILE__, __LINE__); \
+        } \
+    }
+
+#endif /* ADVANSYS_ASSERT */
 
-/* Per board statistics structure */
-struct asc_stats {
-	/* Driver Entrypoint Statistics */
-	ulong 	command;		/* # calls to advansys_command() */
-	ulong 	queuecommand;	/* # calls to advansys_queuecommand() */
-	ulong 	abort;			/* # calls to advansys_abort() */
-	ulong 	reset;			/* # calls to advansys_reset() */
-	ulong 	biosparam;		/* # calls to advansys_biosparam() */
-	ulong 	check_interrupt;/* # advansys_interrupt() check pending calls */
-	ulong 	interrupt;		/* # advansys_interrupt() interrupts */
-	ulong 	callback;		/* # calls asc_isr_callback() */
-	ulong 	done;			/* # calls request scsi_done */
-	/* AscExeScsiQueue() Statistics */
-	ulong 	asc_noerror;	/* # AscExeScsiQueue() ASC_NOERROR returns. */
-	ulong 	asc_busy;		/* # AscExeScsiQueue() ASC_BUSY returns. */
-	ulong 	asc_error;		/* # AscExeScsiQueue() ASC_ERROR returns. */
-	ulong 	asc_unknown;	/* # AscExeScsiQueue() unknown returns. */
-	/* Data Transfer Statistics */
-	ulong 	cont_cnt;		/* # non-scatter-gather I/O requests received */
-	ulong 	cont_xfer;		/* # contiguous transfer 512-bytes */
-	ulong 	sg_cnt;			/* # scatter-gather I/O requests received */
-	ulong 	sg_elem;		/* # scatter-gather elements */
-	ulong 	sg_xfer;		/* # scatter-gather transfer 512-bytes */
-};
-#endif /* ADVANSYS_STATS */
+
+/*
+ * --- Driver Structures
+ */
+
+#ifdef ADVANSYS_STATS
+
+/* Per board statistics structure */
+struct asc_stats {
+    /* Driver Entrypoint Statistics */
+    ulong     command;         /* # calls to advansys_command() */
+    ulong     queuecommand;    /* # calls to advansys_queuecommand() */
+    ulong     abort;           /* # calls to advansys_abort() */
+    ulong     reset;           /* # calls to advansys_reset() */
+    ulong     biosparam;       /* # calls to advansys_biosparam() */
+    ulong     interrupt;       /* # advansys_interrupt() calls */
+    ulong     callback;        /* # calls to asc/adv_isr_callback() */
+    ulong     done;            /* # calls to request's scsi_done function */
+    ulong     build_error;     /* # asc/adv_build_req() ASC_ERROR returns. */
+    ulong     adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
+    ulong     adv_build_nosg;  /* # adv_build_req() adv_sgblk_t alloc. fail. */
+    /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
+    ulong     exe_noerror;     /* # ASC_NOERROR returns. */
+    ulong     exe_busy;        /* # ASC_BUSY returns. */
+    ulong     exe_error;       /* # ASC_ERROR returns. */
+    ulong     exe_unknown;     /* # unknown returns. */
+    /* Data Transfer Statistics */
+    ulong     cont_cnt;        /* # non-scatter-gather I/O requests received */
+    ulong     cont_xfer;       /* # contiguous transfer 512-bytes */
+    ulong     sg_cnt;          /* # scatter-gather I/O requests received */
+    ulong     sg_elem;         /* # scatter-gather elements */
+    ulong     sg_xfer;         /* # scatter-gather transfer 512-bytes */
+};
+#endif /* ADVANSYS_STATS */
 
 /*
  * Request queuing structure
  */
 typedef struct asc_queue {
-	ASC_SCSI_BIT_ID_TYPE	q_tidmask;				  /* queue mask */
-	REQP					q_first[ASC_MAX_TID+1];	  /* first queued request */
-	REQP					q_last[ASC_MAX_TID+1];	  /* last queued request */
+    ADV_SCSI_BIT_ID_TYPE  q_tidmask;                /* queue mask */
+    REQP                  q_first[ADV_MAX_TID+1];   /* first queued request */
+    REQP                  q_last[ADV_MAX_TID+1];    /* last queued request */
 #ifdef ADVANSYS_STATS
-	short					q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */
-	short					q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */
-	ulong					q_tot_cnt[ASC_MAX_TID+1]; /* total enqueue count */
-	ulong					q_tot_tim[ASC_MAX_TID+1]; /* total time queued */
-	ushort					q_max_tim[ASC_MAX_TID+1]; /* maximum time queued */
-	ushort					q_min_tim[ASC_MAX_TID+1]; /* minimum time queued */
+    short                 q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */
+    short                 q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */
+    ulong                 q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */
+    ulong                 q_tot_tim[ADV_MAX_TID+1]; /* total time queued */
+    ushort                q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */
+    ushort                q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */
 #endif /* ADVANSYS_STATS */
 } asc_queue_t;
 
 /*
+ * Adv Library Request Structures
+ *
+ * The following two se structures are used to process Wide Board requests.
+ * One structure is needed for each command received from the Mid-Level SCSI
+ * driver.
+ *
+ * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
+ * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
+ * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
+ * Mid-Level SCSI request structure.
+ *
+ * The adv_sgblk_t structure is used to handle requests that include
+ * scatter-gather elements.
+ */
+typedef struct adv_sgblk {
+    ADV_SG_BLOCK        sg_block[ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING];
+    uchar               align2[4];       /* Sgblock structure padding. */
+    struct adv_sgblk    *next_sgblkp;    /* Next scatter-gather structure. */
+} adv_sgblk_t;
+
+typedef struct adv_req {
+    ADV_SCSI_REQ_Q      scsi_req_q;   /* Adv Library request structure. */
+    uchar               align1[4];    /* Request structure padding. */
+    Scsi_Cmnd           *cmndp;       /* Mid-Level SCSI command pointer. */
+    adv_sgblk_t         *sgblkp;      /* Adv Library scatter-gather pointer. */
+    struct adv_req      *next_reqp;   /* Next Request Structure. */
+} adv_req_t;
+
+/*
  * Structure allocated for each board.
  *
  * This structure is allocated by scsi_register() at the end
@@ -2530,34 +3648,60 @@
  * field. It is guaranteed to be allocated from DMA-able memory.
  */
 typedef struct asc_board {
-	int				 	 id;				/* Board Id */
-	uint				 flags;				/* Board flags */
-	ASC_DVC_VAR			 asc_dvc_var;		/* Board configuration */
-	ASC_DVC_CFG			 asc_dvc_cfg;		/* Device configuration */
-	asc_queue_t			 active;			/* Active command queue */
-	asc_queue_t			 waiting;		  	/* Waiting command queue */
-	asc_queue_t			 done;				/* Done command queue */
-	ASC_SCSI_BIT_ID_TYPE init_tidmask;		/* Target initialized mask */
-	/* The following three structures must be in DMA-able memory. */
-	ASC_SCSI_REQ_Q		 scsireqq;
-	ASC_CAP_INFO		 cap_info;
-	ASC_SCSI_INQUIRY	 inquiry;
-	Scsi_Device			 *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */
-	ushort				 reqcnt[ASC_MAX_TID+1]; /* Starvation request count */
+    int                  id;                    /* Board Id */
+    uint                 flags;                 /* Board flags */
+    union {
+        ASC_DVC_VAR      asc_dvc_var;           /* Narrow board */
+        ADV_DVC_VAR      adv_dvc_var;           /* Wide board */
+    } dvc_var;
+    union {
+        ASC_DVC_CFG      asc_dvc_cfg;           /* Narrow board */
+        ADV_DVC_CFG      adv_dvc_cfg;           /* Wide board */
+    } dvc_cfg;
+    asc_queue_t          active;                /* Active command queue */
+    asc_queue_t          waiting;               /* Waiting command queue */
+    asc_queue_t          done;                  /* Done command queue */
+    ADV_SCSI_BIT_ID_TYPE init_tidmask;          /* Target init./valid mask */
+    Scsi_Device          *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
+    ushort               reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
 #if ASC_QUEUE_FLOW_CONTROL
-	ushort				 nerrcnt[ASC_MAX_TID+1]; /* No error request count */
+    ushort               nerrcnt[ADV_MAX_TID+1]; /* No error request count */
 #endif /* ASC_QUEUE_FLOW_CONTROL */
-	ASC_SCSI_BIT_ID_TYPE queue_full;		/* Queue full mask */
-	ushort	queue_full_cnt[ASC_MAX_TID+1];	/* Queue full count */
-	ASCEEP_CONFIG		 eep_config;		/* EEPROM configuration */
-	ulong				 last_reset;		/* Saved time of last reset */
+    ADV_SCSI_BIT_ID_TYPE queue_full;            /* Queue full mask */
+    ushort               queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
+    union {
+        ASCEEP_CONFIG    asc_eep;               /* Narrow EEPROM config. */
+        ADVEEP_CONFIG    adv_eep;               /* Wide EEPROM config. */
+    } eep_config;
+    ulong                last_reset;            /* Saved last reset time */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-	/* /proc/scsi/advansys/[0...] */
-	char				 *prtbuf;			/* Statistics Print Buffer */
+    /* /proc/scsi/advansys/[0...] */
+    char                 *prtbuf;               /* Statistics Print Buffer */
 #endif /* version >= v1.3.0 */
 #ifdef ADVANSYS_STATS
-	struct asc_stats	 asc_stats;			/* Board statistics */
+    struct asc_stats     asc_stats;             /* Board statistics */
 #endif /* ADVANSYS_STATS */
+    /*
+     * The following fields are used only for Narrow Boards.
+     */
+    /* The following three structures must be in DMA-able memory. */
+    ASC_SCSI_REQ_Q       scsireqq;
+    ASC_CAP_INFO         cap_info;
+    ASC_SCSI_INQUIRY     inquiry;
+    uchar                sdtr_data[ASC_MAX_TID+1]; /* SDTR information */
+    /*
+     * The following fields are used only for Wide Boards.
+     */
+    void                 *ioremap_addr;         /* I/O Memory remap address. */
+    ushort               ioport;                /* I/O Port address. */
+    adv_req_t            *orig_reqp;            /* adv_req_t memory block. */
+    adv_req_t            *adv_reqp;             /* Request structures. */
+    adv_sgblk_t          *orig_sgblkp;          /* adv_sgblk_t memory block. */
+    adv_sgblk_t          *adv_sgblkp;           /* Scatter-gather structures. */
+    ushort               bios_signature;        /* BIOS Signature. */
+    ushort               bios_version;          /* BIOS Version. */
+    ushort               bios_codeseg;          /* BIOS Code Segment. */
+    ushort               bios_codelen;          /* BIOS Code Segment Length. */
 } asc_board_t;
 
 /*
@@ -2565,48 +3709,48 @@
  */
 typedef struct _PCI_DATA_
 {
-	uchar	type;
-	uchar	bus;
-	uchar	slot;
-	uchar	func;
-	uchar	offset;
+    uchar    type;
+    uchar    bus;
+    uchar    slot;
+    uchar    func;
+    uchar    offset;
 } PCI_DATA;
 
 typedef struct _PCI_DEVICE_
 {
-	ushort	vendorID;
-	ushort	deviceID;
-	ushort	slotNumber;
-	ushort	slotFound;
-	uchar	busNumber;
-	uchar	maxBusNumber;
-	uchar	devFunc;
-	ushort	startSlot;
-	ushort	endSlot;
-	uchar	bridge;
-	uchar	type;
+    ushort   vendorID;
+    ushort   deviceID;
+    ushort   slotNumber;
+    ushort   slotFound;
+    uchar    busNumber;
+    uchar    maxBusNumber;
+    uchar    devFunc;
+    ushort   startSlot;
+    ushort   endSlot;
+    uchar    bridge;
+    uchar    type;
 } PCI_DEVICE;
 
 typedef struct _PCI_CONFIG_SPACE_
 {
-	ushort	vendorID;
-	ushort	deviceID;
-	ushort	command;
-	ushort	status;
-	uchar	revision;
-	uchar	classCode[3];
-	uchar	cacheSize;
-	uchar	latencyTimer;
-	uchar	headerType;
-	uchar	bist;
-	ulong	baseAddress[6];
-	ushort	reserved[4];
-	ulong	optionRomAddr;
-	ushort	reserved2[4];
-	uchar	irqLine;
-	uchar	irqPin;
-	uchar	minGnt;
-	uchar	maxLatency;
+    ushort   vendorID;
+    ushort   deviceID;
+    ushort   command;
+    ushort   status;
+    uchar    revision;
+    uchar    classCode[3];
+    uchar    cacheSize;
+    uchar    latencyTimer;
+    uchar    headerType;
+    uchar    bist;
+    ulong    baseAddress[6];
+    ushort   reserved[4];
+    ulong    optionRomAddr;
+    ushort   reserved2[4];
+    uchar    irqLine;
+    uchar    irqPin;
+    uchar    minGnt;
+    uchar    maxLatency;
 } PCI_CONFIG_SPACE;
 
 
@@ -2619,17 +3763,17 @@
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 struct proc_dir_entry proc_scsi_advansys =
 {
-	PROC_SCSI_ADVANSYS,				/* unsigned short low_ino */
-	8,								/* unsigned short namelen */
-	"advansys",						/* const char *name */
-	S_IFDIR | S_IRUGO | S_IXUGO,	/* mode_t mode */
-	2								/* nlink_t nlink */
+    PROC_SCSI_ADVANSYS,              /* unsigned short low_ino */
+    8,                               /* unsigned short namelen */
+    "advansys",                      /* const char *name */
+    S_IFDIR | S_IRUGO | S_IXUGO,     /* mode_t mode */
+    2                                /* nlink_t nlink */
 };
 #endif /* version >= v1.3.0 */
 
 /* Number of boards detected in system. */
 STATIC int asc_board_count = 0;
-STATIC struct Scsi_Host	*asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
+STATIC struct Scsi_Host    *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
 
 /* Overrun buffer shared between all boards. */
 STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
@@ -2641,34 +3785,48 @@
 STATIC ASC_SG_HEAD asc_sg_head = { 0 };
 
 /* List of supported bus types. */
-STATIC ushort asc_bus[ASC_NUM_BUS] = {
-	ASC_IS_ISA,
-	ASC_IS_VL,
-	ASC_IS_EISA,
-	ASC_IS_PCI,
+STATIC ushort asc_bus[ASC_NUM_BUS] ASC_INITDATA = {
+    ASC_IS_ISA,
+    ASC_IS_VL,
+    ASC_IS_EISA,
+    ASC_IS_PCI,
 };
 
-STATIC int pci_scan_method = -1;
+STATIC int pci_scan_method ASC_INITDATA = -1;
 
 /*
  * Used with the LILO 'advansys' option to eliminate or
  * limit I/O port probing at boot time, cf. advansys_setup().
  */
-int asc_iopflag = ASC_FALSE;
-int asc_ioport[ASC_NUM_BOARD_SUPPORTED] = { 0, 0, 0, 0 };
+STATIC int asc_iopflag = ASC_FALSE;
+STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+/*
+ * In kernels earlier than v1.3.0, kmalloc() does not work
+ * during driver initialization. Therefore statically declare
+ * 16 elements of each structure. v1.3.0 kernels will probably
+ * not need any more than this number.
+ */
+uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 };
+uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 };
+#endif /* version >= v1,3,0 */
 
 #ifdef ADVANSYS_DEBUG
-char *
+STATIC char *
 asc_bus_name[ASC_NUM_BUS] = {
-	"ASC_IS_ISA",
-	"ASC_IS_VL",
-	"ASC_IS_EISA",
-	"ASC_IS_PCI",
+    "ASC_IS_ISA",
+    "ASC_IS_VL",
+    "ASC_IS_EISA",
+    "ASC_IS_PCI",
 };
 
-int		asc_dbglvl = 0;
+STATIC int          asc_dbglvl = 0;
 #endif /* ADVANSYS_DEBUG */
 
+/* Declaration for Asc Library internal data referenced by driver. */
+STATIC PortAddr     _asc_def_iop_base[];
+
 
 /*
  * --- Driver Function Prototypes
@@ -2677,60 +3835,77 @@
  */
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-STATIC int			asc_proc_copy(off_t, off_t, char *, int , char *, int);
+STATIC int          asc_proc_copy(off_t, off_t, char *, int , char *, int);
 #endif /* version >= v1.3.0 */
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-STATIC void 		advansys_interrupt(int, struct pt_regs *);
+STATIC void         advansys_interrupt(int, struct pt_regs *);
 #else /* version >= v1.3.70 */
-STATIC void 		advansys_interrupt(int, void *, struct pt_regs *);
+STATIC void         advansys_interrupt(int, void *, struct pt_regs *);
 #endif /* version >= v1.3.70 */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC void 		advansys_select_queue_depths(struct Scsi_Host *,
-												Scsi_Device *);
+STATIC void         advansys_select_queue_depths(struct Scsi_Host *,
+                                                Scsi_Device *);
 #endif /* version >= v1.3.89 */
-STATIC void 		advansys_command_done(Scsi_Cmnd *);
-STATIC void 		asc_scsi_done_list(Scsi_Cmnd *);
-STATIC int 			asc_execute_scsi_cmnd(Scsi_Cmnd *);
-STATIC void 		asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
-STATIC int 			asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
-STATIC int 			asc_srch_pci_dev(PCI_DEVICE *);
-STATIC uchar 		asc_scan_method(void);
-STATIC int 			asc_pci_find_dev(PCI_DEVICE *);
-STATIC void 		asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *);
-STATIC ushort 		asc_get_cfg_word(PCI_DATA *);
-STATIC uchar 		asc_get_cfg_byte(PCI_DATA *);
-STATIC void 		asc_put_cfg_byte(PCI_DATA *, uchar);
-void				asc_enqueue(asc_queue_t *, REQP, int);
-REQP 				asc_dequeue(asc_queue_t *, int);
-REQP 				asc_dequeue_list(asc_queue_t *, REQP *, int);
-int					asc_rmqueue(asc_queue_t *, REQP);
-int					asc_isqueued(asc_queue_t *, REQP);
-void				asc_execute_queue(asc_queue_t *);
-STATIC int			asc_prt_board_devices(struct Scsi_Host *, char *, int);
-STATIC int			asc_prt_board_eeprom(struct Scsi_Host *, char *, int);
-STATIC int			asc_prt_driver_conf(struct Scsi_Host *, char *, int);
-STATIC int			asc_prt_board_info(struct Scsi_Host *, char *, int);
-STATIC int			asc_proc_copy(off_t, off_t, char *, int , char *, int);
-STATIC int			asc_prt_line(char *, int, char *fmt, ...);
-
-/* XXX - Asc Library Routines not supposed to be used directly */
-int             	AscFindSignature(PortAddr);
-ushort          	AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC void       advansys_command_done(Scsi_Cmnd *);
+STATIC void       asc_scsi_done_list(Scsi_Cmnd *);
+STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
+STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
+STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
+STATIC int        adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *);
+STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
+STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int        asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
+STATIC int        asc_srch_pci_dev(PCI_DEVICE *);
+STATIC uchar      asc_scan_method(void);
+STATIC int        asc_pci_find_dev(PCI_DEVICE *);
+STATIC void       asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *);
+STATIC ushort     asc_get_cfg_word(PCI_DATA *);
+STATIC uchar      asc_get_cfg_byte(PCI_DATA *);
+STATIC void       asc_put_cfg_byte(PCI_DATA *, uchar);
+STATIC void       asc_enqueue(asc_queue_t *, REQP, int);
+STATIC REQP       asc_dequeue(asc_queue_t *, int);
+STATIC REQP       asc_dequeue_list(asc_queue_t *, REQP *, int);
+STATIC int        asc_rmqueue(asc_queue_t *, REQP);
+STATIC int        asc_isqueued(asc_queue_t *, REQP);
+STATIC void       asc_execute_queue(asc_queue_t *);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+STATIC int        asc_prt_board_devices(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_adv_bios(struct Scsi_Host *, char *, int);
+STATIC int        asc_get_eeprom_string(ushort *serialnum, uchar *cp);
+STATIC int        asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_driver_conf(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_line(char *, int, char *fmt, ...);
+#endif /* version >= v1.3.0 */
+
+/* Declaration for Asc Library internal functions reference by driver. */
+STATIC int          AscFindSignature(PortAddr);
+STATIC ushort       AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
 
 #ifdef ADVANSYS_STATS
-STATIC int			asc_prt_board_stats(struct Scsi_Host *, char *, int);
+STATIC int          asc_prt_board_stats(struct Scsi_Host *, char *, int);
 #endif /* ADVANSYS_STATS */
+
 #ifdef ADVANSYS_DEBUG
-STATIC void 		asc_prt_scsi_host(struct Scsi_Host *);
-STATIC void 		asc_prt_scsi_cmnd(Scsi_Cmnd *);
-STATIC void 		asc_prt_dvc_cfg(ASC_DVC_CFG *);
-STATIC void 		asc_prt_dvc_var(ASC_DVC_VAR *);
-STATIC void 		asc_prt_scsi_q(ASC_SCSI_Q *);
-STATIC void 		asc_prt_qdone_info(ASC_QDONE_INFO *);
-STATIC void 		asc_prt_hex(char *f, uchar *, int);
-STATIC int 			interrupts_enabled(void);
+STATIC void         asc_prt_scsi_host(struct Scsi_Host *);
+STATIC void         asc_prt_scsi_cmnd(Scsi_Cmnd *);
+STATIC void         asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
+STATIC void         asc_prt_asc_dvc_var(ASC_DVC_VAR *);
+STATIC void         asc_prt_asc_scsi_q(ASC_SCSI_Q *);
+STATIC void         asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
+STATIC void         asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
+STATIC void         asc_prt_adv_dvc_var(ADV_DVC_VAR *);
+STATIC void         asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
+STATIC void         asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
+STATIC void         asc_prt_hex(char *f, uchar *, int);
 #endif /* ADVANSYS_DEBUG */
 
+#ifdef ADVANSYS_ASSERT
+STATIC int             interrupts_enabled(void);
+#endif /* ADVANSYS_ASSERT */
+
 
 /*
  * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
@@ -2759,187 +3934,217 @@
  */
 int
 advansys_proc_info(char *buffer, char **start, off_t offset, int length, 
-				   int hostno, int inout)
+                   int hostno, int inout)
 {
-	struct Scsi_Host	*shp;
-	asc_board_t 		*boardp;
-	int					i;
-	char				*cp;
-	int					cplen;
-	int					cnt;
-	int					totcnt;
-	int					leftlen;
-	char				*curbuf;
-	off_t				advoffset;
-    Scsi_Device			*scd;
-
-	ASC_DBG(1, "advansys_proc_info: begin\n");
-
-	/*
-	 * User write not supported.
-	 */
-	if (inout == TRUE) {
-		return(-ENOSYS);
-	}
-
-	/*
-	 * User read of /proc/scsi/advansys/[0...] file.
-	 */
-
-	/* Find the specified board. */
-	for (i = 0; i < asc_board_count; i++) {
-		if (asc_host[i]->host_no == hostno) {
-			break;
-		}
-	}
-	if (i == asc_board_count) {
-		return(-ENOENT);
-	}
-
-	shp = asc_host[i];
-	boardp = ASC_BOARDP(shp);
-
-	/* Copy read data starting at the beginning of the buffer. */
-	*start = buffer;
-	curbuf = buffer;
-	advoffset = 0;
-	totcnt = 0;
-	leftlen = length;
-
-	/*
-	 * Get board configuration information.
-	 *
-	 * advansys_info() returns the board string from its own static buffer.
-	 */
-	cp = (char *) advansys_info(shp);
-	strcat(cp, "\n");
-	cplen = strlen(cp);
-	/* Copy board information. */
-	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-	totcnt += cnt;
-	leftlen -= cnt;
-	if (leftlen == 0) {
-		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-		return totcnt;
-	}
-	advoffset += cplen;
-	curbuf += cnt;
-
-	/*
-	 * Display driver information for each device attached to the board.
-	 */
-	cp = boardp->prtbuf;
-	cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
-	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-	totcnt += cnt;
-	leftlen -= cnt;
-	if (leftlen == 0) {
-		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-		return totcnt;
-	}
-	advoffset += cplen;
-	curbuf += cnt;
-
-	/*
-	 * Display target driver information for each device attached
-	 * to the board.
-	 */
-    for (scd = scsi_devices; scd; scd = scd->next) {
-		if (scd->host == shp) {
-			cp = boardp->prtbuf;
-			/*
-			 * Note: If proc_print_scsidevice() writes more than
-			 * ASC_PRTBUF_SIZE bytes, it will overrun 'prtbuf'.
-			 */
-	    	proc_print_scsidevice(scd, cp, &cplen, 0);
-			ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-			cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-			totcnt += cnt;
-			leftlen -= cnt;
-			if (leftlen == 0) {
-				ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-				return totcnt;
-			}
-			advoffset += cplen;
-			curbuf += cnt;
-		}
+    struct Scsi_Host    *shp;
+    asc_board_t         *boardp;
+    int                 i;
+    char                *cp;
+    int                 cplen;
+    int                 cnt;
+    int                 totcnt;
+    int                 leftlen;
+    char                *curbuf;
+    off_t               advoffset;
+    Scsi_Device         *scd;
+
+    ASC_DBG(1, "advansys_proc_info: begin\n");
+
+    /*
+     * User write not supported.
+     */
+    if (inout == TRUE) {
+        return(-ENOSYS);
+    }
+
+    /*
+     * User read of /proc/scsi/advansys/[0...] file.
+     */
+
+    /* Find the specified board. */
+    for (i = 0; i < asc_board_count; i++) {
+        if (asc_host[i]->host_no == hostno) {
+            break;
+        }
+    }
+    if (i == asc_board_count) {
+        return(-ENOENT);
+    }
+
+    shp = asc_host[i];
+    boardp = ASC_BOARDP(shp);
+
+    /* Copy read data starting at the beginning of the buffer. */
+    *start = buffer;
+    curbuf = buffer;
+    advoffset = 0;
+    totcnt = 0;
+    leftlen = length;
+
+    /*
+     * Get board configuration information.
+     *
+     * advansys_info() returns the board string from its own static buffer.
+     */
+    cp = (char *) advansys_info(shp);
+    strcat(cp, "\n");
+    cplen = strlen(cp);
+    /* Copy board information. */
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    /*
+     * Display Wide Board BIOS Information.
+     */
+    if (ASC_WIDE_BOARD(boardp)) {
+        cp = boardp->prtbuf;
+        cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
+        ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+        cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+        totcnt += cnt;
+        leftlen -= cnt;
+        if (leftlen == 0) {
+            ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+            return totcnt;
+        }
+        advoffset += cplen;
+        curbuf += cnt;
+    }
+
+    /*
+     * Display driver information for each device attached to the board.
+     */
+    cp = boardp->prtbuf;
+    cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    /*
+     * Display target driver information for each device attached
+     * to the board.
+     */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
+    for (scd = scsi_devices; scd; scd = scd->next)
+#else /* version >= v2.1.75 */
+    for (scd = shp->host_queue; scd; scd = scd->next)
+#endif /* version >= v2.1.75 */
+    {
+        if (scd->host == shp) {
+            cp = boardp->prtbuf;
+            /*
+             * Note: If proc_print_scsidevice() writes more than
+             * ASC_PRTBUF_SIZE bytes, it will overrun 'prtbuf'.
+             */
+            proc_print_scsidevice(scd, cp, &cplen, 0);
+            ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+            cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+            totcnt += cnt;
+            leftlen -= cnt;
+            if (leftlen == 0) {
+                ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+                return totcnt;
+            }
+            advoffset += cplen;
+            curbuf += cnt;
+        }
     }
     
-	/*
-	 * Display EEPROM configuration for the board.
-	 */
-	cp = boardp->prtbuf;
-	cplen = asc_prt_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
-	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-	totcnt += cnt;
-	leftlen -= cnt;
-	if (leftlen == 0) {
-		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-		return totcnt;
-	}
-	advoffset += cplen;
-	curbuf += cnt;
-
-	/*
-	 * Display driver configuration and information for the board.
-	 */
-	cp = boardp->prtbuf;
-	cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
-	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-	totcnt += cnt;
-	leftlen -= cnt;
-	if (leftlen == 0) {
-		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-		return totcnt;
-	}
-	advoffset += cplen;
-	curbuf += cnt;
+    /*
+     * Display EEPROM configuration for the board.
+     */
+    cp = boardp->prtbuf;
+    if (ASC_NARROW_BOARD(boardp)) {
+        cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+    } else {
+        cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+    }
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    /*
+     * Display driver configuration and information for the board.
+     */
+    cp = boardp->prtbuf;
+    cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
 
 #ifdef ADVANSYS_STATS
-	/*
-	 * Display driver statistics for the board.
-	 */
-	cp = boardp->prtbuf;
-	cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
-	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-	totcnt += cnt;
-	leftlen -= cnt;
-	if (leftlen == 0) {
-		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-		return totcnt;
-	}
-	advoffset += cplen;
-	curbuf += cnt;
+    /*
+     * Display driver statistics for the board.
+     */
+    cp = boardp->prtbuf;
+    cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
 #endif /* ADVANSYS_STATS */
 
-	/*
-	 * Display Asc Library dynamic configuration information
-	 * for the board.
-	 */
-	cp = boardp->prtbuf;
-	cplen = asc_prt_board_info(shp, cp, ASC_PRTBUF_SIZE);
-	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-	totcnt += cnt;
-	leftlen -= cnt;
-	if (leftlen == 0) {
-		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-		return totcnt;
-	}
-	advoffset += cplen;
-	curbuf += cnt;
+    /*
+     * Display Asc Library dynamic configuration information
+     * for the board.
+     */
+    cp = boardp->prtbuf;
+    if (ASC_NARROW_BOARD(boardp)) {
+        cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
+    } else {
+        cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
+    }
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
 
-	ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+    ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
 
-	return totcnt;
+    return totcnt;
 }
 #endif /* version >= v1.3.0 */
 
-
 /*
  * advansys_detect()
  *
@@ -2953,558 +4158,913 @@
  * it must not call SCSI mid-level functions including scsi_malloc()
  * and scsi_free().
  */
+ASC_INITFUNC(
 int
 advansys_detect(Scsi_Host_Template *tpnt)
+)
 {
-	static int			detect_called = ASC_FALSE;
-	int					iop;
-	int					bus;
-	struct Scsi_Host	*shp;
-	asc_board_t			*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	int					ioport = 0;
-	int					share_irq = FALSE;
-	PCI_DEVICE			pciDevice;
-	PCI_CONFIG_SPACE	pciConfig;
-	int					ret;
-	extern PortAddr		_asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX];
-
-
-	if (detect_called == ASC_FALSE) {
-		detect_called = ASC_TRUE;
-	} else {
-		printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n");
-		return 0;
-	}
+    static int          detect_called = ASC_FALSE;
+    int                 iop;
+    int                 bus;
+    struct Scsi_Host    *shp;
+    asc_board_t         *boardp;
+    ASC_DVC_VAR         *asc_dvc_varp = NULL;
+    ADV_DVC_VAR         *adv_dvc_varp = NULL;
+    int                 ioport = 0;
+    int                 share_irq = FALSE;
+    PCI_DEVICE          pciDevice;
+    PCI_CONFIG_SPACE    pciConfig;
+    int                 warn_code, err_code;
+    int                 ret;
+
+    if (detect_called == ASC_FALSE) {
+        detect_called = ASC_TRUE;
+    } else {
+        printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
+        return 0;
+    }
 
-	ASC_DBG(1, "advansys_detect: begin\n");
+    ASC_DBG(1, "advansys_detect: begin\n");
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-	tpnt->proc_dir = &proc_scsi_advansys;
+    tpnt->proc_dir = &proc_scsi_advansys;
 #endif /* version >= v1.3.0 */
 
-	asc_board_count = 0;
+    asc_board_count = 0;
+
+    /*
+     * If I/O port probing has been modified, then verify and
+     * clean-up the 'asc_ioport' list.
+     */
+    if (asc_iopflag == ASC_TRUE) {
+        for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
+            ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n",
+                ioport, asc_ioport[ioport]);
+            if (asc_ioport[ioport] != 0) {
+                for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) {
+                    if (_asc_def_iop_base[iop] == asc_ioport[ioport]) {
+                        break;
+                    }
+                }
+                if (iop == ASC_IOADR_TABLE_MAX_IX) {
+                    printk(
+"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
+                        asc_ioport[ioport]);
+                    asc_ioport[ioport] = 0;
+                }
+            }
+        }
+        ioport = 0;
+    }
+
+    memset(&pciDevice, 0, sizeof(PCI_DEVICE));
+    memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE));
+    pciDevice.maxBusNumber = PCI_MAX_BUS;
+    pciDevice.endSlot = PCI_MAX_SLOT;
+
+    for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+
+        ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
+            bus, asc_bus_name[bus]);
+        iop = 0;
+
+        while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+
+            ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
+                asc_board_count);
+
+            switch (asc_bus[bus]) {
+            case ASC_IS_ISA:
+            case ASC_IS_VL:
+                if (asc_iopflag == ASC_FALSE) {
+                    iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+                } else {
+                    /*
+                     * ISA and VL I/O port scanning has either been
+                     * eliminated or limited to selected ports on
+                     * the LILO command line, /etc/lilo.conf, or
+                     * by setting variables when the module was loaded.
+                     */
+                    ASC_DBG(1, "advansys_detect: I/O port scanning modified\n");
+                ioport_try_again:
+                    iop = 0;
+                    for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
+                        if ((iop = asc_ioport[ioport]) != 0) {
+                            break;
+                        }
+                    }
+                    if (iop) {
+                        ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n",
+                            iop);
+                        if (check_region(iop, ASC_IOADR_GAP) != 0) {
+                            printk(
+"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
+                            /* Don't try this I/O port twice. */
+                            asc_ioport[ioport] = 0;
+                            goto ioport_try_again;
+                        } else if (AscFindSignature(iop) == ASC_FALSE) {
+                            printk(
+"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
+                            /* Don't try this I/O port twice. */
+                            asc_ioport[ioport] = 0;
+                            goto ioport_try_again;
+                        } else {
+                            /*
+                             * If this isn't an ISA board, then it must be
+                             * a VL board. If currently looking an ISA
+                             * board is being looked for then try for
+                             * another ISA board in 'asc_ioport'.
+                             */
+                            if (asc_bus[bus] == ASC_IS_ISA &&
+                                (AscGetChipVersion(iop, ASC_IS_ISA) &
+                                 ASC_CHIP_VER_ISA_BIT) == 0) {
+                                 /*
+                                 * Don't clear 'asc_ioport[ioport]'. Try
+                                 * this board again for VL. Increment
+                                 * 'ioport' past this board.
+                                 */
+                                 ioport++;
+                                 goto ioport_try_again;
+                            }
+                        }
+                        /*
+                         * This board appears good, don't try the I/O port
+                         * again by clearing its value. Increment 'ioport'
+                         * for the next iteration.
+                         */
+                        asc_ioport[ioport++] = 0;
+                    }
+                }
+                break;
+
+            case ASC_IS_EISA:
+                iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+                break;
+
+            case ASC_IS_PCI:
+                    if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) {
+                        iop = 0;
+                    } else {
+                        ASC_DBG2(2,
+                            "advansys_detect: slotFound %d, busNumber %d\n",
+                            pciDevice.slotFound, pciDevice.busNumber);
+                        asc_get_pci_cfg(&pciDevice, &pciConfig);
+                        iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK;
+                        ASC_DBG2(1,
+                            "advansys_detect: vendorID %X, deviceID %X\n",
+                            pciConfig.vendorID, pciConfig.deviceID);
+                        ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
+                            iop, pciConfig.irqLine);
+                    }
+                break;
+
+            default:
+                ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
+                    asc_bus[bus]);
+                break;
+            }
+            ASC_DBG1(1, "advansys_detect: iop %x\n", iop);
+
+            /*
+             * Adapter not found, try next bus type.
+             */
+            if (iop == 0) {
+                break;
+            }
+
+            /*
+             * Adapter found.
+             *
+             * Register the adapter, get its configuration, and
+             * initialize it.
+             */
+            ASC_DBG(2, "advansys_detect: scsi_register()\n");
+            shp = scsi_register(tpnt, sizeof(asc_board_t));
+
+            /* Save a pointer to the Scsi_host of each board found. */
+            asc_host[asc_board_count++] = shp;
+
+            /* Initialize private per board data */
+            boardp = ASC_BOARDP(shp);
+            memset(boardp, 0, sizeof(asc_board_t));
+            boardp->id = asc_board_count - 1;
+
+            /*
+             * Handle both narrow and wide PCI boards.
+             *
+             * If a Wide board was detected, set the board structure
+             * wide board flag. Set-up the board structure based on
+             * the board type.
+             */
+            if ((asc_bus[bus] == ASC_IS_PCI &&
+                 pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) == 0) {
+                ASC_DBG(1, "advansys_detect: narrow board\n");
+                asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+                asc_dvc_varp->bus_type = asc_bus[bus];
+                asc_dvc_varp->drv_ptr = (ulong) boardp;
+                asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
+                asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
+                asc_dvc_varp->iop_base = iop;
+                asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback;
+            } else {
+                ASC_DBG(1, "advansys_detect: wide board\n");
+                boardp->flags |= ASC_IS_WIDE_BOARD;
+                adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+                adv_dvc_varp->drv_ptr = (ulong) boardp;
+                adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
+                adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback;
 
-	/*
-	 * If I/O port probing has been modified, then verify and
-	 * clean-up the 'asc_ioport' list.
-	 */
-	if (asc_iopflag == ASC_TRUE) {
-		for (ioport = 0; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) {
-			ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n",
-				ioport, asc_ioport[ioport]);
-			if (asc_ioport[ioport] != 0) {
-				for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) {
-					if (_asc_def_iop_base[iop] == asc_ioport[ioport]) {
-						break;
-					}
-				}
-				if (iop == ASC_IOADR_TABLE_MAX_IX) {
-					printk("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
-						asc_ioport[ioport]);
-					asc_ioport[ioport] = 0;
-				}
-			}
-		}
-		ioport = 0;
-	}
-
-	memset(&pciDevice, 0, sizeof(PCI_DEVICE));
-	memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE));
-	pciDevice.maxBusNumber = PCI_MAX_BUS;
-	pciDevice.endSlot = PCI_MAX_SLOT;
-
-	for (bus = 0; bus < ASC_NUM_BUS; bus++) {
-
-		ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
-			bus, asc_bus_name[bus]);
-		iop = 0;
-
-		while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
-
-			ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
-				asc_board_count);
-
-			switch (asc_bus[bus]) {
-			case ASC_IS_ISA:
-			case ASC_IS_VL:
-				if (asc_iopflag == ASC_FALSE) {
-					iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-				} else {
-					/*
-					 * ISA and VL I/O port scanning has either been
-					 * eliminated or limited to selected ports on
-					 * the LILO command line, /etc/lilo.conf, or
-					 * by setting variables when the module was loaded.
-					 */
-					ASC_DBG(1, "advansys_detect: I/O port scanning modified\n");
-				ioport_try_again:
-					iop = 0;
-					for (; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) {
-						if ((iop = asc_ioport[ioport]) != 0) {
-							break;
-						}
-					}
-					if (iop) {
-						ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n",
-							iop);
-						if (check_region(iop, ASC_IOADR_GAP) != 0) {
-							printk("AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
-							/* Don't try this I/O port twice. */
-							asc_ioport[ioport] = 0;
-							goto ioport_try_again;
-						} else if (AscFindSignature(iop) == ASC_FALSE) {
-							printk("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
-							/* Don't try this I/O port twice. */
-							asc_ioport[ioport] = 0;
-							goto ioport_try_again;
-						} else {
-							/*
-							 * If this isn't an ISA board, then it must be
-							 * a VL board. If currently looking an ISA
-							 * board is being looked for then try for
-							 * another ISA board in 'asc_ioport'.
-							 */
-							if (asc_bus[bus] == ASC_IS_ISA &&
-							    (AscGetChipVersion(iop, ASC_IS_ISA) &
-								 ASC_CHIP_VER_ISA_BIT) == 0) {
-							 	/*
-								 * Don't clear 'asc_ioport[ioport]'. Try
-								 * this board again for VL. Increment
-								 * 'ioport' past this board.
-								 */
-								 ioport++;
-								 goto ioport_try_again;
-							}
-						}
-						/*
-						 * This board appears good, don't try the I/O port
-						 * again by clearing its value. Increment 'ioport'
-						 * for the next iteration.
-						 */
-						asc_ioport[ioport++] = 0;
-					}
-				}
-				break;
-
-			case ASC_IS_EISA:
-				iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-				break;
-
-			case ASC_IS_PCI:
-					if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) {
-						iop = 0;
-					} else {
-						ASC_DBG2(2,
-							"advansys_detect: slotFound %d, busNumber %d\n",
-							pciDevice.slotFound, pciDevice.busNumber);
-						asc_get_pci_cfg(&pciDevice, &pciConfig);
-						iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK;
-						ASC_DBG2(2, "advansys_detect: iop %x, irqLine %d\n",
-							iop, pciConfig.irqLine);
-					}
-				break;
-
-			default:
-				ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
-					asc_bus[bus]);
-				break;
-			}
-			ASC_DBG1(1, "advansys_detect: iop %x\n", iop);
-
-			/*
-			 * Adapter not found, try next bus type.
-			 */
-			if (iop == 0) {
-				break;
-			}
-
-			/*
-			 * Adapter found.
-			 *
-			 * Register the adapter, get its configuration, and
-			 * initialize it.
-			 */
-			ASC_DBG(2, "advansys_detect: scsi_register()\n");
-			shp = scsi_register(tpnt, sizeof(asc_board_t));
-
-			/* Save a pointer to the Scsi_host of each board found. */
-			asc_host[asc_board_count++] = shp;
-
-			/* Initialize private per board data */
-			boardp = ASC_BOARDP(shp);
-			memset(boardp, 0, sizeof(asc_board_t));
-			boardp->id = asc_board_count - 1;
-			asc_dvc_varp = &boardp->asc_dvc_var;
-			asc_dvc_varp->drv_ptr = (ulong) boardp;
-			asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
-			asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
-			asc_dvc_varp->iop_base = iop;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+                adv_dvc_varp->iop_base = iop;
+#else /* version >= v1,3,0 */
+                /*
+                 * Map the board's registers into virtual memory for
+                 * PCI slave access. Only memory accesses are used to
+                 * access the board's registers.
+                 *
+                 * Note: The PCI register base address is not always
+                 * page aligned, but the address passed to ioremap()
+                 * must be page aligned. It is guaranteed that the
+                 * PCI register base address will not cross a page
+                 * boundary.
+                 */
+                if ((boardp->ioremap_addr =
+                    ioremap(pciConfig.baseAddress[1] & PAGE_MASK,
+                         PAGE_SIZE)) == 0) {
+                   ASC_PRINT3(
+"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
+                   boardp->id, pciConfig.baseAddress[1], ADV_CONDOR_IOLEN);
+                   scsi_unregister(shp);
+                   asc_board_count--;
+                   continue;
+                }
+                adv_dvc_varp->iop_base = (AdvPortAddr)
+                    (boardp->ioremap_addr +
+                     (pciConfig.baseAddress[1] -
+                      (pciConfig.baseAddress[1] & PAGE_MASK)));
+#endif /* version >= v1,3,0 */
+
+                /*
+                 * Even though it isn't used to access the board in
+                 * kernels greater than or equal to v1.3.0, save
+                 * the I/O Port address so that it can be reported and
+                 * displayed.
+                 */
+                boardp->ioport = iop;
+            }
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-			if ((boardp->prtbuf =
-				kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
-				ASC_PRINT3(
+            /*
+             * Allocate buffer for printing information from
+             * /proc/scsi/advansys/[0...].
+             */
+            if ((boardp->prtbuf =
+                kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
+                ASC_PRINT3(
 "advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n",
-					boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
-				scsi_unregister(shp);
-				asc_board_count--;
-				continue;
-			}
+                    boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
 #endif /* version >= v1.3.0 */
 
-			/*
-			 * Set the board bus type and PCI IRQ for AscInitGetConfig().
-			 */
-			asc_dvc_varp->bus_type = asc_bus[bus];
-			switch (asc_dvc_varp->bus_type) {
-			case ASC_IS_ISA:
-				shp->unchecked_isa_dma = TRUE;
-				share_irq = FALSE;
-				break;
-			case ASC_IS_VL:
-				shp->unchecked_isa_dma = FALSE;
-				share_irq = FALSE;
-				break;
-			case ASC_IS_EISA:
-				shp->unchecked_isa_dma = FALSE;
-				share_irq = TRUE;
-				break;
-			case ASC_IS_PCI:
-				shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine;
-				asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
-				asc_dvc_varp->cfg->pci_slot_info =
-						ASC_PCI_MKID(pciDevice.busNumber,
-									 pciDevice.slotFound,
-									 pciDevice.devFunc);
-				shp->unchecked_isa_dma = FALSE;
-				share_irq = TRUE;
-				break;
-			default:
-				ASC_PRINT2(
-"advansys_detect: board %d: unknown adapter type: %d",
-					boardp->id, asc_dvc_varp->bus_type);
-				shp->unchecked_isa_dma = TRUE;
-				share_irq = FALSE;
-				break;
-			}
-
-			/*
-			 * Get the board configuration.
-			 *
-			 * NOTE: AscInitGetConfig() may change the board's bus_type
-			 * value. The asc_bus[bus] value should no longer be used. If
-			 * the bus_type field must be referenced only use the bit-wise
-			 * AND operator "&".
-			 */
-			ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
-			switch(ret = AscInitGetConfig(asc_dvc_varp)) {
-			case 0:	/* No error */
-				break;
-			case ASC_WARN_IO_PORT_ROTATE:
-				ASC_PRINT1(
+            if (ASC_NARROW_BOARD(boardp)) {
+                /*
+                 * Set the board bus type and PCI IRQ before
+                 * calling AscInitGetConfig().
+                 */
+                switch (asc_dvc_varp->bus_type) {
+                case ASC_IS_ISA:
+                    shp->unchecked_isa_dma = TRUE;
+                    share_irq = FALSE;
+                    break;
+                case ASC_IS_VL:
+                    shp->unchecked_isa_dma = FALSE;
+                    share_irq = FALSE;
+                    break;
+                case ASC_IS_EISA:
+                    shp->unchecked_isa_dma = FALSE;
+                    share_irq = TRUE;
+                    break;
+                case ASC_IS_PCI:
+                    shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine;
+                    shp->unchecked_isa_dma = FALSE;
+                    share_irq = TRUE;
+                    asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
+                    asc_dvc_varp->cfg->pci_slot_info =
+                        ASC_PCI_MKID(pciDevice.busNumber,
+                            pciDevice.slotFound,
+                            pciDevice.devFunc);
+                    break;
+                default:
+                    ASC_PRINT2(
+"advansys_detect: board %d: unknown adapter type: %d\n",
+                        boardp->id, asc_dvc_varp->bus_type);
+                    shp->unchecked_isa_dma = TRUE;
+                    share_irq = FALSE;
+                    break;
+                }
+            } else {
+                /*
+                 * For Wide boards set PCI information before calling
+                 * AdvInitGetConfig().
+                 */
+                shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine;
+                shp->unchecked_isa_dma = FALSE;
+                share_irq = TRUE;
+                adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
+                adv_dvc_varp->cfg->pci_slot_info =
+                    ASC_PCI_MKID(pciDevice.busNumber,
+                        pciDevice.slotFound,
+                        pciDevice.devFunc);
+            }
+
+            /*
+             * Read the board configuration.
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+                 /*
+                  * NOTE: AscInitGetConfig() may change the board's
+                  * bus_type value. The asc_bus[bus] value should no
+                  * longer be used. If the bus_type field must be
+                  * referenced only use the bit-wise AND operator "&".
+                  */
+                 ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
+                switch(ret = AscInitGetConfig(asc_dvc_varp)) {
+                case 0:    /* No error */
+                    break;
+                case ASC_WARN_IO_PORT_ROTATE:
+                    ASC_PRINT1(
 "AscInitGetConfig: board %d: I/O port address modified\n",
-					boardp->id);
-				break;
-			case ASC_WARN_AUTO_CONFIG:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_AUTO_CONFIG:
+                    ASC_PRINT1(
 "AscInitGetConfig: board %d: I/O port increment switch enabled\n",
-					boardp->id);
-				break;
-			case ASC_WARN_EEPROM_CHKSUM:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_EEPROM_CHKSUM:
+                    ASC_PRINT1(
 "AscInitGetConfig: board %d: EEPROM checksum error\n",
-					boardp->id);
-				break;
-			case ASC_WARN_IRQ_MODIFIED:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_IRQ_MODIFIED:
+                    ASC_PRINT1(
 "AscInitGetConfig: board %d: IRQ modified\n",
-					boardp->id);
-				break;
-			case ASC_WARN_CMD_QNG_CONFLICT:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_CMD_QNG_CONFLICT:
+                    ASC_PRINT1(
 "AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
-					boardp->id);
-				break;
-			default:
-				ASC_PRINT2(
+                        boardp->id);
+                    break;
+                default:
+                    ASC_PRINT2(
 "AscInitGetConfig: board %d: unknown warning: %x\n",
-					boardp->id, ret);
-				break;
-			}
-			if (asc_dvc_varp->err_code != 0) {
-				ASC_PRINT3(
+                        boardp->id, ret);
+                    break;
+                }
+                if ((err_code = asc_dvc_varp->err_code) != 0) {
+                    ASC_PRINT3(
 "AscInitGetConfig: board %d error: init_state %x, err_code %x\n",
-					boardp->id, asc_dvc_varp->init_state,
-					asc_dvc_varp->err_code);
+                        boardp->id, asc_dvc_varp->init_state,
+                        asc_dvc_varp->err_code);
+                }
+            } else {
+                ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n");
+                if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
+                    ASC_PRINT2("AdvInitGetConfig: board %d: warning: %x\n",
+                        boardp->id, ret);
+                }
+                if ((err_code = adv_dvc_varp->err_code) != 0) {
+                    ASC_PRINT2(
+"AdvInitGetConfig: board %d error: err_code %x\n",
+                        boardp->id, adv_dvc_varp->err_code);
+                }
+            }
+        
+            if (err_code != 0) {
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-				kfree(boardp->prtbuf);
+                kfree(boardp->prtbuf);
 #endif /* version >= v1.3.0 */
-				scsi_unregister(shp);
-				asc_board_count--;
-				continue;
-			}
-
-			/*
-			 * Set the adapter's target id bit in the init_tidmask field.
-			 */
-			boardp->init_tidmask |=
-				ASC_TIX_TO_TARGET_ID(asc_dvc_varp->cfg->chip_scsi_id);
-
-			/*
-			 * Save EEPROM settings for the board.
-			 */
-			boardp->eep_config.init_sdtr = asc_dvc_varp->init_sdtr;
-			boardp->eep_config.disc_enable = asc_dvc_varp->cfg->disc_enable;
-			boardp->eep_config.use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
-			boardp->eep_config.isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed;
-			boardp->eep_config.start_motor = asc_dvc_varp->start_motor;
-			boardp->eep_config.cntl = asc_dvc_varp->dvc_cntl;
-			boardp->eep_config.no_scam = asc_dvc_varp->no_scam;
-			boardp->eep_config.max_total_qng = asc_dvc_varp->max_total_qng;
-			boardp->eep_config.chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id;
-			/* 'max_tag_qng' is set to the same value for every device. */
-			boardp->eep_config.max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
-
-			/*
-			 * Modify board configuration.
-			 */
-			asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback;
-			asc_dvc_varp->exe_callback = (Ptr2Func) NULL;
-
-			ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
-			switch (ret = AscInitSetConfig(asc_dvc_varp)) {
-			case 0:	/* No error. */
-				break;
-			case ASC_WARN_IO_PORT_ROTATE:
-				ASC_PRINT1(
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+
+            /*
+             * Save the EEPROM configuration so that it can be displayed
+             * from /proc/scsi/advansys/[0...].
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+
+                ASCEEP_CONFIG *ep;
+
+                /*
+                 * Set the adapter's target id bit in the 'init_tidmask' field.
+                 */
+                boardp->init_tidmask |=
+                    ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
+
+                /*
+                 * Save EEPROM settings for the board.
+                 */
+                ep = &boardp->eep_config.asc_eep;
+
+                ep->init_sdtr = asc_dvc_varp->init_sdtr;
+                ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
+                ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
+                ep->isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed;
+                ep->start_motor = asc_dvc_varp->start_motor;
+                ep->cntl = asc_dvc_varp->dvc_cntl;
+                ep->no_scam = asc_dvc_varp->no_scam;
+                ep->max_total_qng = asc_dvc_varp->max_total_qng;
+                ep->chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id;
+                /* 'max_tag_qng' is set to the same value for every device. */
+                ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
+                ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
+                ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
+                ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
+                ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
+                ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
+                ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
+                ep->adapter_info[6] = asc_dvc_varp->cfg->adapter_info[6];
+
+               /*
+                * Modify board configuration.
+                */
+                ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
+                switch (ret = AscInitSetConfig(asc_dvc_varp)) {
+                case 0:    /* No error. */
+                    break;
+                case ASC_WARN_IO_PORT_ROTATE:
+                    ASC_PRINT1(
 "AscInitSetConfig: board %d: I/O port address modified\n",
-					boardp->id);
-				break;
-			case ASC_WARN_AUTO_CONFIG:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_AUTO_CONFIG:
+                    ASC_PRINT1(
 "AscInitSetConfig: board %d: I/O port increment switch enabled\n",
-					boardp->id);
-				break;
-			case ASC_WARN_EEPROM_CHKSUM:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_EEPROM_CHKSUM:
+                    ASC_PRINT1(
 "AscInitSetConfig: board %d: EEPROM checksum error\n",
-					boardp->id);
-				break;
-			case ASC_WARN_IRQ_MODIFIED:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_IRQ_MODIFIED:
+                    ASC_PRINT1(
 "AscInitSetConfig: board %d: IRQ modified\n",
-					boardp->id);
-				break;
-			case ASC_WARN_CMD_QNG_CONFLICT:
-				ASC_PRINT1(
+                        boardp->id);
+                    break;
+                case ASC_WARN_CMD_QNG_CONFLICT:
+                    ASC_PRINT1(
 "AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
-					boardp->id);
-				break;
-			default:
-				ASC_PRINT2(
+                        boardp->id);
+                    break;
+                default:
+                    ASC_PRINT2(
 "AscInitSetConfig: board %d: unknown warning: %x\n",
-					boardp->id, ret);
-				break;
-			}
-			if (asc_dvc_varp->err_code != 0) {
-				ASC_PRINT3(
+                        boardp->id, ret);
+                    break;
+                }
+                if (asc_dvc_varp->err_code != 0) {
+                    ASC_PRINT3(
 "AscInitSetConfig: board %d error: init_state %x, err_code %x\n",
-					boardp->id, asc_dvc_varp->init_state,
-					asc_dvc_varp->err_code);
+                        boardp->id, asc_dvc_varp->init_state,
+                        asc_dvc_varp->err_code);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-				kfree(boardp->prtbuf);
+                    kfree(boardp->prtbuf);
 #endif /* version >= v1.3.0 */
-				scsi_unregister(shp);
-				asc_board_count--;
-				continue;
-			}
-
-			/*
-			 * Finish initializing the 'Scsi_Host' structure.
-			 */
-
-			/* AscInitSetConfig() will set the IRQ for non-PCI boards. */
-			if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
-				shp->irq = asc_dvc_varp->irq_no;
-			}
-
-			/*
-			 * One host supports one channel. There are two different
-			 * hosts for each channel of a dual channel board.
-			 */
+                    scsi_unregister(shp);
+                    asc_board_count--;
+                    continue;
+                }
+
+                /*
+                 * Finish initializing the 'Scsi_Host' structure.
+                 */
+                /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
+                if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
+                    shp->irq = asc_dvc_varp->irq_no;
+                }
+            } else {
+
+                ADVEEP_CONFIG *ep;
+
+                /*
+                 * Save Wide EEP Configuration Information.
+                 */
+                ep = &boardp->eep_config.adv_eep;
+
+                ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                ep->max_host_qng = adv_dvc_varp->max_host_qng;
+                ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                ep->termination = adv_dvc_varp->cfg->termination;
+                ep->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                ep->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                ep->wdtr_able = adv_dvc_varp->wdtr_able;
+                ep->sdtr_able = adv_dvc_varp->sdtr_able;
+                ep->ultra_able = adv_dvc_varp->ultra_able;
+                ep->tagqng_able = adv_dvc_varp->tagqng_able;
+                ep->start_motor = adv_dvc_varp->start_motor;
+                ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
+                ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait;
+                ep->serial_number_word1 = adv_dvc_varp->cfg->serial1;
+                ep->serial_number_word2 = adv_dvc_varp->cfg->serial2;
+                ep->serial_number_word3 = adv_dvc_varp->cfg->serial3;
+
+                /*
+                 * Set the adapter's target id bit in the 'init_tidmask' field.
+                 */
+                boardp->init_tidmask |=
+                    ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
+
+                /*
+                 * Finish initializing the 'Scsi_Host' structure.
+                 */
+                shp->irq = adv_dvc_varp->irq_no;
+            }
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-			shp->max_channel = 0;
+            /*
+             * Channels are numbered beginning with 0. For AdvanSys One host
+             * structure supports one channel. Multi-channel boards have a
+             * separate host structure for each channel. 
+             */
+            shp->max_channel = 0;
 #endif /* version >= v1.3.89 */
-			shp->max_id = ASC_MAX_TID + 1;
-			shp->max_lun = ASC_MAX_LUN + 1;
-
-			shp->io_port = asc_dvc_varp->iop_base;
-			shp->n_io_port = ASC_IOADR_GAP;
-			shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
-
-			/* Maximum number of queues this adapter can handle. */
-			shp->can_queue = asc_dvc_varp->max_total_qng;
+            if (ASC_NARROW_BOARD(boardp)) {
+                shp->max_id = ASC_MAX_TID + 1;
+                shp->max_lun = ASC_MAX_LUN + 1;
+
+                shp->io_port = asc_dvc_varp->iop_base;
+                shp->n_io_port = ASC_IOADR_GAP;
+                shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
+
+                /* Set maximum number of queues the adapter can handle. */
+                shp->can_queue = asc_dvc_varp->max_total_qng;
+            } else {
+                shp->max_id = ADV_MAX_TID + 1;
+                shp->max_lun = ADV_MAX_LUN + 1;
+
+                /*
+                 * Save the I/O Port address and length even though the
+                 * in v1.3.0 and greater kernels the region is not used
+                 * by a Wide board. Instead the board is accessed with
+                 * Memory Mapped I/O.
+                 */
+                shp->io_port = iop;
+                shp->n_io_port = ADV_CONDOR_IOLEN;
+
+                shp->this_id = adv_dvc_varp->chip_scsi_id;
+
+                /* Set maximum number of queues the adapter can handle. */
+                shp->can_queue = adv_dvc_varp->max_host_qng;
+            }
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
-			/*
-			 * Set a conservative 'cmd_per_lun' value to prevent memory
-			 * allocation failures.
-			 */
+            /*
+             * In old kernels without tag queuing support and with memory
+             * allocation problems set a conservative 'cmd_per_lun' value.
+             */
 #ifdef MODULE
-			shp->cmd_per_lun = 1;
+            shp->cmd_per_lun = 1;
 #else /* MODULE */
-			shp->cmd_per_lun = 4;
+            shp->cmd_per_lun = 4;
 #endif /* MODULE */
-			ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun);
+            ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun);
 #else /* version >= v1.3.89 */
-			/*
-			 * Use the host 'select_queue_depths' function to determine
-			 * the number of commands to queue per device.
-			 */
-			shp->select_queue_depths = advansys_select_queue_depths;
-
+            /*
+             * 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.
+             */
 #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;
+            shp->cmd_per_lun = 1;
 #else /* MODULE */
-			shp->cmd_per_lun = 0;
+            shp->cmd_per_lun = 0;
 #endif /* MODULE */
+            /*
+             * Use the host 'select_queue_depths' function to determine
+             * the number of commands to queue per device.
+             */
+            shp->select_queue_depths = advansys_select_queue_depths;
 #endif /* version >= v1.3.89 */
 
-			/*
-			 * Set the maximum number of scatter-gather elements adapter
-			 * can handle.
-			 */
+            /*
+             * Set the maximum number of scatter-gather elements the
+             * adapter can handle.
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+                /*
+                 * Allow two commands with 'sg_tablesize' scatter-gather
+                 * elements to be executed simultaneously. This value is
+                 * the theoretical hardware limit. It may be decreased
+                 * below.
+                 */
+                shp->sg_tablesize =
+                    (((asc_dvc_varp->max_total_qng - 2) / 2) *
+                    ASC_SG_LIST_PER_Q) + 1;
+            } else {
+                shp->sg_tablesize = ADV_MAX_SG_LIST;
+            }
 
 #ifdef MODULE
-			/*
-			 * If the driver is compiled as a module, set a conservative
-			 * 'sg_tablesize' value to prevent memory allocation failures.
-			 * Memory allocation errors are more likely to occur at module
-			 * load time, then at driver initialization time.
-			 */
-			shp->sg_tablesize = 8;
-#else /* MODULE */
-			/*
-			 * Allow two commands with 'sg_tablesize' scatter-gather
-			 * elements to be executed simultaneously. This value is
-			 * the theoretical hardware limit. It may be decreased
-			 * below.
-			 */
-			shp->sg_tablesize =
-				(((asc_dvc_varp->max_total_qng - 2) / 2) *
-				ASC_SG_LIST_PER_Q) + 1;
+            /*
+             * If the driver is compiled as a module, set a limit on the
+             * 'sg_tablesize' value to prevent memory allocation failures.
+             * Memory allocation errors are more likely to occur at module
+             * load time, then at driver initialization time.
+             */
+            if (shp->sg_tablesize > 64) {
+                shp->sg_tablesize = 64;
+            }
 #endif /* MODULE */
 
-			/*
-			 * The value of 'sg_tablesize' can not exceed the SCSI
-			 * mid-level driver definition of SG_ALL. SG_ALL also
-			 * must not be exceeded, because it is used to define the
-			 * size of the scatter-gather table in 'struct asc_sg_head'.
-			 */
-			if (shp->sg_tablesize > SG_ALL) {
-				shp->sg_tablesize = SG_ALL;
-			}
-
-			ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
-				shp->sg_tablesize);
-
-			/* BIOS start address. */
-			shp->base = (char *) ((ulong) AscGetChipBiosAddress(
-												asc_dvc_varp->iop_base,
-												asc_dvc_varp->bus_type));
-
-			/*
-			 * Register Board Resources - I/O Port, DMA, IRQ
-			 */
-
-			/* Register I/O port range */
-			ASC_DBG(2, "advansys_detect: request_region()\n");
-			request_region(shp->io_port, shp->n_io_port, "advansys");
-
-			/* Register DMA channel for ISA bus. */
-			if ((asc_dvc_varp->bus_type & ASC_IS_ISA) == 0) {
-				shp->dma_channel = NO_ISA_DMA;
-			} else {
-				shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
-				if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) {
-					ASC_PRINT3(
+            /*
+             * The value of 'sg_tablesize' can not exceed the SCSI
+             * mid-level driver definition of SG_ALL. SG_ALL also
+             * must not be exceeded, because it is used to define the
+             * size of the scatter-gather table in 'struct asc_sg_head'.
+             */
+            if (shp->sg_tablesize > SG_ALL) {
+                shp->sg_tablesize = SG_ALL;
+            }
+
+            ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
+                shp->sg_tablesize);
+
+            /* BIOS start address. */
+            if (ASC_NARROW_BOARD(boardp)) {
+                shp->base = (char *) ((ulong) AscGetChipBiosAddress(
+                                                asc_dvc_varp->iop_base,
+                                                asc_dvc_varp->bus_type));
+            } else {
+                /*
+                 * Fill-in BIOS board variables. The Wide BIOS saves
+                 * information in LRAM that is used by the driver.
+                 */
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_SIGNATURE,
+                    boardp->bios_signature);
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_VERSION,
+                    boardp->bios_version);
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODESEG,
+                    boardp->bios_codeseg);
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN,
+                    boardp->bios_codelen);
+
+                ASC_DBG2(1,
+                    "advansys_detect: bios_signature %x, bios_version %x\n",
+                    boardp->bios_signature, boardp->bios_version);
+
+                ASC_DBG2(1,
+                    "advansys_detect: bios_codeseg %x, bios_codelen %x\n",
+                    boardp->bios_codeseg, boardp->bios_codelen);
+
+                /*
+                 * If the BIOS saved a valid signature, then fill in
+                 * the BIOS code segment base address.
+                 */
+                if (boardp->bios_signature == 0x55AA) {
+                    /*
+                     * Convert x86 realmode code segment to a linear
+                     * address by shifting left 4.
+                     */
+                    shp->base = (uchar *) (boardp->bios_codeseg << 4);
+                } else {
+                    shp->base = 0;
+                }
+            }
+
+            /*
+             * Register Board Resources - I/O Port, DMA, IRQ
+             */
+
+            /* Register I/O port range. */
+            ASC_DBG(2, "advansys_detect: request_region()\n");
+            request_region(shp->io_port, shp->n_io_port, "advansys");
+
+            /* Register DMA Channel for Narrow boards. */
+            shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
+            if (ASC_NARROW_BOARD(boardp)) {
+                /* Register DMA channel for ISA bus. */
+                if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+                    shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
+                    if ((ret =
+                         request_dma(shp->dma_channel, "advansys")) != 0) {
+                        ASC_PRINT3(
 "advansys_detect: board %d: request_dma() %d failed %d\n",
-						boardp->id, shp->dma_channel, ret);
-					release_region(shp->io_port, shp->n_io_port);
+                            boardp->id, shp->dma_channel, ret);
+                        release_region(shp->io_port, shp->n_io_port);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-					kfree(boardp->prtbuf);
+                        kfree(boardp->prtbuf);
 #endif /* version >= v1.3.0 */
-					scsi_unregister(shp);
-					asc_board_count--;
-					continue;
-				}
-				AscEnableIsaDma(shp->dma_channel);
-			}
+                        scsi_unregister(shp);
+                        asc_board_count--;
+                        continue;
+                    }
+                    AscEnableIsaDma(shp->dma_channel);
+                }
+            }
 
-			/* Register IRQ Number. */
-			ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
+            /* Register IRQ Number. */
+            ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-			if ((ret = request_irq(shp->irq, advansys_interrupt,
-							SA_INTERRUPT, "advansys")) != 0) {
+            if ((ret = request_irq(shp->irq, advansys_interrupt,
+                            SA_INTERRUPT, "advansys")) != 0)
 #else /* version >= v1.3.70 */
-			if ((ret = request_irq(shp->irq, advansys_interrupt,
-							SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
-							"advansys", boardp)) != 0) {
+            if ((ret = request_irq(shp->irq, advansys_interrupt,
+                            SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
+                            "advansys", boardp)) != 0)
 #endif /* version >= v1.3.70 */
-				ASC_PRINT2(
+            {
+                ASC_PRINT2(
 "advansys_detect: board %d: request_irq() failed %d\n",
-					boardp->id, ret);
-				release_region(shp->io_port, shp->n_io_port);
-				if (shp->dma_channel != NO_ISA_DMA) {
-					free_dma(shp->dma_channel);
-				}
+                    boardp->id, ret);
+                release_region(shp->io_port, shp->n_io_port);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+                iounmap(boardp->ioremap_addr);
+#endif /* version >= v1,3,0 */
+                if (shp->dma_channel != NO_ISA_DMA) {
+                    free_dma(shp->dma_channel);
+                }
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-				kfree(boardp->prtbuf);
+                kfree(boardp->prtbuf);
+#endif /* version >= v1.3.0 */
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+
+            /*
+             * Initialize board RISC chip and enable interrupts.
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+                ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
+                warn_code = AscInitAsc1000Driver(asc_dvc_varp);
+                err_code = asc_dvc_varp->err_code;
+
+                if (warn_code || err_code) {
+                    ASC_PRINT4(
+"AscInitAsc1000Driver: board %d: error: init_state %x, warn %x error %x\n",
+                        boardp->id, asc_dvc_varp->init_state,
+                        warn_code, err_code);
+                }
+            } else {
+                int             req_cnt;
+                adv_req_t       *reqp = NULL;
+                int             sg_cnt;
+                adv_sgblk_t     *sgp = NULL;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+                req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t);
+                sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t);
+                reqp = (adv_req_t *) &adv_req_buf[0];
+                sgp = (adv_sgblk_t *) &adv_sgblk_buf[0];
+#else /* version >= v1.3.0 */
+                /*
+                 * Allocate up to 'max_host_qng' request structures for
+                 * the Wide board.
+                 */
+                for (req_cnt = adv_dvc_varp->max_host_qng;
+                    req_cnt > 0; req_cnt--) {
+
+                    reqp = (adv_req_t *)
+                        kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+
+                    ASC_DBG3(1,
+                        "advansys_detect: reqp %x, req_cnt %d, bytes %d\n",
+                        (unsigned) reqp, req_cnt, sizeof(adv_req_t) * req_cnt);
+
+                    if (reqp != NULL) {
+                        break;
+                    }
+                }
+
+                /*
+                 * Allocate up to ADV_TOT_SG_LIST request structures for
+                 * the Wide board.
+                 */
+                for (sg_cnt = ADV_TOT_SG_LIST; sg_cnt > 0; sg_cnt--) {
+
+                    sgp = (adv_sgblk_t *)
+                        kmalloc(sizeof(adv_sgblk_t) * sg_cnt, GFP_ATOMIC);
+
+                    ASC_DBG3(1,
+                        "advansys_detect: sgp %x, sg_cnt %d, bytes %d\n",
+                        (unsigned) sgp, sg_cnt, sizeof(adv_sgblk_t) * sg_cnt);
+
+                    if (sgp != NULL) {
+                        break;
+                    }
+                }
 #endif /* version >= v1.3.0 */
-				scsi_unregister(shp);
-				asc_board_count--;
-				continue;
-			}
-
-			/*
-			 * Initialize board RISC chip and enable interrupts.
-			 */
-			ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
-			if (AscInitAsc1000Driver(asc_dvc_varp)) {
-				ASC_PRINT3(
-"AscInitAsc1000Driver: board %d: error: init_state %x, err_code %x\n",
-					boardp->id, asc_dvc_varp->init_state,
-					asc_dvc_varp->err_code);
-				release_region(shp->io_port, shp->n_io_port);
-				if (shp->dma_channel != NO_ISA_DMA) {
-					free_dma(shp->dma_channel);
-				}
+
+                /*
+                 * If no request structures or scatter-gather structures could
+                 * be allocated, then return an error. Otherwise continue with
+                 * initialization.
+                 */
+                if (reqp == NULL) {
+                    ASC_PRINT1(
+"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n",
+                        boardp->id);
+                    err_code = ADV_ERROR;
+                } else if (sgp == NULL) {
+                    kfree(reqp);
+                    ASC_PRINT1(
+"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n",
+                        boardp->id);
+                    err_code = ADV_ERROR;
+                } else {
+                    
+                    /*
+                     * Save original pointer for kfree() in case the
+                     * driver is built as a module and can be unloaded.
+                     */
+                    boardp->orig_reqp = reqp;
+
+                    /*
+                     * Point 'adv_reqp' to the request structures and
+                     * link them together.
+                     */
+                    req_cnt--;
+                    reqp[req_cnt].next_reqp = NULL;
+                    for (; req_cnt > 0; req_cnt--) {
+                        reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
+                    }
+                    boardp->adv_reqp = &reqp[0];
+
+                    /*
+                     * Save original pointer for kfree() in case the
+                     * driver is built as a module and can be unloaded.
+                     */
+                    boardp->orig_sgblkp = sgp;
+
+                    /*
+                     * Point 'adv_sgblkp' to the request structures and
+                     * link them together.
+                     */
+                    sg_cnt--;
+                    sgp[sg_cnt].next_sgblkp = NULL;
+                    for (; sg_cnt > 0; sg_cnt--) {
+                        sgp[sg_cnt - 1].next_sgblkp = &sgp[sg_cnt];
+                    }
+                    boardp->adv_sgblkp = &sgp[0];
+
+                    ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n");
+                    warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+                    err_code = adv_dvc_varp->err_code;
+
+                    if (warn_code || err_code) {
+                        ASC_PRINT3(
+"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n",
+                            boardp->id, warn_code, adv_dvc_varp->err_code);
+                    }
+                }
+            }
+
+            if (err_code != 0) {
+                release_region(shp->io_port, shp->n_io_port);
+                if (ASC_WIDE_BOARD(boardp)) {
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+                    iounmap(boardp->ioremap_addr);
+#endif /* version >= v1,3,0 */
+                    if (boardp->orig_reqp) {
+                        kfree(boardp->orig_reqp);
+                        boardp->orig_reqp = boardp->adv_reqp = NULL;
+                    }
+                    if (boardp->orig_sgblkp) {
+                        kfree(boardp->orig_sgblkp);
+                        boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
+                    }
+                }
+                if (shp->dma_channel != NO_ISA_DMA) {
+                    free_dma(shp->dma_channel);
+                }
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-				kfree(boardp->prtbuf);
+                kfree(boardp->prtbuf);
 #endif /* version >= v1.3.0 */
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-				free_irq(shp->irq);
+                free_irq(shp->irq);
 #else /* version >= v1.3.70 */
-				free_irq(shp->irq, boardp);
+                free_irq(shp->irq, boardp);
 #endif /* version >= v1.3.70 */
-				scsi_unregister(shp);
-				asc_board_count--;
-				continue;
-			}
-			ASC_DBG_PRT_SCSI_HOST(2, shp);
-		}
-	}
-	ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
-	return asc_board_count;
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+            ASC_DBG_PRT_SCSI_HOST(2, shp);
+        }
+    }
+    ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
+    return asc_board_count;
 }
 
 /*
@@ -3515,27 +5075,40 @@
 int
 advansys_release(struct Scsi_Host *shp)
 {
-	asc_board_t	*boardp;
+    asc_board_t    *boardp;
 
-	ASC_DBG(1, "advansys_release: begin\n");
-	boardp = ASC_BOARDP(shp);
+    ASC_DBG(1, "advansys_release: begin\n");
+    boardp = ASC_BOARDP(shp);
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-	free_irq(shp->irq);
+    free_irq(shp->irq);
 #else /* version >= v1.3.70 */
-	free_irq(shp->irq, boardp);
+    free_irq(shp->irq, boardp);
 #endif /* version >= v1.3.70 */
-	if (shp->dma_channel != NO_ISA_DMA) {
-		ASC_DBG(1, "advansys_release: free_dma()\n");
-		free_dma(shp->dma_channel);
-	}
-	release_region(shp->io_port, shp->n_io_port);
+    if (shp->dma_channel != NO_ISA_DMA) {
+        ASC_DBG(1, "advansys_release: free_dma()\n");
+        free_dma(shp->dma_channel);
+    }
+    release_region(shp->io_port, shp->n_io_port);
+    if (ASC_WIDE_BOARD(boardp)) {
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+        iounmap(boardp->ioremap_addr);
+#endif /* version >= v1,3,0 */
+        if (boardp->orig_reqp) {
+            kfree(boardp->orig_reqp);
+            boardp->orig_reqp = boardp->adv_reqp = NULL;
+        }
+        if (boardp->orig_sgblkp) {
+            kfree(boardp->orig_sgblkp);
+            boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
+        }
+    }
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-	ASC_ASSERT(boardp->prtbuf != NULL);
-	kfree(boardp->prtbuf);
+    ASC_ASSERT(boardp->prtbuf != NULL);
+    kfree(boardp->prtbuf);
 #endif /* version >= v1.3.0 */
-	scsi_unregister(shp);
-	ASC_DBG(1, "advansys_release: end\n");
-	return 0;
+    scsi_unregister(shp);
+    ASC_DBG(1, "advansys_release: end\n");
+    return 0;
 }
 
 /*
@@ -3550,65 +5123,93 @@
 const char *
 advansys_info(struct Scsi_Host *shp)
 {
-	static char 	info[ASC_INFO_SIZE];
-	asc_board_t		*boardp;
-	ASC_DVC_VAR		*asc_dvc_varp;
-	char			*busname;
-
-	boardp = ASC_BOARDP(shp);
-	asc_dvc_varp = &boardp->asc_dvc_var;
-	ASC_DBG(1, "advansys_info: begin\n");
-	if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
-		if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
-			busname = "ISA PnP";
-		} else {
-			busname = "ISA";
-		}
-		sprintf(info,
-			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u, DMA %u",
-			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
-			(unsigned) shp->base, shp->io_port,
-			shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
-	} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-		if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
-			== ASC_IS_PCI_ULTRA) {
-			busname = "PCI Ultra";
-		} else {
-			busname = "PCI";
-		}
-		sprintf(info,
-			"AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u",
-			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
-			shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq);
-	} else {
-		if (asc_dvc_varp->bus_type & ASC_IS_VL) {
-			busname = "VL";
-		} else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
-			busname = "EISA";
-		} else {
-			busname = "?";
-			ASC_PRINT2(
-"advansys_info: board %d: unknown bus type %d\n",
-				boardp->id, asc_dvc_varp->bus_type);
-		}
-		sprintf(info,
-			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
-			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
-			(unsigned) shp->base, shp->io_port,
-			shp->io_port + (shp->n_io_port - 1), shp->irq);
-	}
-#ifdef ADVANSYS_DEBUG
-	ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
-#endif /* ADVANSYS_DEBUG */
-	ASC_DBG(1, "advansys_info: end\n");
-	return info;
+    static char     info[ASC_INFO_SIZE];
+    asc_board_t     *boardp;
+    ASC_DVC_VAR     *asc_dvc_varp;
+    ADV_DVC_VAR     *adv_dvc_varp;
+    char            *busname;
+
+    boardp = ASC_BOARDP(shp);
+    if (ASC_NARROW_BOARD(boardp)) {
+        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+        ASC_DBG(1, "advansys_info: begin\n");
+        if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+            if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
+                busname = "ISA PnP";
+            } else {
+                busname = "ISA";
+            }
+            sprintf(info,
+"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u, DMA %u",
+                ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
+                (unsigned) shp->base,
+                shp->io_port, shp->n_io_port - 1,
+                shp->irq, shp->dma_channel);
+        } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+            if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+                == ASC_IS_PCI_ULTRA) {
+                busname = "PCI Ultra";
+            } else {
+                busname = "PCI";
+            }
+            sprintf(info,
+                "AdvanSys SCSI %s: %s %u CDB: IO %X/%X, IRQ %u",
+                ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
+                shp->io_port, shp->n_io_port - 1, shp->irq);
+        } else {
+            if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+                busname = "VL";
+            } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+                busname = "EISA";
+            } else {
+                busname = "?";
+                ASC_PRINT2(
+    "advansys_info: board %d: unknown bus type %d\n",
+                    boardp->id, asc_dvc_varp->bus_type);
+            }
+            sprintf(info,
+                "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u",
+                ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
+                (unsigned) shp->base, shp->io_port - 1,
+                shp->n_io_port, shp->irq);
+        }
+    } else {
+        /*
+         * Wide Adapter Information
+         *
+         * Memory-mapped I/O is used instead of I/O space to access
+         * the adapter, but display the I/O Port range. The Memory
+         * I/O address is displayed through the driver /proc file.
+         */
+        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+        if (boardp->bios_signature == 0x55AA) {
+            sprintf(info,
+"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u",
+                ASC_VERSION,
+                boardp->bios_codeseg << 4,
+                boardp->bios_codelen > 0 ?
+                (boardp->bios_codelen << 9) - 1 : 0,
+                (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1,
+                shp->irq);
+        } else {
+            sprintf(info,
+"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u",
+                ASC_VERSION,
+                (unsigned) boardp->ioport,
+                (ADV_CONDOR_IOLEN - 1),
+                shp->irq);
+        }
+    }
+    ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
+    ASC_DBG(1, "advansys_info: end\n");
+    return info;
 }
 
 /*
- * advansys_command()
+ * advansys_command() - polled I/O entrypoint.
  *
- * Polled-I/O. Apparently host drivers shouldn't return until
- * command is finished.
+ * Apparently host drivers shouldn't return until the command
+ * is finished.
  *
  * Note: This is an old interface that is no longer used by the SCSI
  * mid-level driver. The new interface, advansys_queuecommand(),
@@ -3617,23 +5218,19 @@
 int
 advansys_command(Scsi_Cmnd *scp)
 {
-	ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp);
-	ASC_STATS(scp->host, command);
-	scp->SCp.Status = 0; /* Set to a known state */
-	advansys_queuecommand(scp, advansys_command_done);
-	/*
-	 * XXX - Can host drivers block here instead of spinning on
-	 * command status?
-	 */
-	while (scp->SCp.Status == 0) {
-		continue;
-	}
-	ASC_DBG1(1, "advansys_command: result %x\n", scp->result);
-	return scp->result;
+    ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp);
+    ASC_STATS(scp->host, command);
+    scp->SCp.Status = 0; /* Set to a known state */
+    advansys_queuecommand(scp, advansys_command_done);
+    while (scp->SCp.Status == 0) {
+        continue;
+    }
+    ASC_DBG1(1, "advansys_command: result %x\n", scp->result);
+    return scp->result;
 }
 
 /*
- * advansys_queuecommand()
+ * advansys_queuecommand() - interrupt-driven I/O entrypoint.
  *
  * This function always returns 0. Command return status is saved
  * in the 'scp' result field.
@@ -3641,89 +5238,89 @@
 int
 advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
 {
-	struct Scsi_Host	*shp;
-	asc_board_t			*boardp;
-	int					flags;
-	Scsi_Cmnd			*done_scp;
-
-	shp = scp->host;
-	boardp = ASC_BOARDP(shp);
-	ASC_STATS(shp, queuecommand);
-
-	/*
-	 * Disable interrupts to preserve request ordering and provide
-	 * mutually exclusive access to global structures used to initiate
-	 * a request.
-	 */
-	save_flags(flags);
-	cli();
-
-	/*
-	 * Block new commands while handling a reset or abort request.
-	 */
-	if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
-		if (boardp->flags & ASC_HOST_IN_RESET) {
-			ASC_DBG1(1,
-				"advansys_queuecommand: scp %x blocked for reset request\n",
-				(unsigned) scp);
-			scp->result = HOST_BYTE(DID_RESET);
-		} else {
-			ASC_DBG1(1,
-				"advansys_queuecommand: scp %x blocked for abort request\n",
-				(unsigned) scp);
-			scp->result = HOST_BYTE(DID_ABORT);
-		}
-
-		/*
-		 * Add blocked requests to the board's 'done' queue. The queued
-		 * requests will be completed at the end of the abort or reset
-		 * handling.
-		 */
-		asc_enqueue(&boardp->done, scp, ASC_BACK);
-		restore_flags(flags);
-		return 0;
-	}
-
-	/*
-	 * Attempt to execute any waiting commands for the board.
-	 */
-	if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-		ASC_DBG(1,
-			"advansys_queuecommand: before asc_execute_queue() waiting\n");
-		asc_execute_queue(&boardp->waiting);
-	}
-
-	/*
-	 * Save the function pointer to Linux mid-level 'done' function
-	 * and attempt to execute the command.
-	 *
-	 * If ASC_ERROR is returned the request has been added to the
-	 * board's 'active' queue and will be completed by the interrupt
-	 * handler.
-	 *
-	 * If ASC_BUSY is returned add the request to the board's per
-	 * target waiting list.
-	 * 
-	 * If an error occurred, the request will have been placed on the
-	 * board's 'done' queue and must be completed before returning.
-	 */
-	scp->scsi_done = done;
-	switch (asc_execute_scsi_cmnd(scp)) {
-	case ASC_NOERROR:
-		break;
-	case ASC_BUSY:
-		asc_enqueue(&boardp->waiting, scp, ASC_BACK);
-		break;
-	case ASC_ERROR:
-	default:
-		done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
-		/* Interrupts could be enabled here. */
-		asc_scsi_done_list(done_scp);
-		break;
-	}
+    struct Scsi_Host    *shp;
+    asc_board_t         *boardp;
+    int                 flags;
+    Scsi_Cmnd           *done_scp;
+
+    shp = scp->host;
+    boardp = ASC_BOARDP(shp);
+    ASC_STATS(shp, queuecommand);
+
+    /*
+     * Disable interrupts to preserve request ordering and provide
+     * mutually exclusive access to global structures used to initiate
+     * a request.
+     */
+    save_flags(flags);
+    cli();
+
+    /*
+     * Block new commands while handling a reset or abort request.
+     */
+    if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+        if (boardp->flags & ASC_HOST_IN_RESET) {
+            ASC_DBG1(1,
+                "advansys_queuecommand: scp %x blocked for reset request\n",
+                (unsigned) scp);
+            scp->result = HOST_BYTE(DID_RESET);
+        } else {
+            ASC_DBG1(1,
+                "advansys_queuecommand: scp %x blocked for abort request\n",
+                (unsigned) scp);
+            scp->result = HOST_BYTE(DID_ABORT);
+        }
+
+        /*
+         * Add blocked requests to the board's 'done' queue. The queued
+         * requests will be completed at the end of the abort or reset
+         * handling.
+         */
+        asc_enqueue(&boardp->done, scp, ASC_BACK);
+        restore_flags(flags);
+        return 0;
+    }
+
+    /*
+     * Attempt to execute any waiting commands for the board.
+     */
+    if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+        ASC_DBG(1,
+            "advansys_queuecommand: before asc_execute_queue() waiting\n");
+        asc_execute_queue(&boardp->waiting);
+    }
 
-	restore_flags(flags);
-	return 0;
+    /*
+     * Save the function pointer to Linux mid-level 'done' function
+     * and attempt to execute the command.
+     *
+     * If ASC_ERROR is returned the request has been added to the
+     * board's 'active' queue and will be completed by the interrupt
+     * handler.
+     *
+     * If ASC_BUSY is returned add the request to the board's per
+     * target waiting list.
+     * 
+     * If an error occurred, the request will have been placed on the
+     * board's 'done' queue and must be completed before returning.
+     */
+    scp->scsi_done = done;
+    switch (asc_execute_scsi_cmnd(scp)) {
+    case ASC_NOERROR:
+        break;
+    case ASC_BUSY:
+        asc_enqueue(&boardp->waiting, scp, ASC_BACK);
+        break;
+    case ASC_ERROR:
+    default:
+        done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
+        /* Interrupts could be enabled here. */
+        asc_scsi_done_list(done_scp);
+        break;
+    }
+
+    restore_flags(flags);
+    return 0;
 }
 
 /*
@@ -3734,193 +5331,231 @@
 int
 advansys_abort(Scsi_Cmnd *scp)
 {
-	struct Scsi_Host	*shp;
-	asc_board_t			*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	int					flags;
-	int					do_scsi_done;
-	int					scp_found;
-	Scsi_Cmnd			*done_scp = NULL;
-	int					ret;
-
-	/* Save current flags and disable interrupts. */
-	save_flags(flags);
-	cli();
+    struct Scsi_Host    *shp;
+    asc_board_t         *boardp;
+    ASC_DVC_VAR         *asc_dvc_varp;
+    ADV_DVC_VAR         *adv_dvc_varp;
+    int                 flags;
+    int                 do_scsi_done;
+    int                 scp_found;
+    Scsi_Cmnd           *done_scp = NULL;
+    int                 ret;
+
+    /* Save current flags and disable interrupts. */
+    save_flags(flags);
+    cli();
 
-	ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
+    ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
 
 #ifdef ADVANSYS_STATS
-	if (scp->host != NULL) {
-		ASC_STATS(scp->host, abort);
-	}	
+    if (scp->host != NULL) {
+        ASC_STATS(scp->host, abort);
+    }    
 #endif /* ADVANSYS_STATS */
 
-#ifdef ADVVANSYS_DEBUG
-	do_scsi_done = ASC_ERROR;
-	scp_found = ASC_ERROR;
-	ret = ASC_ERROR;
-#endif /* ADVANSYS_DEBUG */
+#ifdef ADVANSYS_ASSERT
+    do_scsi_done = ASC_ERROR;
+    scp_found = ASC_ERROR;
+    ret = ASC_ERROR;
+#endif /* ADVANSYS_ASSERT */
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-	if (scp->serial_number != scp->serial_number_at_timeout) {
-		ASC_PRINT1(
+    if (scp->serial_number != scp->serial_number_at_timeout) {
+        ASC_PRINT1(
 "advansys_abort: timeout serial number changed for request %x\n",
-			(unsigned) scp);
-		do_scsi_done = ASC_FALSE;
-		scp_found = ASC_FALSE;
-		ret = SCSI_ABORT_NOT_RUNNING;
-	} else
+            (unsigned) scp);
+        do_scsi_done = ASC_FALSE;
+        scp_found = ASC_FALSE;
+        ret = SCSI_ABORT_NOT_RUNNING;
+    } else
 #endif /* version >= v1.3.89 */
-	if ((shp = scp->host) == NULL) {
-		scp->result = HOST_BYTE(DID_ERROR);
-		do_scsi_done = ASC_TRUE;
-		scp_found = ASC_FALSE;
-		ret = SCSI_ABORT_ERROR;
-	} else if ((boardp = ASC_BOARDP(shp))->flags & 
-				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
-		ASC_PRINT2(
+    if ((shp = scp->host) == NULL) {
+        scp->result = HOST_BYTE(DID_ERROR);
+        do_scsi_done = ASC_TRUE;
+        scp_found = ASC_FALSE;
+        ret = SCSI_ABORT_ERROR;
+    } else if ((boardp = ASC_BOARDP(shp))->flags & 
+                (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+        ASC_PRINT2(
 "advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n",
-			boardp->id, boardp->flags);
-		do_scsi_done = ASC_TRUE;
-		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
-		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
-			scp_found = ASC_TRUE;
-		} else {
-			scp_found = ASC_FALSE;
-		}
-		scp->result = HOST_BYTE(DID_ERROR);
-		ret = SCSI_ABORT_ERROR;
-	} else {
-		/* Set abort flag to avoid nested reset or abort requests. */
-		boardp->flags |= ASC_HOST_IN_ABORT;
-
-		do_scsi_done = ASC_TRUE;
-		if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
-			/*
-		 	 * If asc_rmqueue() found the command on the waiting
-			 * queue, it had not been sent to the device. After
-			 * the queue is removed, no other handling is required.
-		 	 */
-			ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
-				(unsigned) scp);
-			scp_found = ASC_TRUE;
-			scp->result = HOST_BYTE(DID_ABORT);
-			ret = SCSI_ABORT_SUCCESS;
-		} else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
-			/*
-		 	 * If asc_isqueued() found the command on the active
-			 * queue, it has been sent to the device. The command
-			 * should be returned through the interrupt handler after
-			 * calling AscAbortSRB().
-		 	 */
-			asc_dvc_varp = &boardp->asc_dvc_var;
-			scp->result = HOST_BYTE(DID_ABORT);
-
-			sti(); /* Enable interrupts for AscAbortSRB(). */
-			ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
-				(unsigned) scp);
-			switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
-			case ASC_TRUE:
-				/* asc_isr_callback() will be called */
-				ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
-				ret = SCSI_ABORT_PENDING;
-				break;
-			case ASC_FALSE:
-				/* Request has apparently already completed. */
-				ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n");
-				ret = SCSI_ABORT_NOT_RUNNING;
-				break;
-			case ASC_ERROR:
-			default:
-				ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n");
-				ret = SCSI_ABORT_ERROR;
-				break;
-			}
-			cli();
-
-			/*
-			 * The request will either still be on the active queue
-			 * or have been added to the board's done queue.
-			 */
-			if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
-				scp->result = HOST_BYTE(DID_ABORT);
-				scp_found = ASC_TRUE;
-			} else {
-				scp_found = asc_rmqueue(&boardp->done, scp);
-				ASC_ASSERT(scp_found == ASC_TRUE);
-			}
-
-		} else {
-			/*
-			 * The command was not found on the active or waiting queues.
-			 */
-			do_scsi_done = ASC_TRUE;
-			scp_found = ASC_FALSE;
-			ret = SCSI_ABORT_NOT_RUNNING;
-		}
-
-		/* Clear abort flag. */
-		boardp->flags &= ~ASC_HOST_IN_ABORT;
-
-		/*
-		 * Because the ASC_HOST_IN_ABORT flag causes both
-		 * 'advansys_interrupt' and 'asc_isr_callback' to
-		 * queue requests to the board's 'done' queue and
-		 * prevents waiting commands from being executed,
-		 * these queued requests must be handled here.
-		 */
-		done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
-
-		/*
-		 * Start any waiting commands for the board.
-		 */
-		if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
-			asc_execute_queue(&boardp->waiting);
-		}
-	}
-
-	/* Interrupts could be enabled here. */
-
-	/*
-	 * Complete the request to be aborted, unless it has been
-	 * restarted as detected above, even if it was not found on
-	 * the device active or waiting queues.
-	 */
-	ASC_ASSERT(do_scsi_done != ASC_ERROR);
-	ASC_ASSERT(scp_found != ASC_ERROR);
-	if (do_scsi_done == ASC_TRUE) {
-		if (scp->scsi_done == NULL) {
-			ASC_PRINT1(
+            boardp->id, boardp->flags);
+        do_scsi_done = ASC_TRUE;
+        if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+            (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+            scp_found = ASC_TRUE;
+        } else {
+            scp_found = ASC_FALSE;
+        }
+        scp->result = HOST_BYTE(DID_ERROR);
+        ret = SCSI_ABORT_ERROR;
+    } else {
+        /* Set abort flag to avoid nested reset or abort requests. */
+        boardp->flags |= ASC_HOST_IN_ABORT;
+
+        do_scsi_done = ASC_TRUE;
+        if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
+            /*
+             * If asc_rmqueue() found the command on the waiting
+             * queue, it had not been sent to the device. After
+             * the queue is removed, no other handling is required.
+             */
+            ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
+                (unsigned) scp);
+            scp_found = ASC_TRUE;
+            scp->result = HOST_BYTE(DID_ABORT);
+            ret = SCSI_ABORT_SUCCESS;
+        } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
+            /*
+             * If asc_isqueued() found the command on the active
+             * queue, it has been sent to the device. The command
+             * will be returned through the interrupt handler after
+             * it has been aborted.
+             */
+
+            if (ASC_NARROW_BOARD(boardp)) {
+                /*
+                 * Narrow Board
+                 */
+                asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+                scp->result = HOST_BYTE(DID_ABORT);
+
+                sti(); /* Enable interrupts for AscAbortSRB(). */
+                ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
+                    (unsigned) scp);
+                switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+                case ASC_TRUE:
+                    /* asc_isr_callback() will be called */
+                    ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
+                    ret = SCSI_ABORT_PENDING;
+                    break;
+                case ASC_FALSE:
+                    /* Request has apparently already completed. */
+                    ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n");
+                    ret = SCSI_ABORT_NOT_RUNNING;
+                    break;
+                case ASC_ERROR:
+                default:
+                    ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n");
+                    ret = SCSI_ABORT_ERROR;
+                    break;
+                }
+                cli();
+            } else {
+                /*
+                 * Wide Board
+                 */
+                adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+                scp->result = HOST_BYTE(DID_ABORT);
+
+                ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n",
+                    (unsigned) scp);
+                switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) {
+                case ASC_TRUE:
+                    /* asc_isr_callback() will be called */
+                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n");
+                    ret = SCSI_ABORT_PENDING;
+                    break;
+                case ASC_FALSE:
+                    /* Request has apparently already completed. */
+                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n");
+                    ret = SCSI_ABORT_NOT_RUNNING;
+                    break;
+                case ASC_ERROR:
+                default:
+                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n");
+                    ret = SCSI_ABORT_ERROR;
+                    break;
+                }
+                /*
+                 * Ensure all requests completed by the microcode have
+                 * been processed by calling AdvISR().
+                 */
+                (void) AdvISR(adv_dvc_varp);
+            }
+
+            /*
+             * The request will either still be on the active queue
+             * or have been added to the board's done queue.
+             */
+            if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
+                scp->result = HOST_BYTE(DID_ABORT);
+                scp_found = ASC_TRUE;
+            } else {
+                scp_found = asc_rmqueue(&boardp->done, scp);
+                ASC_ASSERT(scp_found == ASC_TRUE);
+            }
+
+        } else {
+            /*
+             * The command was not found on the active or waiting queues.
+             */
+            do_scsi_done = ASC_TRUE;
+            scp_found = ASC_FALSE;
+            ret = SCSI_ABORT_NOT_RUNNING;
+        }
+
+        /* Clear abort flag. */
+        boardp->flags &= ~ASC_HOST_IN_ABORT;
+
+        /*
+         * Because the ASC_HOST_IN_ABORT flag causes both
+         * 'advansys_interrupt' and 'asc_isr_callback' to
+         * queue requests to the board's 'done' queue and
+         * prevents waiting commands from being executed,
+         * these queued requests must be handled here.
+         */
+        done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
+
+        /*
+         * Start any waiting commands for the board.
+         */
+        if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+            ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+            asc_execute_queue(&boardp->waiting);
+        }
+    }
+
+    /* Interrupts could be enabled here. */
+
+    /*
+     * Complete the request to be aborted, unless it has been
+     * restarted as detected above, even if it was not found on
+     * the device active or waiting queues.
+     */
+    ASC_ASSERT(do_scsi_done != ASC_ERROR);
+    ASC_ASSERT(scp_found != ASC_ERROR);
+    if (do_scsi_done == ASC_TRUE) {
+        if (scp->scsi_done == NULL) {
+            ASC_PRINT1(
 "advansys_abort: aborted request scsi_done() is NULL, %x\n",
-				(unsigned) scp);
-		} else {
-			if (scp_found == ASC_FALSE) {
-				ASC_PRINT1(
+                (unsigned) scp);
+        } else {
+            if (scp_found == ASC_FALSE) {
+                ASC_PRINT1(
 "advansys_abort: abort request not active or waiting, completing anyway %x\n",
-					(unsigned) scp);
-			}
-			ASC_STATS(scp->host, done);
-			scp->scsi_done(scp);
-		}
-	}
-
-	/*
-	 * It is possible for the request done function to re-enable
-	 * interrupts without confusing the driver. But here interrupts
-	 * aren't enabled until all requests have been completed.
-	 */
-	if (done_scp != NULL) {
-		asc_scsi_done_list(done_scp);
-	}
+                    (unsigned) scp);
+            }
+            ASC_STATS(scp->host, done);
+            scp->scsi_done(scp);
+        }
+    }
+
+    /*
+     * It is possible for the request done function to re-enable
+     * interrupts without confusing the driver. But here interrupts
+     * aren't enabled until all requests have been completed.
+     */
+    if (done_scp != NULL) {
+        asc_scsi_done_list(done_scp);
+    }
 
-	ASC_DBG1(1, "advansys_abort: ret %d\n", ret);
+    ASC_DBG1(1, "advansys_abort: ret %d\n", ret);
 
-	/* Re-enable interrupts, if they were enabled on entry. */
-	restore_flags(flags);
+    /* Re-enable interrupts, if they were enabled on entry. */
+    restore_flags(flags);
 
-	ASC_ASSERT(ret != ASC_ERROR);
-	return ret;
+    ASC_ASSERT(ret != ASC_ERROR);
+    return ret;
 }
 
 /*
@@ -3935,304 +5570,388 @@
 advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
 #endif /* version >= v1.3.89 */
 {
-	struct Scsi_Host	*shp;
-	asc_board_t			*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	int					flags;
-	Scsi_Cmnd			*done_scp = NULL, *last_scp = NULL;
-	Scsi_Cmnd			*tscp, *new_last_scp;
-	int					do_scsi_done;
-	int					scp_found;
-	int					status;
-	int					target;
-	int					ret;
-
-	/* Save current flags and disable interrupts. */
-	save_flags(flags);
-	cli();
+    struct Scsi_Host     *shp;
+    asc_board_t          *boardp;
+    ASC_DVC_VAR          *asc_dvc_varp;
+    ADV_DVC_VAR          *adv_dvc_varp;
+    int                  flags;
+    Scsi_Cmnd            *done_scp = NULL, *last_scp = NULL;
+    Scsi_Cmnd            *tscp, *new_last_scp;
+    int                  do_scsi_done;
+    int                  scp_found;
+    int                  status;
+    int                  target;
+    int                  ret;
+    int                  device_reset = ASC_FALSE;
+
+    /* Save current flags and disable interrupts. */
+    save_flags(flags);
+    cli();
 
-	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
+    ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
 
 #ifdef ADVANSYS_STATS
-	if (scp->host != NULL) {
-		ASC_STATS(scp->host, reset);
-	}	
+    if (scp->host != NULL) {
+        ASC_STATS(scp->host, reset);
+    }    
 #endif /* ADVANSYS_STATS */
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-	if (scp->serial_number != scp->serial_number_at_timeout) {
-		ASC_PRINT1(
+    if ((reset_flags & SCSI_RESET_ASYNCHRONOUS) &&
+        (scp->serial_number != scp->serial_number_at_timeout)) {
+        ASC_PRINT1(
 "advansys_reset: timeout serial number changed for request %x\n",
-			(unsigned) scp);
-		do_scsi_done = ASC_FALSE;
-		scp_found = ASC_FALSE;
-		ret = SCSI_RESET_NOT_RUNNING;
-	} else
+            (unsigned) scp);
+        do_scsi_done = ASC_FALSE;
+        scp_found = ASC_FALSE;
+        ret = SCSI_RESET_NOT_RUNNING;
+    } else
 #endif /* version >= v1.3.89 */
-	if ((shp = scp->host) == NULL) {
-		scp->result = HOST_BYTE(DID_ERROR);
-		do_scsi_done = ASC_TRUE;
-		scp_found = ASC_FALSE;
-		ret = SCSI_RESET_ERROR;
-	} else if ((boardp = ASC_BOARDP(shp))->flags & 
-				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
-		ASC_PRINT2(
+    if ((shp = scp->host) == NULL) {
+        scp->result = HOST_BYTE(DID_ERROR);
+        do_scsi_done = ASC_TRUE;
+        scp_found = ASC_FALSE;
+        ret = SCSI_RESET_ERROR;
+    } else if ((boardp = ASC_BOARDP(shp))->flags & 
+                (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+        ASC_PRINT2(
 "advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n",
-			boardp->id, boardp->flags);
-		do_scsi_done = ASC_TRUE;
-		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
-		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
-			scp_found = ASC_TRUE;
-		} else {
-			scp_found = ASC_FALSE;
-		}
-		scp->result = HOST_BYTE(DID_ERROR);
-		ret = SCSI_RESET_ERROR;
-	} else if (jiffies >= boardp->last_reset &&
-			   jiffies < (boardp->last_reset + (10 * HZ))) {
-		/*
-		 * Don't allow a reset to be attempted within 10 seconds
-		 * of the last reset.
-		 *
-		 * If 'jiffies' wrapping occurs, the reset request will go
-		 * through, because a wrapped 'jiffies' would not pass the
-		 * test above.
-		 */
-		ASC_DBG(1,
-			"advansys_reset: reset within 10 sec of last reset ignored\n");
-		do_scsi_done = ASC_TRUE;
-		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
-		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
-			scp_found = ASC_TRUE;
-		} else {
-			scp_found = ASC_FALSE;
-		}
-		scp->result = HOST_BYTE(DID_ERROR);
-		ret = SCSI_RESET_ERROR;
-	} else {
-		int device_reset = ASC_FALSE;
-
-		do_scsi_done = ASC_TRUE;
-
-		/* Set reset flag to avoid nested reset or abort requests. */
-		boardp->flags |= ASC_HOST_IN_RESET;
-
-		/*
-	 	 * If the request is on the target waiting or active queue
-		 * or the board done queue, then remove it and note that it
-		 * was found.
-		 */
-		if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
-			ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
-			scp_found = ASC_TRUE;
-		} else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
-			ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
-			scp_found = ASC_TRUE;
-		} else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) {
-			scp_found = ASC_TRUE;
-		} else {
-			scp_found = ASC_FALSE;
-		}
-
-		/*
-		 * If the suggest reset bus flags are set, reset the bus.
-		 * Otherwise only reset the device.
-		 */
-		asc_dvc_varp = &boardp->asc_dvc_var;
+            boardp->id, boardp->flags);
+        do_scsi_done = ASC_TRUE;
+        if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+            (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+            scp_found = ASC_TRUE;
+        } else {
+            scp_found = ASC_FALSE;
+        }
+        scp->result = HOST_BYTE(DID_ERROR);
+        ret = SCSI_RESET_ERROR;
+    } else if (jiffies >= boardp->last_reset &&
+               jiffies < (boardp->last_reset + (10 * HZ))) {
+        /*
+         * Don't allow a reset to be attempted within 10 seconds
+         * of the last reset.
+         *
+         * If 'jiffies' wrapping occurs, the reset request will go
+         * through, because a wrapped 'jiffies' would not pass the
+         * test above.
+         */
+        ASC_DBG(1,
+            "advansys_reset: reset within 10 sec of last reset ignored\n");
+        do_scsi_done = ASC_TRUE;
+        if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+            (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+            scp_found = ASC_TRUE;
+        } else {
+            scp_found = ASC_FALSE;
+        }
+        scp->result = HOST_BYTE(DID_ERROR);
+        ret = SCSI_RESET_ERROR;
+    } else {
+        do_scsi_done = ASC_TRUE;
+
+        /* Set reset flag to avoid nested reset or abort requests. */
+        boardp->flags |= ASC_HOST_IN_RESET;
+
+        /*
+          * If the request is on the target waiting or active queue
+         * or the board done queue, then remove it and note that it
+         * was found.
+         */
+        if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
+            ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
+            scp_found = ASC_TRUE;
+        } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
+            ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
+            scp_found = ASC_TRUE;
+        } else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) {
+            scp_found = ASC_TRUE;
+        } else {
+            scp_found = ASC_FALSE;
+        }
+
+
+        if (ASC_NARROW_BOARD(boardp)) {
+            /*
+             * Narrow Board
+             *
+             * If the suggest reset bus flags are set, then reset the bus.
+             * Otherwise only reset the device.
+             */
+            asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-		if (reset_flags &
-			(SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
+            if (reset_flags &
+                (SCSI_RESET_SUGGEST_BUS_RESET |
+                 SCSI_RESET_SUGGEST_HOST_RESET)) {
 #endif /* version >= v1.3.89 */
 
-			/*
-			 * Reset the target's SCSI bus.
-			 */
-			ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
-			sti();	/* Enable interrupts for AscResetSB(). */
-			status = AscResetSB(asc_dvc_varp);
-			cli();
-			switch (status) {
-			case ASC_TRUE:
-				ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
-				ret = SCSI_RESET_SUCCESS;
-				break;
-			case ASC_ERROR:
-			default:
-				ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
-				ret = SCSI_RESET_ERROR;
-				break;
-			}
+                /*
+                 * Reset the target's SCSI bus.
+                 */
+                ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
+                sti();    /* Enable interrupts for AscResetSB(). */
+                status = AscResetSB(asc_dvc_varp);
+                cli();
+                switch (status) {
+                case ASC_TRUE:
+                    ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
+                    ret = SCSI_RESET_SUCCESS;
+                    break;
+                case ASC_ERROR:
+                default:
+                    ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
+                    ret = SCSI_RESET_ERROR;
+                    break;
+                }
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-		} else {
-			/*
-			 * Reset the specified device. If the device reset fails,
-			 * then reset the SCSI bus.
-			 */
-
-			ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n",
-				scp->target);
-			sti();	/* Enable interrupts for AscResetDevice(). */
-			status = AscResetDevice(asc_dvc_varp, scp->target);
-			cli();
-
-			/*
-			 * If the device has been reset, try to initialize it.
-			 */
-			if (status == ASC_TRUE) {
-				status = asc_init_dev(asc_dvc_varp, scp);
-			}
-
-			switch (status) {
-			case ASC_TRUE:
-				ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
-				device_reset = ASC_TRUE;
-				ret = SCSI_RESET_SUCCESS;
-				break;
-			case ASC_ERROR:
-			default:
-				ASC_DBG(1,
+            } else {
+                /*
+                 * Reset the specified device. If the device reset fails,
+                 * then reset the SCSI bus.
+                 */
+
+                ASC_DBG1(1,
+                    "advansys_reset: before AscResetDevice(), target %d\n",
+                    scp->target);
+                sti();    /* Enable interrupts for AscResetDevice(). */
+                status = AscResetDevice(asc_dvc_varp, scp->target);
+                cli();
+
+                /*
+                 * If the device has been reset, try to initialize it.
+                 */
+                if (status == ASC_TRUE) {
+                    status = asc_init_dev(asc_dvc_varp, scp);
+                }
+
+                switch (status) {
+                case ASC_TRUE:
+                    ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
+                    device_reset = ASC_TRUE;
+                    ret = SCSI_RESET_SUCCESS;
+                    break;
+                case ASC_ERROR:
+                default:
+                    ASC_DBG(1,
 "advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
-				sti();	/* Enable interrupts for AscResetSB(). */
-				status = AscResetSB(asc_dvc_varp);
-				cli();
-				switch (status) {
-				case ASC_TRUE:
-					ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
-					ret = SCSI_RESET_SUCCESS;
-					break;
-				case ASC_ERROR:
-				default:
-					ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
-					ret = SCSI_RESET_ERROR;
-					break;
-				}
-				break;
-			}
-		}
+                    sti();    /* Enable interrupts for AscResetSB(). */
+                    status = AscResetSB(asc_dvc_varp);
+                    cli();
+                    switch (status) {
+                    case ASC_TRUE:
+                        ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+                        ret = SCSI_RESET_SUCCESS;
+                        break;
+                    case ASC_ERROR:
+                    default:
+                        ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+                        ret = SCSI_RESET_ERROR;
+                        break;
+                    }
+                    break;
+                }
+            }
+#endif /* version >= v1.3.89 */
+        } else {
+            /*
+             * Wide Board
+             *
+             * If the suggest reset bus flags are set, then reset the bus.
+             * Otherwise only reset the device.
+             */
+            adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+            if (reset_flags &
+                (SCSI_RESET_SUGGEST_BUS_RESET |
+                 SCSI_RESET_SUGGEST_HOST_RESET)) {
+#endif /* version >= v1.3.89 */
+
+                /*
+                 * Reset the target's SCSI bus.
+                 */
+                ASC_DBG(1, "advansys_reset: before AdvResetSB()\n");
+                switch (AdvResetSB(adv_dvc_varp)) {
+                case ASC_TRUE:
+                    ASC_DBG(1, "advansys_reset: AdvResetSB() success\n");
+                    ret = SCSI_RESET_SUCCESS;
+                    break;
+                case ASC_FALSE:
+                default:
+                    ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n");
+                    ret = SCSI_RESET_ERROR;
+                    break;
+                }
+                /*
+                 * Ensure all requests completed by the microcode have
+                 * been processed by calling AdvISR().
+                 */
+                (void) AdvISR(adv_dvc_varp);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+            } else {
+                /*
+                 * Reset the specified device. If the device reset fails,
+                 * then reset the SCSI bus.
+                 */
+
+                ASC_DBG1(1,
+                    "advansys_reset: before AdvResetDevice(), target %d\n",
+                    scp->target);
+                
+                switch (AdvResetDevice(adv_dvc_varp, scp->target)) {
+                case ASC_TRUE:
+                    ASC_DBG(1, "advansys_reset: AdvResetDevice() success\n");
+                    device_reset = ASC_TRUE;
+                    ret = SCSI_RESET_SUCCESS;
+                    break;
+                case ASC_FALSE:
+                default:
+                    ASC_DBG(1,
+"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n");
+                    
+                    switch (AdvResetSB(adv_dvc_varp)) {
+                    case ASC_TRUE:
+                        ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n");
+                        ret = SCSI_RESET_SUCCESS;
+                        break;
+                    case ASC_FALSE:
+                    default:
+                        ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n");
+                        ret = SCSI_RESET_ERROR;
+                        break;
+                    }
+                    break;
+                }
+                /*
+                 * Ensure all requests completed by the microcode have
+                 * been processed by calling AdvISR().
+                 */
+                (void) AdvISR(adv_dvc_varp);
+            }
 #endif /* version >= v1.3.89 */
+        }
+
+        /*
+         * Because the ASC_HOST_IN_RESET flag causes both
+         * 'advansys_interrupt' and 'asc_isr_callback' to
+         * queue requests to the board's 'done' queue and
+         * prevents waiting commands from being executed,
+         * these queued requests must be handled here.
+         */
+        done_scp = asc_dequeue_list(&boardp->done, &last_scp,
+                                    ASC_TID_ALL);
+
+        /*
+         * If a device reset was performed dequeue all waiting
+         * and active requests for the device and set the request
+         * status to DID_RESET.
+         *
+         * If a SCSI bus reset was performed dequeue all waiting
+         * and active requests for all devices and set the request
+         * status to DID_RESET.
+         */
+        if (device_reset == ASC_TRUE) {
+            target = scp->target;
+        } else {
+            target = ASC_TID_ALL;
+        }
+
+        /*
+         * Add active requests to 'done_scp' and set the request status
+         * to DID_RESET.
+         */
+        if (done_scp == NULL) {
+            done_scp = asc_dequeue_list(&boardp->active, &last_scp, target);
+            for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+                tscp->result = HOST_BYTE(DID_RESET);
+            }
+        } else {
+            ASC_ASSERT(last_scp != NULL);
+            REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active,
+                &new_last_scp, target);
+            if (new_last_scp != NULL) {
+                ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+                for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                    tscp->result = HOST_BYTE(DID_RESET);
+                }
+                last_scp = new_last_scp;
+            }
+        }
+
+        /*
+         * Add waiting requests to 'done_scp' and set the request status
+         * to DID_RESET.
+         */
+        if (done_scp == NULL) {
+            done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target);
+            for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+                tscp->result = HOST_BYTE(DID_RESET);
+            }
+        } else {
+            ASC_ASSERT(last_scp != NULL);
+            REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting,
+                &new_last_scp, target);
+            if (new_last_scp != NULL) {
+                ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+                for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                    tscp->result = HOST_BYTE(DID_RESET);
+                }
+                last_scp = new_last_scp;
+            }
+        }
+
+        /* Save the time of the most recently completed reset. */
+        boardp->last_reset = jiffies;
+
+        /* Clear reset flag. */
+        boardp->flags &= ~ASC_HOST_IN_RESET;
+
+        /*
+         * Start any waiting commands for the board.
+         */
+        if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+            ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+            asc_execute_queue(&boardp->waiting);
+        }
+        ret = SCSI_RESET_SUCCESS;
+    }
+
+    /* Interrupts could be enabled here. */
 
-		/*
-		 * Because the ASC_HOST_IN_RESET flag causes both
-		 * 'advansys_interrupt' and 'asc_isr_callback' to
-		 * queue requests to the board's 'done' queue and
-		 * prevents waiting commands from being executed,
-		 * these queued requests must be handled here.
-		 */
-		done_scp = asc_dequeue_list(&boardp->done, &last_scp,
-									ASC_TID_ALL);
-
-		/*
-		 * If a device reset was performed dequeue all waiting
-		 * and active requests for the device and set the request
-		 * status to DID_RESET.
-		 *
-		 * If a SCSI bus reset was performed dequeue all waiting
-		 * and active requests for all devices and set the request
-		 * status to DID_RESET.
-		 */
-		if (device_reset == ASC_TRUE) {
-			target = scp->target;
-		} else {
-			target = ASC_TID_ALL;
-		}
-
-		/*
-		 * Add active requests to 'done_scp' and set the request status
-		 * to DID_RESET.
-		 */
-		if (done_scp == NULL) {
-			done_scp = asc_dequeue_list(&boardp->active, &last_scp, target);
-			for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-				tscp->result = HOST_BYTE(DID_RESET);
-			}
-		} else {
-			ASC_ASSERT(last_scp != NULL);
-			REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active,
-				&new_last_scp, target);
-			if (new_last_scp != NULL) {
-				ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-				for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
-					tscp->result = HOST_BYTE(DID_RESET);
-				}
-				last_scp = new_last_scp;
-			}
-		}
-
-		/*
-		 * Add waiting requests to 'done_scp' and set the request status
-		 * to DID_RESET.
-		 */
-		if (done_scp == NULL) {
-			done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target);
-			for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-				tscp->result = HOST_BYTE(DID_RESET);
-			}
-		} else {
-			ASC_ASSERT(last_scp != NULL);
-			REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting,
-				&new_last_scp, target);
-			if (new_last_scp != NULL) {
-				ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-				for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
-					tscp->result = HOST_BYTE(DID_RESET);
-				}
-				last_scp = new_last_scp;
-			}
-		}
-
-		/* Save the time of the most recently completed reset. */
-		boardp->last_reset = jiffies;
-
-		/* Clear reset flag. */
-		boardp->flags &= ~ASC_HOST_IN_RESET;
-
-		/*
-		 * Start any waiting commands for the board.
-		 */
-		if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
-			asc_execute_queue(&boardp->waiting);
-		}
-		ret = SCSI_RESET_SUCCESS;
-	}
-
-	/* Interrupts could be enabled here. */
-
-	ASC_ASSERT(do_scsi_done != ASC_ERROR);
-	ASC_ASSERT(scp_found != ASC_ERROR);
-	if (do_scsi_done == ASC_TRUE) {
-		if (scp->scsi_done == NULL) {
-			ASC_PRINT1(
+    ASC_ASSERT(do_scsi_done != ASC_ERROR);
+    ASC_ASSERT(scp_found != ASC_ERROR);
+    if (do_scsi_done == ASC_TRUE) {
+        if (scp->scsi_done == NULL) {
+            ASC_PRINT1(
 "advansys_reset: reset request scsi_done() is NULL, %x\n",
-				(unsigned) scp);
-		} else {
-			if (scp_found == ASC_FALSE) {
-				ASC_PRINT1(
+                (unsigned) scp);
+        } else {
+            if (scp_found == ASC_FALSE) {
+                ASC_PRINT1(
 "advansys_reset: reset request not active or waiting, completing anyway %x\n",
-					(unsigned) scp);
-			}
-			ASC_STATS(scp->host, done);
-			scp->scsi_done(scp);
-		}
-	}
-
-	/*
-	 * It is possible for the request done function to re-enable
-	 * interrupts without confusing the driver. But here interrupts
-	 * aren't enabled until requests have been completed.
-	 */
-	if (done_scp != NULL) {
-		asc_scsi_done_list(done_scp);
-	}
+                    (unsigned) scp);
+            }
+            ASC_STATS(scp->host, done);
+            scp->scsi_done(scp);
+        }
+    }
+
+    /*
+     * It is possible for the request done function to re-enable
+     * interrupts without confusing the driver. But here interrupts
+     * aren't enabled until requests have been completed.
+     */
+    if (done_scp != NULL) {
+        asc_scsi_done_list(done_scp);
+    }
 
-	ASC_DBG1(1, "advansys_reset: ret %d", ret);
+    ASC_DBG1(1, "advansys_reset: ret %d", ret);
 
-	/* Re-enable interrupts, if they were enabled on entry. */
-	restore_flags(flags);
+    /* Re-enable interrupts, if they were enabled on entry. */
+    restore_flags(flags);
 
-	ASC_ASSERT(ret != ASC_ERROR);
-	return ret;
+    ASC_ASSERT(ret != ASC_ERROR);
+    return ret;
 }
 
 /*
@@ -4253,19 +5972,33 @@
 advansys_biosparam(Disk *dp, kdev_t dep, int ip[])
 #endif /* version >= v1.3.0 */
 {
-	ASC_DBG(1, "advansys_biosparam: begin\n");
-	ASC_STATS(dp->device->host, biosparam);
-	if ((ASC_BOARDP(dp->device->host)->asc_dvc_var.dvc_cntl &
-	     ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) {
-			ip[0] = 255;
-			ip[1] = 63;
-	} else {
-			ip[0] = 64;
-			ip[1] = 32;
-	}
-	ip[2] = dp->capacity / (ip[0] * ip[1]);
-	ASC_DBG(1, "advansys_biosparam: end\n");
-	return 0;
+    asc_board_t     *boardp;
+
+    ASC_DBG(1, "advansys_biosparam: begin\n");
+    ASC_STATS(dp->device->host, biosparam);
+    boardp = ASC_BOARDP(dp->device->host);
+    if (ASC_NARROW_BOARD(boardp)) {
+        if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+             ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) {
+                ip[0] = 255;
+                ip[1] = 63;
+        } else {
+                ip[0] = 64;
+                ip[1] = 32;
+        }
+    } else {
+        if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+             BIOS_CTRL_EXTENDED_XLAT) && dp->capacity > 0x200000) {
+                ip[0] = 255;
+                ip[1] = 63;
+        } else {
+                ip[0] = 64;
+                ip[1] = 32;
+        }
+    }
+    ip[2] = dp->capacity / (ip[0] * ip[1]);
+    ASC_DBG(1, "advansys_biosparam: end\n");
+    return 0;
 }
 
 /*
@@ -4282,65 +6015,67 @@
  * only affects searching for ISA and VL boards.
  *
  * If ADVANSYS_DEBUG is defined the driver debug level may
- * be set using the 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port.
+ * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port.
  *
  * Examples:
  * 1. Eliminate I/O port scanning:
- * 		boot: linux advansys=
+ *         boot: linux advansys=
  *       or
- * 		boot: linux advansys=0x0
+ *         boot: linux advansys=0x0
  * 2. Limit I/O port scanning to one I/O port:
- *		boot: linux advansys=0x110
+ *        boot: linux advansys=0x110
  * 3. Limit I/O port scanning to four I/O ports:
- *		boot: linux advansys=0x110,0x210,0x230,0x330
+ *        boot: linux advansys=0x110,0x210,0x230,0x330
  * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and
  *    set the driver debug level to 2.
- *		boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2
+ *        boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2
  *
  * ints[0] - number of arguments
  * ints[1] - first argument
  * ints[2] - second argument
  * ...
  */
+ASC_INITFUNC(
 void
 advansys_setup(char *str, int *ints)
+)
 {
-	int	i;
+    int    i;
 
-	if (asc_iopflag == ASC_TRUE) {
-		printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n");
-		return;
-	}
+    if (asc_iopflag == ASC_TRUE) {
+        printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n");
+        return;
+    }
 
-	asc_iopflag = ASC_TRUE;
+    asc_iopflag = ASC_TRUE;
 
-	if (ints[0] > ASC_NUM_BOARD_SUPPORTED) {
+    if (ints[0] > ASC_NUM_IOPORT_PROBE) {
 #ifdef ADVANSYS_DEBUG
-		if ((ints[0] == ASC_NUM_BOARD_SUPPORTED + 1) &&
-		    (ints[ASC_NUM_BOARD_SUPPORTED + 1] >> 4 == 0xdeb)) {
-			asc_dbglvl = ints[ASC_NUM_BOARD_SUPPORTED + 1] & 0xf;
-		} else {
+        if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) &&
+            (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) {
+            asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf;
+        } else {
 #endif /* ADVANSYS_DEBUG */
-			printk("AdvanSys SCSI: only %d I/O ports accepted\n",
-				ASC_NUM_BOARD_SUPPORTED);
+            printk("AdvanSys SCSI: only %d I/O ports accepted\n",
+                ASC_NUM_IOPORT_PROBE);
 #ifdef ADVANSYS_DEBUG
-		}
+        }
 #endif /* ADVANSYS_DEBUG */
-	}
+    }
 
 #ifdef ADVANSYS_DEBUG
-	ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]);
-	for (i = 1; i < ints[0]; i++) {
-		ASC_DBG2(1, " ints[%d] %x", i, ints[i]);
-	}
-	ASC_DBG(1, "\n");
+    ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]);
+    for (i = 1; i < ints[0]; i++) {
+        ASC_DBG2(1, " ints[%d] %x", i, ints[i]);
+    }
+    ASC_DBG(1, "\n");
 #endif /* ADVANSYS_DEBUG */
 
-	for (i = 1; i <= ints[0] && i <= ASC_NUM_BOARD_SUPPORTED; i++) {
-		asc_ioport[i-1] = ints[i];
-		ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n",
-			i - 1, asc_ioport[i-1]);
-	}
+    for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) {
+        asc_ioport[i-1] = ints[i];
+        ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n",
+            i - 1, asc_ioport[i-1]);
+    }
 }
 
 
@@ -4374,76 +6109,98 @@
 advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 #endif /* version >= v1.3.70 */
 {
-	int				flags;
-	int				i;
-	asc_board_t		*boardp;
-	Scsi_Cmnd		*done_scp = NULL, *last_scp = NULL;
-	Scsi_Cmnd		*new_last_scp;
-
-	/* Disable interrupts, if they aren't already disabled. */
-	save_flags(flags);
-	cli();
-
-	ASC_DBG(1, "advansys_interrupt: begin\n");
-	/*
-	 * Check for interrupts on all boards.
-	 * AscISR() will call asc_isr_callback().
-	 */
-	for (i = 0; i < asc_board_count; i++) {
-		ASC_STATS(asc_host[i], check_interrupt);
-		boardp = ASC_BOARDP(asc_host[i]);
-		while (AscIsIntPending(asc_host[i]->io_port)) {
-			ASC_STATS(asc_host[i], interrupt);
-			ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
-			AscISR(&boardp->asc_dvc_var);
-		}
-
-		/*
-		 * Start waiting requests and create a list of completed requests.
-		 * 
-		 * If a reset or abort request is being performed for the board,
-		 * the reset or abort handler will complete pending requests after
-		 * it has completed.
-		 */
-    	if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) {
-			/* Start any waiting commands for the board. */
-			if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-				ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
-				asc_execute_queue(&boardp->waiting);
-			}
-
-		 	/*
-			 * Add to the list of requests that must be completed.
-			 */
-			if (done_scp == NULL) {
-				done_scp = asc_dequeue_list(&boardp->done, &last_scp,
-					ASC_TID_ALL);
-			} else {
-				ASC_ASSERT(last_scp != NULL);
-				REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done,
-					&new_last_scp, ASC_TID_ALL);
-				if (new_last_scp != NULL) {
-					ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-					last_scp = new_last_scp;
-				}
-			}
-		}
-	}
-
-	/* Interrupts could be enabled here. */
-
-	/*
-	 * It is possible for the request done function to re-enable
-	 * interrupts without confusing the driver. But here interrupts
-	 * aren't enabled until all requests have been completed.
-	 */
-	asc_scsi_done_list(done_scp);
+    int             flags;
+    int             i;
+    asc_board_t     *boardp;
+    Scsi_Cmnd       *done_scp = NULL, *last_scp = NULL;
+    Scsi_Cmnd       *new_last_scp;
+
+    /* Disable interrupts, if they aren't already disabled. */
+    save_flags(flags);
+    cli();
+
+    ASC_DBG(1, "advansys_interrupt: begin\n");
 
-	/* Re-enable interrupts, if they were enabled on entry. */
-	restore_flags(flags);
+    /*
+     * Check for interrupts on all boards.
+     * AscISR() will call asc_isr_callback().
+     */
+    for (i = 0; i < asc_board_count; i++) {
+        boardp = ASC_BOARDP(asc_host[i]);
+        ASC_DBG2(2, "advansys_interrupt: i %d, boardp %lx\n",
+            i, (ulong) boardp)            
+        if (ASC_NARROW_BOARD(boardp)) {
+            /*
+             * Narrow Board
+             */
+            if (AscIsIntPending(asc_host[i]->io_port)) {
+                ASC_STATS(asc_host[i], interrupt);
+                ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
+                AscISR(&boardp->dvc_var.asc_dvc_var);
+            }
+        } else {
+            /*
+             * Wide Board
+             */
+            ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
+            if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+                ASC_STATS(asc_host[i], interrupt);
+            }
+        }
+
+        /*
+         * Start waiting requests and create a list of completed requests.
+         * 
+         * If a reset or abort request is being performed for the board,
+         * the reset or abort handler will complete pending requests after
+         * it has completed.
+         */
+        if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) {
+            ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n",
+                (ulong) done_scp, (ulong) last_scp);
+
+            /* Start any waiting commands for the board. */
+            if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+                ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+                asc_execute_queue(&boardp->waiting);
+            }
+
+             /*
+              * Add to the list of requests that must be completed.
+              *
+              * 'done_scp' will always be NULL on the first iteration
+              * of this loop. 'last_scp' is set at the same time as
+              * 'done_scp'.
+              */
+            if (done_scp == NULL) {
+                done_scp = asc_dequeue_list(&boardp->done, &last_scp,
+                    ASC_TID_ALL);
+            } else {
+                ASC_ASSERT(last_scp != NULL);
+                REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done,
+                    &new_last_scp, ASC_TID_ALL);
+                if (new_last_scp != NULL) {
+                    ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+                    last_scp = new_last_scp;
+                }
+            }
+        }
+    }
+
+    /* Interrupts could be enabled here. */
+
+    /*
+     * It is possible for the request done function to re-enable
+     * interrupts without confusing the driver. But here interrupts
+     * aren't enabled until all requests have been completed.
+     */
+    asc_scsi_done_list(done_scp);
+
+    /* Re-enable interrupts, if they were enabled on entry. */
+    restore_flags(flags);
 
-	ASC_DBG(1, "advansys_interrupt: end\n");
-	return;
+    ASC_DBG(1, "advansys_interrupt: end\n");
+    return;
 }
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
@@ -4454,23 +6211,30 @@
 STATIC void
 advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
 {
-	Scsi_Device		*device;
-	asc_board_t		*boardp;
+    Scsi_Device        *device;
+    asc_board_t        *boardp;
 
-	boardp = ASC_BOARDP(shp);
-	for (device = devicelist; device != NULL; device = device->next) {
-		if (device->host != shp) {
-			continue;
-		}
-		/*
-		 * Save a pointer to the device and set its initial/maximum
-		 * queue depth.
-		 */
-		boardp->device[device->id] = device;
-		device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id];
-		ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n",
-			(unsigned) shp, device->id, device->queue_depth);
-	}
+    boardp = ASC_BOARDP(shp);
+    boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
+    for (device = devicelist; device != NULL; device = device->next) {
+        if (device->host != shp) {
+            continue;
+        }
+        /*
+         * Save a pointer to the device and set its initial/maximum
+         * queue depth.
+         */
+        boardp->device[device->id] = device;
+        if (ASC_NARROW_BOARD(boardp)) {
+            device->queue_depth =
+                boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id];
+        } else {
+            device->queue_depth =
+                boardp->dvc_var.adv_dvc_var.max_dvc_qng;
+        }
+        ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n",
+            (unsigned) shp, device->id, device->queue_depth);
+    }
 }
 #endif /* version >= v1.3.89 */
 
@@ -4481,8 +6245,8 @@
 STATIC void
 advansys_command_done(Scsi_Cmnd *scp)
 {
-	ASC_DBG1(1, "advansys_command_done: scp %x\n", (unsigned) scp);
-	scp->SCp.Status = 1;
+    ASC_DBG1(1, "advansys_command_done: scp %x\n", (unsigned) scp);
+    scp->SCp.Status = 1;
 }
 
 /*
@@ -4494,17 +6258,20 @@
 STATIC void
 asc_scsi_done_list(Scsi_Cmnd *scp)
 {
-	Scsi_Cmnd	*tscp;
+    Scsi_Cmnd    *tscp;
 
-	while (scp != NULL) {
-		tscp = REQPNEXT(scp);
-		REQPNEXT(scp) = NULL;
-		ASC_STATS(scp->host, done);
-		ASC_ASSERT(scp->scsi_done != NULL);
-		scp->scsi_done(scp);
-		scp = tscp;
-	}
-	return;
+    ASC_DBG(2, "asc_scsi_done_list: begin\n");
+    while (scp != NULL) {
+        ASC_DBG1(3, "asc_scsi_done_list: scp %x\n", (unsigned) scp);
+        tscp = REQPNEXT(scp);
+        REQPNEXT(scp) = NULL;
+        ASC_STATS(scp->host, done);
+        ASC_ASSERT(scp->scsi_done != NULL);
+        scp->scsi_done(scp);
+        scp = tscp;
+    }
+    ASC_DBG(2, "asc_scsi_done_list: done\n");
+    return;
 }
 
 /*
@@ -4519,28 +6286,29 @@
  *  target - target of device
  *  lun - lun of device
  *  cmd_len - length of SCSI CDB
- *	cmnd - buffer for SCSI 8, 10, or 12 byte CDB
+ *  cmnd - buffer for SCSI 8, 10, or 12 byte CDB
  *  use_sg - if non-zero indicates scatter-gather request with use_sg elements
  *
- *  if (use_sg == 0)
- *		request_buffer - buffer address for request
- *		request_bufflen - length of request buffer
- *  else
- *		request_buffer - pointer to scatterlist structure
+ *  if (use_sg == 0) {
+ *    request_buffer - buffer address for request
+ *    request_bufflen - length of request buffer
+ *  } else {
+ *    request_buffer - pointer to scatterlist structure
+ *  }
  *
  *  sense_buffer - sense command buffer
  *
  *  result (4 bytes of an int):
- *   Byte Meaning
- *   0	  SCSI Status Byte Code
- *   1	  SCSI One Byte Message Code
- *   2 	  Host Error Code
- *   3	  Mid-Level Error Code
+ *    Byte Meaning
+ *    0 SCSI Status Byte Code
+ *    1 SCSI One Byte Message Code
+ *    2 Host Error Code
+ *    3 Mid-Level Error Code
  *
  *  host driver fields:
- *  SCp - Scsi_Pointer used for command processing status
- *  scsi_done - used to save caller's done function
- * 	host_scribble - used for pointer to another Scsi_Cmnd
+ *    SCp - Scsi_Pointer used for command processing status
+ *    scsi_done - used to save caller's done function
+ *    host_scribble - used for pointer to another Scsi_Cmnd
  *
  * If this function returns ASC_NOERROR or ASC_ERROR the request
  * has been enqueued on the board's 'done' queue and must be
@@ -4552,696 +6320,1285 @@
 STATIC int
 asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
 {
-	asc_board_t		*boardp;
-	ASC_DVC_VAR		*asc_dvc_varp;
-	Scsi_Device		*device;
-	int				ret;
-
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n",
-		(unsigned) scp, (unsigned) scp->scsi_done);
-
-	boardp = ASC_BOARDP(scp->host);
-	asc_dvc_varp = &boardp->asc_dvc_var;
-	device = boardp->device[scp->target];
-
-	/*
-	 * If this is the first command, then initialize the device. If
-	 * no device is found set 'DID_BAD_TARGET' and return.
-	 */
-	if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) {
-		if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
-			scp->result = HOST_BYTE(DID_BAD_TARGET);
-			asc_enqueue(&boardp->done, scp, ASC_BACK);
-			return ASC_ERROR;
-		}
-		boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
-	}
-
-	/*
-	 * Mutually exclusive access is required to 'asc_scsi_q' and
-	 * 'asc_sg_head' until after the request is started.
-	 */
-	memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
-
-	/*
-	 * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
-	 */
-	asc_scsi_q.q2.srb_ptr = (ulong) scp;
-
-	/*
-	 * Build the ASC_SCSI_Q request.
-	 */
-	asc_scsi_q.cdbptr = &scp->cmnd[0];
-	asc_scsi_q.q2.cdb_len = scp->cmd_len;
-	asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	asc_scsi_q.q1.target_lun = scp->lun;
-	asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-	asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
-#else /* version >= v2.0.0 */
-	asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]);
-#endif /* version >= v2.0.0 */
-	asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
-
-	/*
-	 * If there are any outstanding requests for the current target,
-	 * then every 255th request send an ORDERED request. This heuristic
-	 * tries to retain the benefit of request sorting while preventing
-	 * request starvation. 255 is the max number of tags or pending commands
-	 * a device may have outstanding.
-	 *
-	 * The request count is incremented below for every successfully
-	 * started request.
-	 * 
-	 */
-	if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) &&
-	    (boardp->reqcnt[scp->target] % 255) == 0) {
-		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
-	} else {
-		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
-	}
-
-	/*
-	 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
-	 * buffer command.
-	 */
-	if (scp->use_sg == 0) {
-		/*
-		 * CDB request of single contiguous buffer.
-		 */
-		ASC_STATS(scp->host, cont_cnt);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-		asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
-#else /* version >= v2.0.0 */
-		asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer);
-#endif /* version >= v2.0.0 */
-		asc_scsi_q.q1.data_cnt = scp->request_bufflen;
-		ASC_STATS_ADD(scp->host, cont_xfer,
-					  ASC_CEILING(scp->request_bufflen, 512));
-		asc_scsi_q.q1.sg_queue_cnt = 0;
-		asc_scsi_q.sg_head = NULL;
-	} else {
-		/*
-		 * CDB scatter-gather request list.
-		 */
-		int					sgcnt;
-		struct scatterlist	*slp;
-
-		if (scp->use_sg > scp->host->sg_tablesize) {
-			ASC_PRINT3(
-"asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n",
-				boardp->id, scp->use_sg, scp->host->sg_tablesize);
-			scp->result = HOST_BYTE(DID_ERROR);
-			asc_enqueue(&boardp->done, scp, ASC_BACK);
-			return ASC_ERROR;
-		}
-
-		ASC_STATS(scp->host, sg_cnt);
-
-		/*
-		 * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q
-		 * to point to it.
-		 */
-		memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
-
-		asc_scsi_q.q1.cntl |= QC_SG_HEAD;
-		asc_scsi_q.sg_head = &asc_sg_head;
-		asc_scsi_q.q1.data_cnt = 0;
-		asc_scsi_q.q1.data_addr = 0;
-		asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
-		ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt);
-
-		/*
-		 * Convert scatter-gather list into ASC_SG_HEAD list.
-		 */
-		slp = (struct scatterlist *) scp->request_buffer;
-		for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-			asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
-#else /* version >= v2.0.0 */
-			asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address);
-#endif /* version >= v2.0.0 */
-			asc_sg_head.sg_list[sgcnt].bytes = slp->length;
-			ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
-		}
-	}
-
-	ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q);
-	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
-
-	/*
-	 * Execute the command. If there is no error, add the command
-	 * to the active queue.
-	 */
-	switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
-	case ASC_NOERROR:
-		ASC_STATS(scp->host, asc_noerror);
-		/*
-		 * Increment monotonically increasing per device successful
-		 * request counter. Wrapping doesn't matter.
-		 */
-		boardp->reqcnt[scp->target]++;
+    asc_board_t        *boardp;
+    ASC_DVC_VAR        *asc_dvc_varp;
+    ADV_DVC_VAR        *adv_dvc_varp;
+    ADV_SCSI_REQ_Q     *adv_scsiqp;
+    Scsi_Device        *device;
+    int                ret;
+
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n",
+        (unsigned) scp, (unsigned) scp->scsi_done);
+
+    boardp = ASC_BOARDP(scp->host);
+    device = boardp->device[scp->target];
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        /*
+         * Build and execute Narrow Board request.
+         */
+
+        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+
+        /*
+         * Narrow Board - Asc Library requires special device initialization.
+         *
+         * If this is the first command, then initialize the device. If
+         * no device is found set 'DID_BAD_TARGET' and return.
+         */
+        if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0) {
+            if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
+                scp->result = HOST_BYTE(DID_BAD_TARGET);
+                asc_enqueue(&boardp->done, scp, ASC_BACK);
+                return ASC_ERROR;
+            }
+            boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
+        }
+
+        /*
+         * Build Asc Library request structure using the
+         * global structures 'asc_scsi_req' and 'asc_sg_head'.
+         *
+         * asc_build_req() can not return ASC_BUSY.
+         */
+        if (asc_build_req(boardp, scp) == ASC_ERROR) {
+            ASC_STATS(scp->host, build_error);
+            return ASC_ERROR;
+        }
+
+        /*
+         * Execute the command. If there is no error, add the command
+         * to the active queue.
+         */
+        switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
+        case ASC_NOERROR:
+            ASC_STATS(scp->host, exe_noerror);
+            /*
+             * Increment monotonically increasing per device successful
+             * request counter. Wrapping doesn't matter.
+             */
+            boardp->reqcnt[scp->target]++;
 
 #if ASC_QUEUE_FLOW_CONTROL
-		/*
-		 * Conditionally increment the device queue depth.
-		 *
-	 	 * If no error occurred and there have been 100 consecutive
-		 * successfull requests and the current queue depth is less
-		 * than the maximum queue depth, then increment the current
-		 * queue depth.
-		 */
-		if (boardp->nerrcnt[scp->target]++ > 100) {
-			boardp->nerrcnt[scp->target] = 0;
-			if ((device->queue_curr_depth < device->queue_depth) &&
-			    (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) ||
-				 (boardp->queue_full_cnt[scp->target] >
-				  device->queue_curr_depth))) {
-				device->queue_curr_depth++;
-			}
-		}
+            /*
+             * Conditionally increment the device queue depth.
+             *
+             * If no error occurred and there have been 100 consecutive
+             * successful requests and the current queue depth is less
+             * than the maximum queue depth, then increment the current
+             * queue depth.
+             */
+            if (boardp->nerrcnt[scp->target]++ > 100) {
+                boardp->nerrcnt[scp->target] = 0;
+                if (device != NULL &&
+                    (device->queue_curr_depth < device->queue_depth) &&
+                    (!(boardp->queue_full &
+                       ADV_TID_TO_TIDMASK(scp->target)) ||
+                     (boardp->queue_full_cnt[scp->target] >
+                      device->queue_curr_depth))) {
+                    device->queue_curr_depth++;
+                }
+            }
 #endif /* ASC_QUEUE_FLOW_CONTROL */
-		asc_enqueue(&boardp->active, scp, ASC_BACK);
-		ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
-		break;
-	case ASC_BUSY:
-		/* Caller must enqueue request and retry later. */
-		ASC_STATS(scp->host, asc_busy);
+            asc_enqueue(&boardp->active, scp, ASC_BACK);
+            ASC_DBG(1,
+                "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
+            break;
+        case ASC_BUSY:
+            /* Caller must enqueue request and retry later. */
+            ASC_STATS(scp->host, exe_busy);
 #if ASC_QUEUE_FLOW_CONTROL
-		/*
-		 * Clear consecutive no error counter and if possbile decrement
-		 * queue depth.
-		 */
-		boardp->nerrcnt[scp->target] = 0;
-		if (device->queue_curr_depth > 1) {
-			device->queue_curr_depth--;
-		}
+            /*
+             * Clear consecutive no error counter and if possible decrement
+             * queue depth.
+             */
+            boardp->nerrcnt[scp->target] = 0;
+            if (device != NULL && device->queue_curr_depth > 1) {
+                device->queue_curr_depth--;
+            }
 #endif /* ASC_QUEUE_FLOW_CONTROL */
-		break;
-	case ASC_ERROR:
-		ASC_PRINT2(
+            break;
+        case ASC_ERROR:
+            ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
-			boardp->id, asc_dvc_varp->err_code);
-		ASC_STATS(scp->host, asc_error);
+                boardp->id, asc_dvc_varp->err_code);
+            ASC_STATS(scp->host, exe_error);
 #if ASC_QUEUE_FLOW_CONTROL
-		/* Clear consecutive no error counter. */
-		boardp->nerrcnt[scp->target] = 0;
+            /* Clear consecutive no error counter. */
+            boardp->nerrcnt[scp->target] = 0;
 #endif /* ASC_QUEUE_FLOW_CONTROL */
-		scp->result = HOST_BYTE(DID_ERROR);
-		asc_enqueue(&boardp->done, scp, ASC_BACK);
-		break;
-	default:
-		ASC_PRINT2(
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        default:
+            ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
-			boardp->id, asc_dvc_varp->err_code);
-		ASC_STATS(scp->host, asc_unknown);
+                boardp->id, asc_dvc_varp->err_code);
+            ASC_STATS(scp->host, exe_unknown);
 #if ASC_QUEUE_FLOW_CONTROL
-		/* Clear consecutive no error counter. */
-		boardp->nerrcnt[scp->target] = 0;
+            /* Clear consecutive no error counter. */
+            boardp->nerrcnt[scp->target] = 0;
 #endif /* ASC_QUEUE_FLOW_CONTROL */
-		scp->result = HOST_BYTE(DID_ERROR);
-		asc_enqueue(&boardp->done, scp, ASC_BACK);
-		break;
-	}
-
-	ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	return ret;
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        }
+    } else {
+        /*
+         * Build and execute Wide Board request.
+         */
+        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+
+        /*
+         * Build and get a pointer to an Adv Library request structure.
+         *
+         * If the request is successfully built then send  it below,
+         * otherwise return with an error.
+         */
+        switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+        case ASC_NOERROR:
+            ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
+            break;
+        case ASC_BUSY:
+            ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
+            return ASC_BUSY;
+        case ASC_ERROR:
+        default:
+            ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
+            ASC_STATS(scp->host, build_error);
+            return ASC_ERROR;
+        }
+    
+        /*
+         * Execute the command. If there is no error, add the command
+         * to the active queue.
+         */
+        switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
+        case ASC_NOERROR:
+            ASC_STATS(scp->host, exe_noerror);
+            /*
+             * Increment monotonically increasing per device successful
+             * request counter. Wrapping doesn't matter.
+             */
+            boardp->reqcnt[scp->target]++;
+            asc_enqueue(&boardp->active, scp, ASC_BACK);
+            ASC_DBG(1,
+                "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
+            break;
+        case ASC_BUSY:
+            /* Caller must enqueue request and retry later. */
+            ASC_STATS(scp->host, exe_busy);
+            break;
+        case ASC_ERROR:
+            ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code %x\n",
+                boardp->id, adv_dvc_varp->err_code);
+            ASC_STATS(scp->host, exe_error);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        default:
+            ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code %x\n",
+                boardp->id, adv_dvc_varp->err_code);
+            ASC_STATS(scp->host, exe_unknown);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        }
+    }
+
+    ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    return ret;
 }
 
 /*
- * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ * Build a request structure for the Asc Library (Narrow Board).
+ *
+ * The global structures 'asc_scsi_q' and 'asc_sg_head' are
+ * used to build the request.
+ *
+ * If an error occurs, then return ASC_ERROR.
  */
-void
-asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+STATIC int
+asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
 {
-	asc_board_t			*boardp;
-	Scsi_Cmnd			*scp;
-	struct Scsi_Host	*shp;
-	int					i;
-
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n",
-		(unsigned) asc_dvc_varp, (unsigned) qdonep);
-	ASC_DBG_PRT_QDONE_INFO(2, qdonep);
-
-	/*
-	 * Get the Scsi_Cmnd structure and Scsi_Host structure for the
-	 * command that has been completed.
-	 */
-	scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr;
-	ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
-	ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
-
-	if (scp == NULL) {
-		ASC_PRINT("asc_isr_callback: scp is NULL\n");
-		return;
-	}
-
-	/*
-	 * If the request's host pointer is not valid, display a
-	 * message and return.
-	 */
-	shp = scp->host;
-	for (i = 0; i < asc_board_count; i++) {
-		if (asc_host[i] == shp) {
-			break;
-		}
-	}
-	if (i == asc_board_count) {
-		ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n",
-			(unsigned) scp, (unsigned) shp);
-		return;
-	}
-
-	ASC_STATS(shp, callback);
-	ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp);
-
-	/*
-	 * If the request isn't found on the active queue, it may
-	 * have been removed to handle a reset or abort request.
-	 * Display a message and return.
-	 */
-	boardp = ASC_BOARDP(shp);
-	if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-		ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n",
-			boardp->id, (unsigned) scp);
-		return;
-	}
-
-	/*
-	 * 'qdonep' contains the command's ending status.
-	 */
-	switch (qdonep->d3.done_stat) {
-	case QD_NO_ERROR:
-		ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
-		switch (qdonep->d3.host_stat) {
-		case QHSTA_NO_ERROR:
-			scp->result = 0;
-			break;
-		default:
-			/* QHSTA error occurred */
-			scp->result = HOST_BYTE(DID_ERROR);
-			break;
-		}
-		break;
-
-	case QD_WITH_ERROR:
-		ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
-		switch (qdonep->d3.host_stat) {
-		case QHSTA_NO_ERROR:
-			if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) {
-				ASC_DBG(2, "asc_isr_callback: SS_CHK_CONDITION\n");
-				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-					sizeof(scp->sense_buffer));
-				/*
-				 * Note: The 'status_byte()' macro used by target drivers
-				 * defined in scsi.h shifts the status byte returned by
-				 * host drivers right by 1 bit. This is why target drivers
-				 * also use right shifted status byte definitions. For
-				 * instance target drivers use CHECK_CONDITION, defined to
-				 * 0x1, instead of the SCSI defined check condition value
-				 * of 0x2. Host drivers are supposed to return the status
-				 * byte as it is defined by SCSI.
-				 */
-				scp->result = DRIVER_BYTE(DRIVER_SENSE) |
-					STATUS_BYTE(qdonep->d3.scsi_stat); 
-			} else {
-				scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); 
-			}
-			break;
-
-		default:
-			/* QHSTA error occurred */
-			ASC_DBG1(2, "asc_isr_callback: host_stat %x\n",
-				qdonep->d3.host_stat);
-			scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
-				STATUS_BYTE(qdonep->d3.scsi_stat);
-			break;
-		}
-		break;
-
-	case QD_ABORTED_BY_HOST:
-		ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
-		scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) |
-				STATUS_BYTE(qdonep->d3.scsi_stat);
-		break;
-
-	default:
-		ASC_PRINT1("asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat );
-		scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
-				STATUS_BYTE(qdonep->d3.scsi_stat);
-		break;
-	}
-
-	/* 
-	 * Because interrupts may be enabled by the 'Scsi_Cmnd' done
-	 * function, add the command to the end of the board's done queue.
-	 * The done function for the command will be called from
-	 * advansys_interrupt().
-	 */
-	asc_enqueue(&boardp->done, scp, ASC_BACK);
+    /*
+     * Mutually exclusive access is required to 'asc_scsi_q' and
+     * 'asc_sg_head' until after the request is started.
+     */
+    memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
+
+    /*
+     * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
+     */
+    asc_scsi_q.q2.srb_ptr = (ulong) scp;
+
+    /*
+     * Build the ASC_SCSI_Q request.
+     */
+    ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN);
+    if (scp->cmd_len > ASC_MAX_CDB_LEN) {
+        scp->cmd_len = ASC_MAX_CDB_LEN;
+    }
+    asc_scsi_q.cdbptr = &scp->cmnd[0];
+    asc_scsi_q.q2.cdb_len = scp->cmd_len;
+    asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+    asc_scsi_q.q1.target_lun = scp->lun;
+    asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+    asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+#else /* version >= v2.0.0 */
+    asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]);
+#endif /* version >= v2.0.0 */
+    asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+
+    /*
+     * If there are any outstanding requests for the current target,
+     * then every 255th request send an ORDERED request. This heuristic
+     * tries to retain the benefit of request sorting while preventing
+     * request starvation. 255 is the max number of tags or pending commands
+     * a device may have outstanding.
+     *
+     * The request count is incremented below for every successfully
+     * started request.
+     * 
+     */
+    if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) &&
+        (boardp->reqcnt[scp->target] % 255) == 0) {
+        asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
+    } else {
+        asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+    }
+
+    /*
+     * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
+     * buffer command.
+     */
+    if (scp->use_sg == 0) {
+        /*
+         * CDB request of single contiguous buffer.
+         */
+        ASC_STATS(scp->host, cont_cnt);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+        asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
+#else /* version >= v2.0.0 */
+        asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer);
+#endif /* version >= v2.0.0 */
+        asc_scsi_q.q1.data_cnt = scp->request_bufflen;
+        ASC_STATS_ADD(scp->host, cont_xfer,
+                      ASC_CEILING(scp->request_bufflen, 512));
+        asc_scsi_q.q1.sg_queue_cnt = 0;
+        asc_scsi_q.sg_head = NULL;
+    } else {
+        /*
+         * CDB scatter-gather request list.
+         */
+        int                     sgcnt;
+        struct scatterlist      *slp;
+
+        if (scp->use_sg > scp->host->sg_tablesize) {
+            ASC_PRINT3(
+"asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
+                boardp->id, scp->use_sg, scp->host->sg_tablesize);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            return ASC_ERROR;
+        }
+
+        ASC_STATS(scp->host, sg_cnt);
+
+        /*
+         * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
+         * structure to point to it.
+         */
+        memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
+
+        asc_scsi_q.q1.cntl |= QC_SG_HEAD;
+        asc_scsi_q.sg_head = &asc_sg_head;
+        asc_scsi_q.q1.data_cnt = 0;
+        asc_scsi_q.q1.data_addr = 0;
+        asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
+        ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt);
+
+        /*
+         * Convert scatter-gather list into ASC_SG_HEAD list.
+         */
+        slp = (struct scatterlist *) scp->request_buffer;
+        for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+            asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
+#else /* version >= v2.0.0 */
+            asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address);
+#endif /* version >= v2.0.0 */
+            asc_sg_head.sg_list[sgcnt].bytes = slp->length;
+            ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
+        }
+    }
 
-	return;
+    ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
+    ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+    return ASC_NOERROR;
 }
 
 /*
- * asc_init_dev()
+ * Build a request structure for the Adv Library (Wide Board).
  *
- * Perform one-time initialization of a device.
+ * If an adv_req_t can not be allocated to issue the request,
+ * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
  */
 STATIC int
-asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
+adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp,
+    ADV_SCSI_REQ_Q **adv_scsiqpp)
 {
-	asc_board_t				*boardp;
-	ASC_SCSI_REQ_Q			*scsireqq;
-	ASC_CAP_INFO			*cap_info;
-	ASC_SCSI_INQUIRY		*inquiry;
-	int						found;
-	ASC_SCSI_BIT_ID_TYPE	save_use_tagged_qng;
-	ASC_SCSI_BIT_ID_TYPE	save_can_tagged_qng;
-	int						ret;
-#ifdef ADVANSYS_DEBUG
-	ASC_SCSI_BIT_ID_TYPE	tidmask; /* target id bit mask: 1 - 128 */
-#endif /* ADVANSYS_DEBUG */
+    adv_req_t           *reqp;
+    ADV_SCSI_REQ_Q      *scsiqp;
+    int                 i;
 
-	ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target);
+    /*
+     * Allocate an adv_req_t structure from the board to execute
+     * the command.
+     */
+    if (boardp->adv_reqp == NULL) {
+        ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
+        ASC_STATS(scp->host, adv_build_noreq);
+        return ASC_BUSY;
+    } else {
+        reqp = boardp->adv_reqp;
+        boardp->adv_reqp = reqp->next_reqp;
+        reqp->next_reqp = NULL;
+    }
 
-	/* The host's target id is set in init_tidmask during initialization. */
-	ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target);
+    /*
+     * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+     */
+    scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q);
+    memset(scsiqp, 0, sizeof(ADV_SCSI_REQ_Q));
 
-	boardp = ASC_BOARDP(scp->host);
+    /*
+     * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
+     */
+    scsiqp->srb_ptr = (ulong) reqp;
 
-	/* Set-up AscInitPollTarget() arguments. */
-	scsireqq = &boardp->scsireqq;
-	memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
-	cap_info = &boardp->cap_info;
-	memset(cap_info, 0, sizeof(ASC_CAP_INFO));
-	inquiry = &boardp->inquiry;
-
-	/*
-	 * XXX - AscInitPollBegin() re-initializes these fields to
-	 * zero. 'Or' in the new values and restore them before calling 
-	 * AscInitPollEnd(). Normally all targets are initialized within
-	 * a call to AscInitPollBegin() and AscInitPollEnd().
-	 */
-	save_use_tagged_qng = asc_dvc_varp->use_tagged_qng;
-    save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng;
+    /*
+     * Set the adv_req_t 'cmndp' to point to the Scsi_Cmnd structure.
+     */
+    reqp->cmndp = scp;
 
-	ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n");
-	if (AscInitPollBegin(asc_dvc_varp)) {
-		ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n",
-			boardp->id);
-		return ASC_FALSE;
-	}
-
-	scsireqq->sense_ptr = &scsireqq->sense[0];
-	scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
-	scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	scsireqq->r1.target_lun = 0;
-	scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
-
-	found = ASC_FALSE;
-	ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
-	switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry,
-		cap_info)) {
-	case ASC_TRUE:
-		found = ASC_TRUE;
-#ifdef ADVANSYS_DEBUG
-		tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
-		ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
-			cap_info->lba, cap_info->blk_size);
-		ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
-			inquiry->byte0.peri_dvc_type);
-		if (asc_dvc_varp->use_tagged_qng & tidmask) {
-			ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
-				asc_dvc_varp->max_dvc_qng[scp->target]);
-		} else {
-			ASC_DBG(1, "asc_init_dev: command queuing disabled\n");
-		}
-		if (asc_dvc_varp->init_sdtr & tidmask) {
-			ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n");
-		} else {
-			ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n");
-		}
-		/* Set bit means fix disabled. */
-		if (asc_dvc_varp->pci_fix_asyn_xfer & tidmask) {
-			ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n");
-		} else {
-			ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n");
-		}
-#endif /* ADVANSYS_DEBUG */
-		break;
-	case ASC_FALSE:
-		ASC_DBG(1, "asc_init_dev: no device found\n");
-		break;
-	case ASC_ERROR:
-		ASC_PRINT1("asc_init_dev: board %d: AscInitPollTarget() ASC_ERROR\n",
-				boardp->id);
-		break;
-	default:
-		ASC_PRINT2(
-"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n",
-				boardp->id, ret);
-		break;
-	}
+    /*
+     * Build the ADV_SCSI_REQ_Q request.
+     */
 
-	/* XXX - 'Or' in original tag bits. */
-	asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng;
-	asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng;
+    /*
+     * Set CDB length and copy it to the request structure.
+     */
+    ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN);
+    if (scp->cmd_len > ASC_MAX_CDB_LEN) {
+        scp->cmd_len = ASC_MAX_CDB_LEN;
+    }
+    scsiqp->cdb_len = scp->cmd_len;
+    for (i = 0; i < scp->cmd_len; i++) {
+        scsiqp->cdb[i] = scp->cmnd[i];
+    }
 
-	ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n");
-	AscInitPollEnd(asc_dvc_varp);
+    scsiqp->target_id = scp->target;
+    scsiqp->target_lun = scp->lun;
 
-	ASC_DBG1(1, "asc_init_dev: found %d\n", found); 
+    scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0];
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+    scsiqp->sense_addr = (ulong) &scp->sense_buffer[0];
+#else /* version >= v2.0.0 */
+    scsiqp->sense_addr = virt_to_bus(&scp->sense_buffer[0]);
+#endif /* version >= v2.0.0 */
+    scsiqp->sense_len = sizeof(scp->sense_buffer);
 
-	return found;
-}
+    /*
+     * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
+     * buffer command.
+     */
+    scsiqp->data_cnt = scp->request_bufflen;
+    scsiqp->vdata_addr = (ulong) scp->request_buffer;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+    scsiqp->data_addr = (ulong) scp->request_buffer;
+#else /* version >= v2.0.0 */
+    scsiqp->data_addr = virt_to_bus(scp->request_buffer);
+#endif /* version >= v2.0.0 */
 
-/*
- * Search for an AdvanSys PCI device in the PCI configuration space.
- */
-STATIC int
-asc_srch_pci_dev(PCI_DEVICE *pciDevice)
-{
-	int ret;
+    if (scp->use_sg == 0) {
+        /*
+         * CDB request of single contiguous buffer.
+         */
+        reqp->sgblkp = NULL;
+        scsiqp->sg_list_ptr = NULL;
+        ASC_STATS(scp->host, cont_cnt);
+        ASC_STATS_ADD(scp->host, cont_xfer,
+                      ASC_CEILING(scp->request_bufflen, 512));
+    } else {
+        /*
+         * CDB scatter-gather request list.
+         */
+        if (scp->use_sg > ADV_MAX_SG_LIST) {
+            ASC_PRINT3(
+"adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
+                boardp->id, scp->use_sg, scp->host->sg_tablesize);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+            /*
+             * Free the 'adv_req_t' structure by adding it back to the
+             * board free list.
+             */
+            reqp->next_reqp = boardp->adv_reqp;
+            boardp->adv_reqp = reqp;
+
+            return ASC_ERROR;
+        }
+
+        /*
+         * Allocate an 'adv_sgblk_t' structure from the board to
+         * execute the command.
+         */
+        if (boardp->adv_sgblkp == NULL) {
+            ASC_DBG(1, "adv_build_req: no free adv_sgblk_t\n");
+            ASC_STATS(scp->host, adv_build_nosg);
+            /*
+             * Free the 'adv_req_t' structure by adding it back to the
+             * board free list.
+             */
+            reqp->next_reqp = boardp->adv_reqp;
+            boardp->adv_reqp = reqp;
+            return ASC_BUSY;
+        } else {
+            reqp->sgblkp = boardp->adv_sgblkp;
+            boardp->adv_sgblkp = reqp->sgblkp->next_sgblkp;
+            reqp->sgblkp->next_sgblkp = NULL;
+        }
+
+        /*
+         * Build scatter-gather list.
+         */
+        scsiqp->sg_list_ptr = (ADV_SG_BLOCK *)
+            ADV_DWALIGN(&reqp->sgblkp->sg_block[0]);
+
+        memset(scsiqp->sg_list_ptr, 0, sizeof(ADV_SG_BLOCK) *
+            (ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING));
+         
+        if (adv_get_sglist(&boardp->dvc_var.adv_dvc_var, scsiqp, scp) ==
+            ADV_ERROR) {
+
+            /*
+             * Free the adv_sgblk_t structure, if any, by adding it back
+             * to the board free list.
+             */
+            ASC_ASSERT(reqp->sgblkp != NULL);
+            reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp;
+            boardp->adv_sgblkp = reqp->sgblkp;
+
+            /*
+             * Free the adv_req_t structure by adding it back to the
+             * board free list.
+             */
+            reqp->next_reqp = boardp->adv_reqp;
+            boardp->adv_reqp = reqp;
 
-	ASC_DBG(2, "asc_srch_pci_dev: begin\n");
+            return ADV_ERROR;
+        }
 
-	if (pci_scan_method == -1) {
-		pci_scan_method = asc_scan_method();
-	}
-	pciDevice->type = pci_scan_method;
-	ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type);
-
-	ret = asc_pci_find_dev(pciDevice);
-	ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret);
-	if (ret == PCI_DEVICE_FOUND) {
-		pciDevice->slotNumber = pciDevice->slotFound + 1;
-		pciDevice->startSlot = pciDevice->slotFound + 1;
-	} else {
-		if (pciDevice->bridge > pciDevice->busNumber) {
-			ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n",
-				pciDevice->bridge, pciDevice->busNumber);
-			pciDevice->busNumber++;
-			pciDevice->slotNumber = 0;
-			pciDevice->startSlot = 0;
-			pciDevice->endSlot = 0x0f;
-			ret = asc_srch_pci_dev(pciDevice);
-			ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret);
-		}
-	}
-	ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret);
-	return ret;
-}
+        ASC_STATS(scp->host, sg_cnt);
+        ASC_STATS_ADD(scp->host, sg_elem, scp->use_sg);
+    }
 
-/*
- * Determine the access method to be used for 'pciDevice'.
- */
-STATIC uchar
-asc_scan_method(void)
-{
-	ushort data;
-	PCI_DATA pciData;
-	uchar type;
-	uchar slot;
-
-	ASC_DBG(2, "asc_scan_method: begin\n");
-	memset(&pciData, 0, sizeof(pciData));
-	for (type = 1; type < 3; type++) {
-		pciData.type = type;
-		for (slot = 0; slot < PCI_MAX_SLOT; slot++) {
-			pciData.slot = slot;
-			data = asc_get_cfg_word(&pciData);
-			if ((data != 0xFFFF) && (data != 0x0000)) {
-				ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type);
-				return (type);
-			}
-		}
-	}
-	ASC_DBG1(4, "asc_scan_method: type %d\n", type);
-	return (type);
+    ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+    ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+    *adv_scsiqpp = scsiqp;
+
+    return ASC_NOERROR;
 }
 
 /*
- * Check for an AdvanSys PCI device in 'pciDevice'.
+ * Build scatter-gather list for Adv Library (Wide Board).
  *
- * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND.
+ * Return:
+ *      ADV_SUCCESS(1) - SG List successfully created
+ *      ADV_ERROR(-1) - SG List creation failed
  */
 STATIC int
-asc_pci_find_dev(PCI_DEVICE *pciDevice)
+adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp,
+    Scsi_Cmnd *scp)
 {
-	PCI_DATA pciData;
-	ushort vendorid, deviceid;
-	uchar classcode, subclass;
-	uchar lslot;
-
-	ASC_DBG(3, "asc_pci_find_dev: begin\n");
-	pciData.type = pciDevice->type;
-	pciData.bus = pciDevice->busNumber;
-	pciData.func = pciDevice->devFunc;
-	lslot = pciDevice->startSlot;
-	for (; lslot < pciDevice->endSlot; lslot++) {
-		pciData.slot = lslot;
-		pciData.offset = VENDORID_OFFSET;
-		vendorid = asc_get_cfg_word(&pciData);
-		ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid);
-		if (vendorid != 0xffff) {
-			pciData.offset = DEVICEID_OFFSET;
-			deviceid = asc_get_cfg_word(&pciData);
-			ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid);
-			if ((vendorid == ASC_PCI_VENDORID) &&
-				((deviceid == ASC_PCI_DEVICE_ID_1100) ||
-				 (deviceid == ASC_PCI_DEVICE_ID_1200) ||
-				 (deviceid == ASC_PCI_DEVICE_ID_1300))) {
-				pciDevice->slotFound = lslot;
-				ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
-				return PCI_DEVICE_FOUND;
-			} else {
-				pciData.offset = SUBCLASS_OFFSET;
-				subclass = asc_get_cfg_byte(&pciData);
-				pciData.offset = CLASSCODE_OFFSET;
-				classcode = asc_get_cfg_byte(&pciData);
-				if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) &&
-					(subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) {
-					pciDevice->bridge++;
-				}
-				ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n",
-					subclass, classcode);
-			}
-		}
-	}
-	return PCI_DEVICE_NOT_FOUND;
+    ADV_SG_BLOCK        *sg_block;              /* virtual address of a SG */
+    ulong               sg_block_next_addr;     /* block and its next */
+    ulong               sg_block_physical_addr;
+    int                 sg_block_index, i;      /* how many SG entries */
+    struct scatterlist  *slp;
+    int                 sg_elem_cnt;
+
+    slp = (struct scatterlist *) scp->request_buffer;
+    sg_elem_cnt = scp->use_sg;
+
+    sg_block = scsiqp->sg_list_ptr;
+    sg_block_next_addr = (ulong) sg_block;    /* allow math operation */
+    sg_block_physical_addr =
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+        (ulong) scsiqp->sg_list_ptr;
+#else /* version >= v2.0.0 */
+        virt_to_bus(scsiqp->sg_list_ptr);
+#endif /* version >= v2.0.0 */
+    ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
+                   sg_block_physical_addr);
+    scsiqp->sg_real_addr = sg_block_physical_addr;
+
+    sg_block_index = 0;
+    do
+    {
+        sg_block->first_entry_no = sg_block_index;
+        for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
+        {
+            sg_block->sg_list[i].sg_addr =
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+                (ulong) slp->address;
+#else /* version >= v2.0.0 */
+                virt_to_bus(slp->address);
+#endif /* version >= v2.0.0 */
+            sg_block->sg_list[i].sg_count = slp->length;
+            ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
+
+            if (--sg_elem_cnt == 0)
+            {   /* last entry, get out */
+                scsiqp->sg_entry_cnt = sg_block_index + i + 1;
+                sg_block->last_entry_no = sg_block_index + i;
+                sg_block->sg_ptr = 0L;    /* next link = NULL */
+                return ADV_SUCCESS;
+            }
+            slp++;
+        } 
+        sg_block_next_addr += sizeof(ADV_SG_BLOCK);
+        sg_block_physical_addr += sizeof(ADV_SG_BLOCK);
+        ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
+                       sg_block_physical_addr);
+
+        sg_block_index += NO_OF_SG_PER_BLOCK;
+        sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr;
+        sg_block->last_entry_no = sg_block_index - 1;
+        sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */
+    }
+    while (1);
+    /* NOTREACHED */
 }
 
 /*
- * Read PCI configuration data into 'pciConfig'.
+ * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ *
+ * Interrupt callback function for the Narrow SCSI Asc Library.
  */
 STATIC void
-asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
+asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 {
-	PCI_DATA pciData;
-	uchar counter;
-	uchar *localConfig;
-
-	ASC_DBG1(4, "asc_get_pci_cfg: slot found - %d\n ",
-		pciDevice->slotFound);
-
-	pciData.type = pciDevice->type;
-	pciData.bus = pciDevice->busNumber;
-	pciData.slot = pciDevice->slotFound;
-	pciData.func = pciDevice->devFunc;
-	localConfig = (uchar *) pciConfig;
-
-	for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) {
-		pciData.offset = counter;
-		*localConfig = asc_get_cfg_byte(&pciData);
-		ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig);
-		localConfig++;
-	}
-	ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter);
-}
+    asc_board_t         *boardp;
+    Scsi_Cmnd           *scp;
+    struct Scsi_Host    *shp;
+    int            underrun = ASC_FALSE;
+    int                 i;
+
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n",
+        (unsigned) asc_dvc_varp, (unsigned) qdonep);
+    ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
 
-/*
- * Read a word (16 bits) from the PCI configuration space.
- *
- * The configuration mechanism is checked for the correct access method.
+    /*
+     * Get the Scsi_Cmnd structure and Scsi_Host structure for the
+     * command that has been completed.
+     */
+    scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr;
+    ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
+
+    if (scp == NULL) {
+        ASC_PRINT("asc_isr_callback: scp is NULL\n");
+        return;
+    }
+    ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+    /*
+     * If the request's host pointer is not valid, display a
+     * message and return.
+     */
+    shp = scp->host;
+    for (i = 0; i < asc_board_count; i++) {
+        if (asc_host[i] == shp) {
+            break;
+        }
+    }
+    if (i == asc_board_count) {
+        ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n",
+            (unsigned) scp, (unsigned) shp);
+        return;
+    }
+
+    ASC_STATS(shp, callback);
+    ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp);
+
+    /*
+     * If the request isn't found on the active queue, it may
+     * have been removed to handle a reset or abort request.
+     * Display a message and return.
+     */
+    boardp = ASC_BOARDP(shp);
+    if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+        ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n",
+            boardp->id, (unsigned) scp);
+        return;
+    }
+
+    /*
+     * Check for an underrun condition.
+     */
+    if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && 
+    qdonep->remain_bytes <= scp->request_bufflen != 0) {
+        ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
+        (unsigned) qdonep->remain_bytes);
+        underrun = ASC_TRUE;
+    }
+
+    /*
+     * 'qdonep' contains the command's ending status.
+     */
+    switch (qdonep->d3.done_stat) {
+    case QD_NO_ERROR:
+        ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
+        switch (qdonep->d3.host_stat) {
+        case QHSTA_NO_ERROR:
+            scp->result = 0;
+            break;
+        default:
+            /* QHSTA error occurred */
+            scp->result = HOST_BYTE(DID_ERROR);
+            break;
+        }
+    /*
+     * If there was an underrun without any other error,
+     * set DID_ERROR to indicate the underrun error.
+     */
+    if (scp->result == 0 && underrun == ASC_TRUE) {
+            scp->result = HOST_BYTE(DID_UNDERRUN);
+    }
+        break;
+
+    case QD_WITH_ERROR:
+        ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
+        switch (qdonep->d3.host_stat) {
+        case QHSTA_NO_ERROR:
+            if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) {
+                ASC_DBG(2, "asc_isr_callback: SS_CHK_CONDITION\n");
+                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+                    sizeof(scp->sense_buffer));
+                /*
+                 * Note: The 'status_byte()' macro used by target drivers
+                 * defined in scsi.h shifts the status byte returned by
+                 * host drivers right by 1 bit. This is why target drivers
+                 * also use right shifted status byte definitions. For
+                 * instance target drivers use CHECK_CONDITION, defined to
+                 * 0x1, instead of the SCSI defined check condition value
+                 * of 0x2. Host drivers are supposed to return the status
+                 * byte as it is defined by SCSI.
+                 */
+                scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+                    STATUS_BYTE(qdonep->d3.scsi_stat); 
+            } else {
+                scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); 
+            }
+            break;
+
+        default:
+            /* QHSTA error occurred */
+            ASC_DBG1(2, "asc_isr_callback: host_stat %x\n",
+                qdonep->d3.host_stat);
+            scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
+                STATUS_BYTE(qdonep->d3.scsi_stat);
+            break;
+        }
+        break;
+
+    case QD_ABORTED_BY_HOST:
+        ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
+        scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) |
+                STATUS_BYTE(qdonep->d3.scsi_stat);
+        break;
+
+    default:
+        ASC_PRINT1("asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat);
+        scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
+                STATUS_BYTE(qdonep->d3.scsi_stat);
+        break;
+    }
+
+    /* 
+     * Because interrupts may be enabled by the 'Scsi_Cmnd' done
+     * function, add the command to the end of the board's done queue.
+     * The done function for the command will be called from
+     * advansys_interrupt().
+     */
+    asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+    return;
+}
+
+/*
+ * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ *
+ * Callback function for the Wide SCSI Adv Library.
+ */
+STATIC void
+adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+{
+    asc_board_t         *boardp;
+    adv_req_t           *reqp;
+    Scsi_Cmnd           *scp;
+    struct Scsi_Host    *shp;
+    int            underrun = ASC_FALSE;
+    int                 i;
+
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %x, scsiqp %x\n",
+        (unsigned) adv_dvc_varp, (unsigned) scsiqp);
+    ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+
+    /*
+     * Get the adv_req_t structure for the command that has been
+     * completed. The adv_req_t structure actually contains the
+     * completed ADV_SCSI_REQ_Q structure.
+     */
+    reqp = (adv_req_t *) scsiqp->srb_ptr;
+    ASC_DBG1(1, "adv_isr_callback: reqp %x\n", (unsigned) reqp);
+    if (reqp == NULL) {
+        ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+        return;
+    }
+
+    /*
+     * Get the Scsi_Cmnd structure and Scsi_Host structure for the
+     * command that has been completed.
+     *
+     * Note: The adv_req_t request structure and adv_sgblk_t structure,
+     * if any, * dropped, because a board structure pointer can not be
+     * determined.
+     */
+    scp = reqp->cmndp;
+    ASC_DBG1(1, "adv_isr_callback: scp %x\n", (unsigned) scp);
+    if (scp == NULL) {
+        ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+        return;
+    }
+    ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+    /*
+     * If the request's host pointer is not valid, display a message
+     * and return.
+     */
+    shp = scp->host;
+    for (i = 0; i < asc_board_count; i++) {
+        if (asc_host[i] == shp) {
+            break;
+        }
+    }
+    /*
+     * Note: If the host structure is not found, the adv_req_t request
+     * structure and adv_sgblk_t structure, if any, is dropped.
+     */
+    if (i == asc_board_count) {
+        ASC_PRINT2("adv_isr_callback: scp %x has bad host pointer, host %x\n",
+            (unsigned) scp, (unsigned) shp);
+        return;
+    }
+
+    ASC_STATS(shp, callback);
+    ASC_DBG1(1, "adv_isr_callback: shp %x\n", (unsigned) shp);
+
+    /*
+     * If the request isn't found on the active queue, it may have been
+     * removed to handle a reset or abort request. Display a message and
+     * return.
+     *
+     * Note: Because the structure may still be in use don't attempt
+     * to free the adv_req_t and adv_sgblk_t, if any, structures.
+     */
+    boardp = ASC_BOARDP(shp);
+    if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+        ASC_PRINT2("adv_isr_callback: board %d: scp %x not on active queue\n",
+            boardp->id, (unsigned) scp);
+        return;
+    }
+
+    /*
+     * Check for an underrun condition.
+     */
+    if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0) {
+        ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
+        scsiqp->data_cnt);
+        underrun = ASC_TRUE;
+    }
+
+    /*
+     * 'done_status' contains the command's ending status.
+     */
+    switch (scsiqp->done_status) {
+    case QD_NO_ERROR:
+        ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
+        switch (scsiqp->host_status) {
+        case QHSTA_NO_ERROR:
+            scp->result = 0;
+            break;
+        default:
+            /* QHSTA error occurred. */
+            ASC_DBG1(2, "adv_isr_callback: host_status %x\n",
+                scsiqp->host_status);
+            scp->result = HOST_BYTE(DID_ERROR);
+            break;
+        }
+    /*
+     * If there was an underrun without any other error,
+     * set DID_ERROR to indicate the underrun error.
+     */
+    if (scp->result == 0 && underrun == ASC_TRUE) {
+            scp->result = HOST_BYTE(DID_UNDERRUN);
+    }
+        break;
+
+    case QD_WITH_ERROR:
+        ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
+        switch (scsiqp->host_status) {
+        case QHSTA_NO_ERROR:
+            if (scsiqp->scsi_status == SS_CHK_CONDITION) {
+                ASC_DBG(2, "adv_isr_callback: SS_CHK_CONDITION\n");
+                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+                    sizeof(scp->sense_buffer));
+                /*
+                 * Note: The 'status_byte()' macro used by target drivers
+                 * defined in scsi.h shifts the status byte returned by
+                 * host drivers right by 1 bit. This is why target drivers
+                 * also use right shifted status byte definitions. For
+                 * instance target drivers use CHECK_CONDITION, defined to
+                 * 0x1, instead of the SCSI defined check condition value
+                 * of 0x2. Host drivers are supposed to return the status
+                 * byte as it is defined by SCSI.
+                 */
+                scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+                    STATUS_BYTE(scsiqp->scsi_status);
+            } else {
+                scp->result = STATUS_BYTE(scsiqp->scsi_status);
+            }
+            break;
+
+        default:
+            /* Some other QHSTA error occurred. */
+            ASC_DBG1(2, "adv_isr_callback: host_status %x\n",
+                scsiqp->host_status);
+            scp->result = HOST_BYTE(DID_BAD_TARGET);
+            break;
+        }
+        break;
+
+    case QD_ABORTED_BY_HOST:
+        ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
+        scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+        break;
+
+    default:
+        ASC_PRINT1("adv_isr_callback: done_status %x\n", scsiqp->done_status);
+        scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+        break;
+    }
+
+    /*
+     * If the 'init_tidmask' bit isn't already set for the target and the
+     * current request did not finish with a Selection Timeout, then set
+     * the bit for the target to indicate that a device is present.
+     */
+    if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0 &&
+        scsiqp->done_status == QD_NO_ERROR &&
+        scsiqp->host_status == QHSTA_NO_ERROR) {
+        boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
+    }
+
+    /* 
+     * Because interrupts may be enabled by the 'Scsi_Cmnd' done
+     * function, add the command to the end of the board's done queue.
+     * The done function for the command will be called from
+     * advansys_interrupt().
+     */
+    asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+    /*
+     * Free the adv_sgblk_t structure, if any, by adding it back
+     * to the board free list.
+     */
+    if (reqp->sgblkp != NULL) {
+        reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp;
+        boardp->adv_sgblkp = reqp->sgblkp;
+    }
+
+    /*
+     * Free the adv_req_t structure used with the command by adding
+     * it back to the board free list.
+     */
+    reqp->next_reqp = boardp->adv_reqp;
+    boardp->adv_reqp = reqp;
+
+    ASC_DBG(1, "adv_isr_callback: done\n");
+
+    return;
+}
+
+/*
+ * asc_init_dev() - Narrow Board initialization function. 
+ *
+ * Perform one-time initialization of a device for Asc Library
+ */
+STATIC int
+asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
+{
+    asc_board_t             *boardp;
+    ASC_SCSI_REQ_Q          *scsireqq;
+    ASC_CAP_INFO            *cap_info;
+    ASC_SCSI_INQUIRY        *inquiry;
+    int                     found;
+    ASC_SCSI_BIT_ID_TYPE    save_use_tagged_qng;
+    ASC_SCSI_BIT_ID_TYPE    save_can_tagged_qng;
+    int                     ret;
+#ifdef ADVANSYS_DEBUG
+    ASC_SCSI_BIT_ID_TYPE    tidmask; /* target id bit mask: 1 - 128 */
+#endif /* ADVANSYS_DEBUG */
+
+    ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target);
+
+    /* The host's target id is set in init_tidmask during initialization. */
+    ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target);
+
+    boardp = ASC_BOARDP(scp->host);
+
+    /* Set-up AscInitPollTarget() arguments. */
+    scsireqq = &boardp->scsireqq;
+    memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
+    cap_info = &boardp->cap_info;
+    memset(cap_info, 0, sizeof(ASC_CAP_INFO));
+    inquiry = &boardp->inquiry;
+    memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+
+    /*
+     * AscInitPollBegin() re-initializes these bitmask fields to zero.
+     * Save the current bitmask value and 'or' them back in after calling
+     * AscInitPollEnd() below..
+     */
+    save_use_tagged_qng = asc_dvc_varp->use_tagged_qng;
+    save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng;
+
+    ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n");
+    if (AscInitPollBegin(asc_dvc_varp)) {
+        ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n",
+            boardp->id);
+        return ASC_FALSE;
+    }
+
+    scsireqq->sense_ptr = &scsireqq->sense[0];
+    scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
+    scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+    scsireqq->r1.target_lun = 0;
+    scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
+
+    found = ASC_FALSE;
+    ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
+    switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry,
+        cap_info)) {
+    case ASC_TRUE:
+        found = ASC_TRUE;
+#ifdef ADVANSYS_DEBUG
+        tidmask = ADV_TID_TO_TIDMASK(scp->target);
+        ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
+            cap_info->lba, cap_info->blk_size);
+        ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
+            inquiry->byte0.peri_dvc_type);
+        if (asc_dvc_varp->use_tagged_qng & tidmask) {
+            ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
+                asc_dvc_varp->max_dvc_qng[scp->target]);
+        } else {
+            ASC_DBG(1, "asc_init_dev: command queuing disabled\n");
+        }
+        if (asc_dvc_varp->init_sdtr & tidmask) {
+            ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n");
+        } else {
+            ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n");
+        }
+        /* Set bit means fix disabled. */
+        if (asc_dvc_varp->pci_fix_asyn_xfer & tidmask) {
+            ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n");
+        } else {
+            ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n");
+        }
+#endif /* ADVANSYS_DEBUG */
+        break;
+    case ASC_FALSE:
+        ASC_DBG(1, "asc_init_dev: no device found\n");
+        break;
+    case ASC_ERROR:
+        ASC_PRINT1("asc_init_dev: board %d: AscInitPollTarget() ASC_ERROR\n",
+                boardp->id);
+        break;
+    default:
+        ASC_PRINT2(
+"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n",
+                boardp->id, ret);
+        break;
+    }
+
+    /* Restore previously set bits in the bitmask fields. */
+    asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng;
+    asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng;
+
+    ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n");
+    AscInitPollEnd(asc_dvc_varp);
+
+    ASC_DBG1(1, "asc_init_dev: found %d\n", found); 
+
+    return found;
+}
+
+/*
+ * Search for an AdvanSys PCI device in the PCI configuration space.
+ */
+ASC_INITFUNC(
+STATIC int
+asc_srch_pci_dev(PCI_DEVICE *pciDevice)
+)
+{
+    int ret;
+
+    ASC_DBG(2, "asc_srch_pci_dev: begin\n");
+
+    if (pci_scan_method == -1) {
+        pci_scan_method = asc_scan_method();
+    }
+    pciDevice->type = pci_scan_method;
+    ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type);
+
+    ret = asc_pci_find_dev(pciDevice);
+    ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret);
+    if (ret == PCI_DEVICE_FOUND) {
+        pciDevice->slotNumber = pciDevice->slotFound + 1;
+        pciDevice->startSlot = pciDevice->slotFound + 1;
+    } else {
+        if (pciDevice->bridge > pciDevice->busNumber) {
+            ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n",
+                pciDevice->bridge, pciDevice->busNumber);
+            pciDevice->busNumber++;
+            pciDevice->slotNumber = 0;
+            pciDevice->startSlot = 0;
+            pciDevice->endSlot = 0x0f;
+            ret = asc_srch_pci_dev(pciDevice);
+            ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret);
+        }
+    }
+    ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret);
+    return ret;
+}
+
+/*
+ * Determine the access method to be used for 'pciDevice'.
+ */
+ASC_INITFUNC(
+STATIC uchar
+asc_scan_method(void)
+)
+{
+    ushort      data;
+    PCI_DATA    pciData;
+    uchar       type;
+    uchar       slot;
+
+    ASC_DBG(2, "asc_scan_method: begin\n");
+    memset(&pciData, 0, sizeof(pciData));
+    for (type = 1; type < 3; type++) {
+        pciData.type = type;
+        for (slot = 0; slot < PCI_MAX_SLOT; slot++) {
+            pciData.slot = slot;
+            data = asc_get_cfg_word(&pciData);
+            if ((data != 0xFFFF) && (data != 0x0000)) {
+                ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type);
+                return (type);
+            }
+        }
+    }
+    ASC_DBG1(4, "asc_scan_method: type %d\n", type);
+    return (type);
+}
+
+/*
+ * Check for an AdvanSys PCI device in 'pciDevice'.
+ *
+ * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND.
+ */
+ASC_INITFUNC(
+STATIC int
+asc_pci_find_dev(PCI_DEVICE *pciDevice)
+)
+{
+    PCI_DATA    pciData;
+    ushort      vendorid, deviceid;
+    uchar       classcode, subclass;
+    uchar       lslot;
+
+    ASC_DBG(3, "asc_pci_find_dev: begin\n");
+    pciData.type = pciDevice->type;
+    pciData.bus = pciDevice->busNumber;
+    pciData.func = pciDevice->devFunc;
+    lslot = pciDevice->startSlot;
+    for (; lslot < pciDevice->endSlot; lslot++) {
+        pciData.slot = lslot;
+        pciData.offset = VENDORID_OFFSET;
+        vendorid = asc_get_cfg_word(&pciData);
+        ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid);
+        if (vendorid != 0xffff) {
+            pciData.offset = DEVICEID_OFFSET;
+            deviceid = asc_get_cfg_word(&pciData);
+            ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid);
+            if ((vendorid == ASC_PCI_VENDORID) &&
+                ((deviceid == ASC_PCI_DEVICE_ID_1100) ||
+                 (deviceid == ASC_PCI_DEVICE_ID_1200) ||
+                 (deviceid == ASC_PCI_DEVICE_ID_1300) ||
+                 (deviceid == ASC_PCI_DEVICE_ID_2300))) {
+                pciDevice->slotFound = lslot;
+                ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
+                return PCI_DEVICE_FOUND;
+            } else {
+                pciData.offset = SUBCLASS_OFFSET;
+                subclass = asc_get_cfg_byte(&pciData);
+                pciData.offset = CLASSCODE_OFFSET;
+                classcode = asc_get_cfg_byte(&pciData);
+                if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) &&
+                    (subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) {
+                    pciDevice->bridge++;
+                }
+                ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n",
+                    subclass, classcode);
+            }
+        }
+    }
+    return PCI_DEVICE_NOT_FOUND;
+}
+
+/*
+ * Read PCI configuration data into 'pciConfig'.
+ */
+ASC_INITFUNC(
+STATIC void
+asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
+)
+{
+    PCI_DATA    pciData;
+    uchar       counter;
+    uchar       *localConfig;
+
+    ASC_DBG1(4, "asc_get_pci_cfg: slot found - %d\n ",
+        pciDevice->slotFound);
+
+    pciData.type = pciDevice->type;
+    pciData.bus = pciDevice->busNumber;
+    pciData.slot = pciDevice->slotFound;
+    pciData.func = pciDevice->devFunc;
+    localConfig = (uchar *) pciConfig;
+
+    for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) {
+        pciData.offset = counter;
+        *localConfig = asc_get_cfg_byte(&pciData);
+        ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig);
+        localConfig++;
+    }
+    ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter);
+}
+
+/*
+ * Read a word (16 bits) from the PCI configuration space.
+ *
+ * The configuration mechanism is checked for the correct access method.
  */
+ASC_INITFUNC(
 STATIC ushort
 asc_get_cfg_word(PCI_DATA *pciData)
+)
 {
-	ushort	tmp;
-	ulong	address;
-	ulong	lbus = pciData->bus;
-	ulong	lslot = pciData->slot;
-	ulong	lfunc = pciData->func;
-	uchar	t2CFA, t2CF8;
-	ulong	t1CF8, t1CFC;
-
-	ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n",
-		pciData->type, lbus, lslot, lfunc);
-
-	/*
-	 * Check type of configuration mechanism.
-	 */
-	if (pciData->type == 2) {
-		/*
-		 * Save registers to be restored later.
-		 */
-		t2CFA = inp(0xCFA);	/* save PCI bus register */
-		t2CF8 = inp(0xCF8);	/* save config space enable register */
-
-		/*
-		 * Write the bus and enable registers.
-		 */
-		/* set for type 1 cycle, if needed */
-		outp(0xCFA, pciData->bus);
-		/* set the function number */
-		outp(0xCF8, 0x10 | (pciData->func << 1)) ;
-
-		/*
-		 * Read the configuration space type 2 locations.
-		 */
-		tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset));
-
-		outp(0xCFA, t2CFA);	/* save PCI bus register */
-		outp(0xCF8, t2CF8);	/* save config space enable register */
-	} else {
-		/*
-		 * Type 1 or 3 configuration mechanism.
-		 *
-		 * Save the CONFIG_ADDRESS and CONFIG_DATA register values.
-		 */
-		t1CF8 = inpl(0xCF8);
-		t1CFC = inpl(0xCFC);
-
-		/*
-		 * enable <31>, bus = <23:16>, slot = <15:11>,
-		 * func = <10:8>, reg = <7:2>
-		 */
-		address = (ulong) ((lbus << 16) | (lslot << 11) |
-			(lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
-
-		/*
-		 * Write out the address to CONFIG_ADDRESS.
-		 */
-		outpl(0xCF8, address);
-
-		/*
-		 * Read in word from CONFIG_DATA.
-		 */
-		tmp = (ushort) ((inpl(0xCFC) >>
-				 ((pciData->offset & 2) * 8)) & 0xFFFF);
-
-		/*
-		 * Restore registers.
-		 */
-		outpl(0xCF8, t1CF8);
-		outpl(0xCFC, t1CFC);
-	}
-	ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp);
-	return tmp;
+    ushort   tmp;
+    ulong    address;
+    ulong    lbus = pciData->bus;
+    ulong    lslot = pciData->slot;
+    ulong    lfunc = pciData->func;
+    uchar    t2CFA, t2CF8;
+    ulong    t1CF8, t1CFC;
+
+    ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n",
+        pciData->type, lbus, lslot, lfunc);
+
+    /*
+     * Check type of configuration mechanism.
+     */
+    if (pciData->type == 2) {
+        /*
+         * Save registers to be restored later.
+         */
+        t2CFA = inp(0xCFA);    /* save PCI bus register */
+        t2CF8 = inp(0xCF8);    /* save config space enable register */
+
+        /*
+         * Write the bus and enable registers.
+         */
+        /* set for type 1 cycle, if needed */
+        outp(0xCFA, pciData->bus);
+        /* set the function number */
+        outp(0xCF8, 0x10 | (pciData->func << 1)) ;
+
+        /*
+         * Read the configuration space type 2 locations.
+         */
+        tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset));
+
+        outp(0xCFA, t2CFA);    /* save PCI bus register */
+        outp(0xCF8, t2CF8);    /* save config space enable register */
+    } else {
+        /*
+         * Type 1 or 3 configuration mechanism.
+         *
+         * Save the CONFIG_ADDRESS and CONFIG_DATA register values.
+         */
+        t1CF8 = inpl(0xCF8);
+        t1CFC = inpl(0xCFC);
+
+        /*
+         * enable <31>, bus = <23:16>, slot = <15:11>,
+         * func = <10:8>, reg = <7:2>
+         */
+        address = (ulong) ((lbus << 16) | (lslot << 11) |
+            (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
+
+        /*
+         * Write out the address to CONFIG_ADDRESS.
+         */
+        outpl(0xCF8, address);
+
+        /*
+         * Read in word from CONFIG_DATA.
+         */
+        tmp = (ushort) ((inpl(0xCFC) >>
+                 ((pciData->offset & 2) * 8)) & 0xFFFF);
+
+        /*
+         * Restore registers.
+         */
+        outpl(0xCF8, t1CF8);
+        outpl(0xCFC, t1CFC);
+    }
+    ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp);
+    return tmp;
 }
 
 /*
@@ -5249,162 +7606,166 @@
  *
  * The configuration mechanism is checked for the correct access method.
  */
+ASC_INITFUNC(
 STATIC uchar
 asc_get_cfg_byte(PCI_DATA *pciData)
+)
 {
-	uchar tmp;
-	ulong address;
-	ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
-	uchar t2CFA, t2CF8;
-	ulong t1CF8, t1CFC;
-
-	ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type);
-
-	/*
-	 * Check type of configuration mechanism.
-	 */
-	if (pciData->type == 2) {
-		/*
-		 * Save registers to be restored later.
-		 */
-		t2CFA = inp(0xCFA);	/* save PCI bus register */
-		t2CF8 = inp(0xCF8);	/* save config space enable register */
-
-		/*
-		 * Write the bus and enable registers.
-		 */
-		/* set for type 1 cycle, if needed */
-		outp(0xCFA, pciData->bus);
-		/* set the function number */
-		outp(0xCF8, 0x10 | (pciData->func << 1));
-
-		/*
-		 * Read configuration space type 2 locations.
-		 */
-		tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset));
-
-		/*
-		 * Restore registers.
-		 */
-		outp(0xCF8, t2CF8);	/* restore the enable register */
-		outp(0xCFA, t2CFA);	/* restore PCI bus register */
-	} else {
-		/*
-		 * Type 1 or 3 configuration mechanism.
-		 *
-		 * Save CONFIG_ADDRESS and CONFIG_DATA register values.
-		 */
-		t1CF8 = inpl(0xCF8);
-		t1CFC = inpl(0xCFC);
-
-		/*
-		 * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
-		 * reg = <7:2>
-		 */
-		address = (ulong) ((lbus << 16) | (lslot << 11) |
-			(lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
-
-		/*
-		 * Write out address to CONFIG_ADDRESS.
-		 */
-		outpl(0xCF8, address);
-
-		/*
-		 * Read in word from CONFIG_DATA.
-		 */
-		tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF);
-
-		/*
-		 * Restore registers.
-		 */
-		outpl(0xCF8, t1CF8);
-		outpl(0xCFC, t1CFC);
-	}
-	ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp);
-	return tmp;
+    uchar tmp;
+    ulong address;
+    ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
+    uchar t2CFA, t2CF8;
+    ulong t1CF8, t1CFC;
+
+    ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type);
+
+    /*
+     * Check type of configuration mechanism.
+     */
+    if (pciData->type == 2) {
+        /*
+         * Save registers to be restored later.
+         */
+        t2CFA = inp(0xCFA);    /* save PCI bus register */
+        t2CF8 = inp(0xCF8);    /* save config space enable register */
+
+        /*
+         * Write the bus and enable registers.
+         */
+        /* set for type 1 cycle, if needed */
+        outp(0xCFA, pciData->bus);
+        /* set the function number */
+        outp(0xCF8, 0x10 | (pciData->func << 1));
+
+        /*
+         * Read configuration space type 2 locations.
+         */
+        tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset));
+
+        /*
+         * Restore registers.
+         */
+        outp(0xCF8, t2CF8);    /* restore the enable register */
+        outp(0xCFA, t2CFA);    /* restore PCI bus register */
+    } else {
+        /*
+         * Type 1 or 3 configuration mechanism.
+         *
+         * Save CONFIG_ADDRESS and CONFIG_DATA register values.
+         */
+        t1CF8 = inpl(0xCF8);
+        t1CFC = inpl(0xCFC);
+
+        /*
+         * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
+         * reg = <7:2>
+         */
+        address = (ulong) ((lbus << 16) | (lslot << 11) |
+            (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
+
+        /*
+         * Write out address to CONFIG_ADDRESS.
+         */
+        outpl(0xCF8, address);
+
+        /*
+         * Read in word from CONFIG_DATA.
+         */
+        tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF);
+
+        /*
+         * Restore registers.
+         */
+        outpl(0xCF8, t1CF8);
+        outpl(0xCFC, t1CFC);
+    }
+    ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp);
+    return tmp;
 }
 
 /*
  * Write a byte to the PCI configuration space.
  */
-void
+ASC_INITFUNC(
+STATIC void
 asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
+)
 {
-	ulong tmpl;
-	ulong address;
-	ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
-	uchar t2CFA, t2CF8;
-	ulong t1CF8, t1CFC;
-
-	ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n",
-		pciData->type, byte_data);
-
-	/*
-	 * Check type of configuration mechanism.
-	 */
-	if (pciData->type == 2) {
-
-		/*
-		 * Save registers to be restored later.
-		 */
-		t2CFA = inp(0xCFA);	/* save PCI bus register */
-		t2CF8 = inp(0xCF8);	/* save config space enable register */
-
-		/*
-		 * Write bus and enable registers.
-		 */
-		outp(0xCFA, pciData->bus);
-
-		/*
-		 * Set the function number.
-		 */
-		outp(0xCF8, 0x10 | (pciData->func << 1));
-
-		/*
-		 * Write the configuration space type 2 locations.
-		 */
-		outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data);
-
-		/*
-		 * Restore registers.
-		 */
-		outp(0xCF8, t2CF8);	/* restore the enable register */
-		outp(0xCFA, t2CFA);	/* restore PCI bus register	*/
-	} else {
-
-		/*
-		 * Type 1 or 3 configuration mechanism.
-		 *
-		 * Save the CONFIG_ADDRESS and CONFIG_DATA register values.
-		 */
-		t1CF8 = inpl(0xCF8);
-		t1CFC = inpl(0xCFC);
-
-		/*
-		 * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
-		 * reg = <7:2>
-		 */
-		address = (ulong) ((lbus << 16) | (lslot << 11) | (lfunc << 8) |
-				(pciData->offset & 0xFC) | 0x80000000L);
-		/*
-		 * Write out address to CONFIG_ADDRESS.
-		 */
-		outpl(0xCF8, address);
-
-		/*
-		 * Write double word to CONFIG_DATA preserving the bytes
-		 * in the double not written.
-		 */
-		tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8));
-		outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8)));
-
-		/*
-		 * Restore registers.
-		 */
-		outpl(0xCF8, t1CF8);
-		outpl(0xCFC, t1CFC);
-	}
-	ASC_DBG(4, "asc_put_cfg_byte: end\n");
+    ulong tmpl;
+    ulong address;
+    ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
+    uchar t2CFA, t2CF8;
+    ulong t1CF8, t1CFC;
+
+    ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n",
+        pciData->type, byte_data);
+
+    /*
+     * Check type of configuration mechanism.
+     */
+    if (pciData->type == 2) {
+
+        /*
+         * Save registers to be restored later.
+         */
+        t2CFA = inp(0xCFA);    /* save PCI bus register */
+        t2CF8 = inp(0xCF8);    /* save config space enable register */
+
+        /*
+         * Write bus and enable registers.
+         */
+        outp(0xCFA, pciData->bus);
+
+        /*
+         * Set the function number.
+         */
+        outp(0xCF8, 0x10 | (pciData->func << 1));
+
+        /*
+         * Write the configuration space type 2 locations.
+         */
+        outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data);
+
+        /*
+         * Restore registers.
+         */
+        outp(0xCF8, t2CF8);    /* restore the enable register */
+        outp(0xCFA, t2CFA);    /* restore PCI bus register    */
+    } else {
+
+        /*
+         * Type 1 or 3 configuration mechanism.
+         *
+         * Save the CONFIG_ADDRESS and CONFIG_DATA register values.
+         */
+        t1CF8 = inpl(0xCF8);
+        t1CFC = inpl(0xCFC);
+
+        /*
+         * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
+         * reg = <7:2>
+         */
+        address = (ulong) ((lbus << 16) | (lslot << 11) | (lfunc << 8) |
+                (pciData->offset & 0xFC) | 0x80000000L);
+        /*
+         * Write out address to CONFIG_ADDRESS.
+         */
+        outpl(0xCF8, address);
+
+        /*
+         * Write double word to CONFIG_DATA preserving the bytes
+         * in the double not written.
+         */
+        tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8));
+        outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8)));
+
+        /*
+         * Restore registers.
+         */
+        outpl(0xCF8, t1CF8);
+        outpl(0xCFC, t1CFC);
+    }
+    ASC_DBG(4, "asc_put_cfg_byte: end\n");
 }
 
 /*
@@ -5415,51 +7776,51 @@
  *
  * 'REQPNEXT(reqp)' returns reqp's next pointer.
  */
-void
+STATIC void
 asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
 {
-	int		tid;
+    int        tid;
 
-	ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
-		(unsigned) ascq, (unsigned) reqp, flag);
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ASC_ASSERT(reqp != NULL);
-	ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
-	tid = REQPTID(reqp);
-	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
-	if (flag == ASC_FRONT) {
-		REQPNEXT(reqp) = ascq->q_first[tid];
-		ascq->q_first[tid] = reqp;
-		/* If the queue was empty, set the last pointer. */
-		if (ascq->q_last[tid] == NULL) {
-			ascq->q_last[tid] = reqp;
-		}
-	} else { /* ASC_BACK */
-		if (ascq->q_last[tid] != NULL) {
-			REQPNEXT(ascq->q_last[tid]) = reqp;
-		}
-		ascq->q_last[tid] = reqp;
-		REQPNEXT(reqp) = NULL;
-		/* If the queue was empty, set the first pointer. */
-		if (ascq->q_first[tid] == NULL) {
-			ascq->q_first[tid] = reqp;
-		}
-	}
-	/* The queue has at least one entry, set its bit. */
-	ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
+    ASC_DBG3(3, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
+        (unsigned) ascq, (unsigned) reqp, flag);
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_ASSERT(reqp != NULL);
+    ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+    tid = REQPTID(reqp);
+    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+    if (flag == ASC_FRONT) {
+        REQPNEXT(reqp) = ascq->q_first[tid];
+        ascq->q_first[tid] = reqp;
+        /* If the queue was empty, set the last pointer. */
+        if (ascq->q_last[tid] == NULL) {
+            ascq->q_last[tid] = reqp;
+        }
+    } else { /* ASC_BACK */
+        if (ascq->q_last[tid] != NULL) {
+            REQPNEXT(ascq->q_last[tid]) = reqp;
+        }
+        ascq->q_last[tid] = reqp;
+        REQPNEXT(reqp) = NULL;
+        /* If the queue was empty, set the first pointer. */
+        if (ascq->q_first[tid] == NULL) {
+            ascq->q_first[tid] = reqp;
+        }
+    }
+    /* The queue has at least one entry, set its bit. */
+    ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
 #ifdef ADVANSYS_STATS
-	/* Maintain request queue statistics. */
-	ascq->q_tot_cnt[tid]++;
-	ascq->q_cur_cnt[tid]++;
-	if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
-		ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
-		ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n",
-			tid, ascq->q_max_cnt[tid]);
-	}
-	REQPTIME(reqp) = REQTIMESTAMP();
+    /* Maintain request queue statistics. */
+    ascq->q_tot_cnt[tid]++;
+    ascq->q_cur_cnt[tid]++;
+    if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
+        ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
+        ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
+            tid, ascq->q_max_cnt[tid]);
+    }
+    REQPTIME(reqp) = REQTIMESTAMP();
 #endif /* ADVANSYS_STATS */
-	ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp);
-	return;
+    ASC_DBG1(3, "asc_enqueue: reqp %x\n", (unsigned) reqp);
+    return;
 }
 
 /*
@@ -5469,32 +7830,32 @@
  *
  * 'REQPNEXT(reqp)' returns reqp's next pointer.
  */
-REQP
+STATIC REQP
 asc_dequeue(asc_queue_t *ascq, int tid)
 {
-	REQP	reqp;
+    REQP    reqp;
 
-	ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
-	if ((reqp = ascq->q_first[tid]) != NULL) {
-		ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		ascq->q_first[tid] = REQPNEXT(reqp);
-		/* If the queue is empty, clear its bit and the last pointer. */
-		if (ascq->q_first[tid] == NULL) {
-			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
-			ASC_ASSERT(ascq->q_last[tid] == reqp);
-			ascq->q_last[tid] = NULL;
-		}
+    ASC_DBG2(3, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+    if ((reqp = ascq->q_first[tid]) != NULL) {
+        ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
+        ascq->q_first[tid] = REQPNEXT(reqp);
+        /* If the queue is empty, clear its bit and the last pointer. */
+        if (ascq->q_first[tid] == NULL) {
+            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+            ASC_ASSERT(ascq->q_last[tid] == reqp);
+            ascq->q_last[tid] = NULL;
+        }
 #ifdef ADVANSYS_STATS
-		/* Maintain request queue statistics. */
-		ascq->q_cur_cnt[tid]--;
-		ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
-		REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
+        /* Maintain request queue statistics. */
+        ascq->q_cur_cnt[tid]--;
+        ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+        REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
 #endif /* ADVANSYS_STATS */
-	}
-	ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp);
-	return reqp;
+    }
+    ASC_DBG1(3, "asc_dequeue: reqp %x\n", (unsigned) reqp);
+    return reqp;
 }
 
 /*
@@ -5517,75 +7878,75 @@
  * Unfortunately collecting queuing time statistics adds overhead to
  * the function that isn't inherent to the function's algorithm.
  */
-REQP
+STATIC REQP
 asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
 {
-	REQP	firstp, lastp;
-	int		i;
+    REQP    firstp, lastp;
+    int     i;
+
+    ASC_DBG2(3, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
 
-	ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ASC_MAX_TID));
-
-	/*
-	 * If 'tid' is not ASC_TID_ALL, return requests only for
-	 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
-	 * requests for all tids.
-	 */
-	if (tid != ASC_TID_ALL) {
-		/* Return all requests for the specified 'tid'. */
-		if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) {
-			/* List is empty; Set first and last return pointers to NULL. */
-			firstp = lastp = NULL;
-		} else {
-			firstp = ascq->q_first[tid];
-			lastp = ascq->q_last[tid];
-			ascq->q_first[tid] = ascq->q_last[tid] = NULL;
-			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+    /*
+     * If 'tid' is not ASC_TID_ALL, return requests only for
+     * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
+     * requests for all tids.
+     */
+    if (tid != ASC_TID_ALL) {
+        /* Return all requests for the specified 'tid'. */
+        if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
+            /* List is empty; Set first and last return pointers to NULL. */
+            firstp = lastp = NULL;
+        } else {
+            firstp = ascq->q_first[tid];
+            lastp = ascq->q_last[tid];
+            ascq->q_first[tid] = ascq->q_last[tid] = NULL;
+            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
 #ifdef ADVANSYS_STATS
-			{
-				REQP reqp;
-				ascq->q_cur_cnt[tid] = 0;
-				for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
-					REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid);
-				}
-			}
+            {
+                REQP reqp;
+                ascq->q_cur_cnt[tid] = 0;
+                for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+                    REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid);
+                }
+            }
 #endif /* ADVANSYS_STATS */
-		}
-	} else {
-		/* Return all requests for all tids. */
-		firstp = lastp = NULL;
-		for (i = 0; i <= ASC_MAX_TID; i++) {
-			if (ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
-				if (firstp == NULL) {
-					firstp = ascq->q_first[i];
-					lastp = ascq->q_last[i];
-				} else {
-					ASC_ASSERT(lastp != NULL);
-					REQPNEXT(lastp) = ascq->q_first[i];
-					lastp = ascq->q_last[i];
-				}
-				ascq->q_first[i] = ascq->q_last[i] = NULL;
-				ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+        }
+    } else {
+        /* Return all requests for all tids. */
+        firstp = lastp = NULL;
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
+                if (firstp == NULL) {
+                    firstp = ascq->q_first[i];
+                    lastp = ascq->q_last[i];
+                } else {
+                    ASC_ASSERT(lastp != NULL);
+                    REQPNEXT(lastp) = ascq->q_first[i];
+                    lastp = ascq->q_last[i];
+                }
+                ascq->q_first[i] = ascq->q_last[i] = NULL;
+                ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
 #ifdef ADVANSYS_STATS
-				ascq->q_cur_cnt[i] = 0;
+                ascq->q_cur_cnt[i] = 0;
 #endif /* ADVANSYS_STATS */
-			}
-		}
+            }
+        }
 #ifdef ADVANSYS_STATS
-		{
-			REQP reqp;
-			for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
-				REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->target);
-			}
-		}
+        {
+            REQP reqp;
+            for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+                REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->target);
+            }
+        }
 #endif /* ADVANSYS_STATS */
-	}
-	if (lastpp) {
-		*lastpp = lastp;
-	}
-	ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
-	return firstp;
+    }
+    if (lastpp) {
+        *lastpp = lastp;
+    }
+    ASC_DBG1(3, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
+    return firstp;
 }
 
 /*
@@ -5598,98 +7959,98 @@
  * Return ASC_TRUE if the command was found and removed,
  * otherwise return ASC_FALSE.
  */
-int
+STATIC int
 asc_rmqueue(asc_queue_t *ascq, REQP reqp)
 {
-	REQP		currp, prevp;
-	int			tid;
-	int			ret = ASC_FALSE;
-
-	ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %x\n",
-		(unsigned) ascq, (unsigned) reqp);
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ASC_ASSERT(reqp != NULL);
-
-	tid = REQPTID(reqp);
-	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
-
-	/*
-	 * Handle the common case of 'reqp' being the first
-	 * entry on the queue.
-	 */
-	if (reqp == ascq->q_first[tid]) {
-		ret = ASC_TRUE;
-		ascq->q_first[tid] = REQPNEXT(reqp);
-		/* If the queue is now empty, clear its bit and the last pointer. */
-		if (ascq->q_first[tid] == NULL) {
-			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
-			ASC_ASSERT(ascq->q_last[tid] == reqp);
-			ascq->q_last[tid] = NULL;
-		}
-	} else if (ascq->q_first[tid] != NULL) {
-		ASC_ASSERT(ascq->q_last[tid] != NULL);
-		/*
-		 * Because the case of 'reqp' being the first entry has been
-		 * handled above and it is known the queue is not empty, if
-		 * 'reqp' is found on the queue it is guaranteed the queue will
-		 * not become empty and that 'q_first[tid]' will not be changed.
-		 *
-		 * Set 'prevp' to the first entry, 'currp' to the second entry,
-		 * and search for 'reqp'.
-		 */
-		for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
-			 currp; prevp = currp, currp = REQPNEXT(currp)) {
-			if (currp == reqp) {
-				ret = ASC_TRUE;
-				REQPNEXT(prevp) = REQPNEXT(currp);
-				REQPNEXT(reqp) = NULL;
-				if (ascq->q_last[tid] == reqp) {
-					ascq->q_last[tid] = prevp;
-				}
-				break;
-			}
-		}
-	}
+    REQP        currp, prevp;
+    int         tid;
+    int         ret = ASC_FALSE;
+
+    ASC_DBG2(3, "asc_rmqueue: ascq %x, reqp %x\n",
+        (unsigned) ascq, (unsigned) reqp);
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_ASSERT(reqp != NULL);
+
+    tid = REQPTID(reqp);
+    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+
+    /*
+     * Handle the common case of 'reqp' being the first
+     * entry on the queue.
+     */
+    if (reqp == ascq->q_first[tid]) {
+        ret = ASC_TRUE;
+        ascq->q_first[tid] = REQPNEXT(reqp);
+        /* If the queue is now empty, clear its bit and the last pointer. */
+        if (ascq->q_first[tid] == NULL) {
+            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+            ASC_ASSERT(ascq->q_last[tid] == reqp);
+            ascq->q_last[tid] = NULL;
+        }
+    } else if (ascq->q_first[tid] != NULL) {
+        ASC_ASSERT(ascq->q_last[tid] != NULL);
+        /*
+         * Because the case of 'reqp' being the first entry has been
+         * handled above and it is known the queue is not empty, if
+         * 'reqp' is found on the queue it is guaranteed the queue will
+         * not become empty and that 'q_first[tid]' will not be changed.
+         *
+         * Set 'prevp' to the first entry, 'currp' to the second entry,
+         * and search for 'reqp'.
+         */
+        for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
+             currp; prevp = currp, currp = REQPNEXT(currp)) {
+            if (currp == reqp) {
+                ret = ASC_TRUE;
+                REQPNEXT(prevp) = REQPNEXT(currp);
+                REQPNEXT(reqp) = NULL;
+                if (ascq->q_last[tid] == reqp) {
+                    ascq->q_last[tid] = prevp;
+                }
+                break;
+            }
+        }
+    }
 #ifdef ADVANSYS_STATS
-	/* Maintain request queue statistics. */
-	if (ret == ASC_TRUE) {
-		ascq->q_cur_cnt[tid]--;
-		REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
-	}
-	ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+    /* Maintain request queue statistics. */
+    if (ret == ASC_TRUE) {
+        ascq->q_cur_cnt[tid]--;
+        REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
+    }
+    ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
-	ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
-	return ret;
+    ASC_DBG2(3, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
+    return ret;
 }
 
 /*
  * If the specified 'REQP' is queued on the specified queue for
  * the specified target device, return ASC_TRUE.
  */
-int
+STATIC int
 asc_isqueued(asc_queue_t *ascq, REQP reqp)
 {
-	REQP		treqp;
-	int			tid;
-	int			ret = ASC_FALSE;
-
-	ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n",
-		(unsigned) ascq, (unsigned) reqp);
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ASC_ASSERT(reqp != NULL);
-
-	tid = REQPTID(reqp);
-	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
-
-	for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) {
-		ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		if (treqp == reqp) {
-			ret = ASC_TRUE;
-			break;
-		}
-	}
-	ASC_DBG1(1, "asc_isqueued: ret %x\n", ret);
-	return ret;
+    REQP        treqp;
+    int            tid;
+    int            ret = ASC_FALSE;
+
+    ASC_DBG2(3, "asc_isqueued: ascq %x, reqp %x\n",
+        (unsigned) ascq, (unsigned) reqp);
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    ASC_ASSERT(reqp != NULL);
+
+    tid = REQPTID(reqp);
+    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+
+    for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) {
+        ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
+        if (treqp == reqp) {
+            ret = ASC_TRUE;
+            break;
+        }
+    }
+    ASC_DBG1(3, "asc_isqueued: ret %x\n", ret);
+    return ret;
 }
 
 /*
@@ -5697,37 +8058,38 @@
  *
  * Calls asc_execute_scsi_cmnd() to execute a REQP/Scsi_Cmnd.
  */
-void
+STATIC void
 asc_execute_queue(asc_queue_t *ascq)
 {
-	ASC_SCSI_BIT_ID_TYPE	scan_tidmask;
-	REQP					reqp;
-	int						i;
-
-	ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq);
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	/*
-	 * Execute queued commands for devices attached to
-	 * the current board in round-robin fashion.
-	 */
-	scan_tidmask = ascq->q_tidmask;
-	do {
-		for (i = 0; i <= ASC_MAX_TID; i++) {
-			if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
-				if ((reqp = asc_dequeue(ascq, i)) == NULL) {
-					scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
-				} else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp)
-							== ASC_BUSY) {
-					scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
-					/* Put the request back at front of the list. */
-					asc_enqueue(ascq, reqp, ASC_FRONT);
-				}
-			}
-		}
-	} while (scan_tidmask);
-	return;
+    ADV_SCSI_BIT_ID_TYPE    scan_tidmask;
+    REQP                    reqp;
+    int                     i;
+
+    ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq);
+    ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+    /*
+     * Execute queued commands for devices attached to
+     * the current board in round-robin fashion.
+     */
+    scan_tidmask = ascq->q_tidmask;
+    do {
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
+                if ((reqp = asc_dequeue(ascq, i)) == NULL) {
+                    scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+                } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp)
+                            == ASC_BUSY) {
+                    scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+                    /* Put the request back at front of the list. */
+                    asc_enqueue(ascq, reqp, ASC_FRONT);
+                }
+            }
+        }
+    } while (scan_tidmask);
+    return;
 }
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 /*
  * asc_prt_board_devices()
  *
@@ -5742,39 +8104,181 @@
 STATIC int
 asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	asc_board_t		*boardp;
-	int				leftlen;
-	int				totlen;
-	int				len;
-	int				i;
-
-	boardp = ASC_BOARDP(shp);
-	leftlen = cplen;
-	totlen = len = 0;
+    asc_board_t        *boardp;
+    int                leftlen;
+    int                totlen;
+    int                len;
+    int                chip_scsi_id;
+    int                i;
+
+    boardp = ASC_BOARDP(shp);
+    leftlen = cplen;
+    totlen = len = 0;
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 "\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no);
-	ASC_PRT_NEXT();
+    ASC_PRT_NEXT();
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+    } else {
+        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+    }
+
+    len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
+            len = asc_prt_line(cp, leftlen, " %X,", i);
+            ASC_PRT_NEXT();
+        }
+    }
+    len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
+    ASC_PRT_NEXT();
+
+    return totlen;
+}
+
+/*
+ * Display Wide Board BIOS Information.
+ */
+STATIC int
+asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t        *boardp;
+    int                leftlen;
+    int                totlen;
+    int                len;
+    int                upgrade = ASC_FALSE;
+    ushort             major, minor, letter;
+
+    boardp = ASC_BOARDP(shp);
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
+    ASC_PRT_NEXT();
+
+    /*
+     * If the BIOS saved a valid signature, then fill in
+     * the BIOS code segment base address.
+     */
+    if (boardp->bios_signature != 0x55AA) {
+        len = asc_prt_line(cp, leftlen, "Pre-3.1\n");
+        ASC_PRT_NEXT();
+        upgrade = ASC_TRUE;
+    } else {
+        major = (boardp->bios_version >> 12) & 0xF;
+        minor = (boardp->bios_version >> 8) & 0xF;
+        letter = (boardp->bios_version & 0xFF);
+
+        len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
+            major, minor, letter >= 26 ? '?' : letter + 'A');
+        ASC_PRT_NEXT();
+
+        /* Current available ROM BIOS release is 3.1E. */
+        if (major < 3 || (major <= 3 && minor < 1) ||
+            (major <= 3 && minor <= 1 && letter < ('E'- 'A'))) {
+            upgrade = ASC_TRUE;
+        }
+    }
+    if (upgrade == ASC_TRUE) {
+        len = asc_prt_line(cp, leftlen,
+"Newer version of ROM BIOS available: ftp://ftp.advansys.com/pub\n");
+            ASC_PRT_NEXT();
+    }
+
+    return totlen;
+}
+
+/*
+ * Add serial number to information bar if signature AAh
+ * is found in at bit 15-9 (7 bits) of word 1.
+ *
+ * Serial Number consists 12 alpha-numeric digits.
+ *
+ *       1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
+ *       2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
+ *     3-4 - Product ID (0-99)        Word0: 10-0 (11 bits)
+ *       5 - Product revision         Word0:  "         "
+ *
+ *         Signature                Word1: 15-9 (7 bits)
+ *       6 - Year (4-9)               Word1: 8-6 (3 bits)
+ *     7-8 - Week of the year         Word1: 5-0 (6 bits)
+ *
+ *    9-12 - Serial Number            Word2: 15-0 (16 bits)
+ *
+ * Note 1: Only production cards will have a serial number.
+ *
+ * Note 2: Signature is most significant 7 bits (0xFE).
+ *
+ * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
+ */
+STATIC int
+asc_get_eeprom_string(ushort *serialnum, uchar *cp)
+{
+    ushort      w, num;
 
-	len = asc_prt_line(cp, leftlen, "Target Ids Detected:");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if (boardp->asc_dvc_cfg.chip_scsi_id == i) {
-			continue;
-		} else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
-			len = asc_prt_line(cp, leftlen, " %d,", i);
-			ASC_PRT_NEXT();
-		}
-	}
-	len = asc_prt_line(cp, leftlen, " (%d=Host Adapter)\n",
-					   boardp->asc_dvc_cfg.chip_scsi_id);
-	ASC_PRT_NEXT();
+    if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) {
+        return ASC_FALSE;
+    } else {
+        /*
+         * First word - 6 digits.
+         */
+        w = serialnum[0];
+
+        /* Product type - 1st digit. */
+        *cp++ = 'A' + ((w & 0xE000) >> 13);
+
+        /* Manufacturing location - 2nd digit. */
+        *cp++ = 'A' + ((w & 0x1C00) >> 10);
+
+        /* Product ID - 3rd, 4th digits. */
+        num = w & 0x3FF;
+        *cp++ = '0' + (num / 100);
+        num %= 100;
+        *cp++ = '0' + (num / 10);
+
+        /* Product revision - 5th digit. */
+        *cp++ = 'A' + (num % 10);
+
+        /*
+         * Second word
+         */
+        w = serialnum[1];
+
+        /* Year - 6th digit. */
+        *cp++ = '0' + ((w & 0x1C0) >> 6);
+
+        /* Week of year - 7th, 8th digits. */
+        num = w & 0x003F;
+        *cp++ = '0' + num / 10;
+        num %= 10;
+        *cp++ = '0' + num;
+
+        /*
+         * Third word
+         */
+        w = serialnum[2];
+
+        /* Serial number - 9th digit. */
+        *cp++ = 'A' + (w / 1000);
+
+        /* 10th, 11th, 12th digits. */
+        num = w % 1000;
+        *cp++ = '0' + num / 100;
+        num %= 100;
+        *cp++ = '0' + num / 10;
+        num %= 10;
+        *cp++ = '0' + num;
 
- 	return totlen;
+        *cp = '\0';     /* Null Terminate the string. */
+        return ASC_TRUE;
+    }
 }
 
 /*
- * asc_prt_board_eeprom()
+ * asc_prt_asc_board_eeprom()
  *
  * Print board EEPROM configuration.
  *
@@ -5785,89 +8289,123 @@
  * 'cplen' characters will be copied to 'cp'.
  */
 STATIC int
-asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	asc_board_t		*boardp;
-	ASC_DVC_VAR		*asc_dvc_varp;
-	int				leftlen;
-	int				totlen;
-	int				len;
-	ASCEEP_CONFIG	*ep;
-	int				i;
-	int				isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
-
-	boardp = ASC_BOARDP(shp);
-	asc_dvc_varp = &boardp->asc_dvc_var;
-	ep = &boardp->eep_config;
+    asc_board_t        *boardp;
+    ASC_DVC_VAR        *asc_dvc_varp;
+    int                leftlen;
+    int                totlen;
+    int                len;
+    ASCEEP_CONFIG      *ep;
+    int                i;
+    int                isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+    uchar              serialstr[13];
+
+    boardp = ASC_BOARDP(shp);
+    asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+    ep = &boardp->eep_config.asc_eep;
 
-	leftlen = cplen;
-	totlen = len = 0;
+    leftlen = cplen;
+    totlen = len = 0;
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
-	ASC_PRT_NEXT();
+    ASC_PRT_NEXT();
+
+    if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) ==
+        ASC_TRUE) {
+        len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
+        ASC_PRT_NEXT();
+    } else {
+        if (ep->adapter_info[5] == 0xBB) {
+            len = asc_prt_line(cp, leftlen,
+                " Default Settings Used for EEPROM-less Adapter.\n");
+            ASC_PRT_NEXT();
+        } else {
+            len = asc_prt_line(cp, leftlen,
+                " Serial Number Signature Not Present.\n");
+            ASC_PRT_NEXT();
+        }
+    }
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-		ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng);
-	ASC_PRT_NEXT();
+        ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" cntl %x, no_scam %x\n",
+        ep->cntl, ep->no_scam);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Target ID:           ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %d", i);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 " Disconnects:         ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 " Command Queuing:     ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 " Start Motor:         ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 " Synchronous Transfer:");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-	if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
-		len = asc_prt_line(cp, leftlen,
+    if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+        len = asc_prt_line(cp, leftlen,
 " Host ISA DMA speed:   %d MB/S\n",
-			isa_dma_speed[ep->isa_dma_speed]);
-		ASC_PRT_NEXT();
-	}
+            isa_dma_speed[ep->isa_dma_speed]);
+        ASC_PRT_NEXT();
+    }
 
- 	return totlen;
+     return totlen;
 }
 
 /*
- * asc_prt_driver_conf()
+ * asc_prt_adv_board_eeprom()
+ *
+ * Print board EEPROM configuration.
  *
  * Note: no single line should be greater than ASC_PRTLINE_SIZE,
  * cf. asc_prt_line().
@@ -5876,117 +8414,283 @@
  * 'cplen' characters will be copied to 'cp'.
  */
 STATIC int
-asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	asc_board_t			*boardp;
-	int					leftlen;
-	int					totlen;
-	int					len;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-	int					i;
-#endif /* version >= v1.3.89 */
+    asc_board_t        *boardp;
+    ADV_DVC_VAR        *adv_dvc_varp;
+    int                leftlen;
+    int                totlen;
+    int                len;
+    int                i;
+    char               *termstr;
+    uchar              serialstr[13];
+    ADVEEP_CONFIG      *ep;
+
+    boardp = ASC_BOARDP(shp);
+    adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+    ep = &boardp->eep_config.adv_eep;
 
-	boardp = ASC_BOARDP(shp);
+    leftlen = cplen;
+    totlen = len = 0;
 
-	leftlen = cplen;
-	totlen = len = 0;
+    len = asc_prt_line(cp, leftlen,
+"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
+    ASC_PRT_NEXT();
 
-	len = asc_prt_line(cp, leftlen,
-"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
-		shp->host_no);
-	ASC_PRT_NEXT();
+    if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) ==
+        ASC_TRUE) {
+        len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
+        ASC_PRT_NEXT();
+    } else {
+        len = asc_prt_line(cp, leftlen,
+            " Serial Number Signature Not Present.\n");
+        ASC_PRT_NEXT();
+    }
 
-	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
-" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
-		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
-#else /* version >= v1.3.89 */
-" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
-		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
-		shp->max_channel);
-#endif /* version >= v1.3.89 */
-	ASC_PRT_NEXT();
-	
-	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
-" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
-		shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
-#else /* version >= v1.3.57 */
-" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
-		shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
-		shp->cmd_per_lun);
-#endif /* version >= v1.3.57 */
-	ASC_PRT_NEXT();
+    len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+        ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng);
+    ASC_PRT_NEXT();
 
-	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
-" unchecked_isa_dma %d, loaded_as_module %d\n",
-		shp->unchecked_isa_dma, shp->loaded_as_module);
-#else /* version >= v1.3.57 */
-" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
-		shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
-#endif /* version >= v1.3.57 */
-	ASC_PRT_NEXT();
+    switch (ep->termination) {
+        case 1:
+            termstr = "Low Off/High Off";
+            break;
+        case 2:
+            termstr = "Low Off/High On";
+            break;
+        case 3:
+            termstr = "Low On/High On";
+            break;
+        default:
+        case 0:
+            termstr = "Automatic";
+            break;
+    }
 
-	len = asc_prt_line(cp, leftlen,
-" flags %x, last_reset %x, jiffies %x\n",
-		ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies);
-	ASC_PRT_NEXT();
+    len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: %x\n",
+        ep->termination, termstr, ep->bios_ctrl);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Target ID:           ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %X", i);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-	len = asc_prt_line(cp, leftlen,
-" queue_depth:     ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		len = asc_prt_line(cp, leftlen, " %d:%d",
-			i, boardp->device[i]->queue_depth);
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
-#endif /* version >= v1.3.89 */
+    len = asc_prt_line(cp, leftlen,
+" Disconnects:         ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-#if ASC_QUEUE_FLOW_CONTROL
-	len = asc_prt_line(cp, leftlen,
-" queue_curr_depth:");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		len = asc_prt_line(cp, leftlen, " %d:%d",
-			i, boardp->device[i]->queue_curr_depth);
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
-
-	len = asc_prt_line(cp, leftlen,
-" queue_count:     ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		len = asc_prt_line(cp, leftlen, " %d:%d",
-			i, boardp->device[i]->queue_count);
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
+    len = asc_prt_line(cp, leftlen,
+" Command Queuing:     ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Start Motor:         ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Ultra Transfer:      ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Wide Transfer:       ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    return totlen;
+}
+
+/*
+ * asc_prt_driver_conf()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t            *boardp;
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    int                    chip_scsi_id;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+    int                    i;
+#endif /* version >= v1.3.89 */
+
+    boardp = ASC_BOARDP(shp);
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+        shp->host_no);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
+" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
+        shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
+#else /* version >= v1.3.89 */
+" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
+        shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
+        shp->max_channel);
+#endif /* version >= v1.3.89 */
+    ASC_PRT_NEXT();
+    
+    len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
+" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+        shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
+#else /* version >= v1.3.57 */
+" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+        shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
+        shp->cmd_per_lun);
+#endif /* version >= v1.3.57 */
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
+" unchecked_isa_dma %d, loaded_as_module %d\n",
+        shp->unchecked_isa_dma, shp->loaded_as_module);
+#else /* version >= v1.3.57 */
+" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
+        shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
+#endif /* version >= v1.3.57 */
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen, " flags %x, last_reset %x, jiffies %x\n",
+        boardp->flags, boardp->last_reset, jiffies);
+    ASC_PRT_NEXT();
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+    } else {
+        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+    }
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+    if (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) {
+        len = asc_prt_line(cp, leftlen, " queue_depth:");
+        ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            if ((chip_scsi_id == i) ||
+                ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                continue;
+            }
+            if (boardp->device[i] == NULL) {
+                continue;
+            }
+            len = asc_prt_line(cp, leftlen, " %X:%d",
+                i, boardp->device[i]->queue_depth);
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+    }
+#endif /* version >= v1.3.89 */
+
+#if ASC_QUEUE_FLOW_CONTROL
+    if (ASC_NARROW_BOARD(boardp)) {
+        len = asc_prt_line(cp, leftlen, " queue_curr_depth:");
+        ASC_PRT_NEXT();
+        /* Use ASC_MAX_TID for Narrow Board. */
+        for (i = 0; i <= ASC_MAX_TID; i++) {
+            if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+                ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                continue;
+            }
+            if (boardp->device[i] == NULL) {
+                continue;
+            }
+            len = asc_prt_line(cp, leftlen, " %d:%d",
+                i, boardp->device[i]->queue_curr_depth);
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, " queue_count:");
+        ASC_PRT_NEXT();
+        /* Use ASC_MAX_TID for Narrow Board. */
+        for (i = 0; i <= ASC_MAX_TID; i++) {
+            if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+                ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                continue;
+            }
+            if (boardp->device[i] == NULL) {
+                continue;
+            }
+            len = asc_prt_line(cp, leftlen, " %d:%d",
+                i, boardp->device[i]->queue_count);
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+    }
 #endif /* ASC_QUEUE_FLOW_CONTROL */
 
- 	return totlen;
+    return totlen;
 }
 
 /*
- * asc_prt_board_info()
+ * asc_prt_asc_board_info()
  *
  * Print dynamic board configuration information.
  *
@@ -5997,127 +8701,339 @@
  * 'cplen' characters will be copied to 'cp'.
  */
 STATIC int
-asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	asc_board_t			*boardp;
-	int					leftlen;
-	int					totlen;
-	int					len;
-	ASC_DVC_VAR			*v;
-	ASC_DVC_CFG			*c;
-	int					i;
-
-	boardp = ASC_BOARDP(shp);
-	v = &boardp->asc_dvc_var;
-	c = &boardp->asc_dvc_cfg;
+    asc_board_t            *boardp;
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    ASC_DVC_VAR            *v;
+    ASC_DVC_CFG            *c;
+    int                    i;
+
+    boardp = ASC_BOARDP(shp);
+    v = &boardp->dvc_var.asc_dvc_var;
+    c = &boardp->dvc_cfg.asc_dvc_cfg;
 
-	leftlen = cplen;
-	totlen = len = 0;
+    leftlen = cplen;
+    totlen = len = 0;
 
-	len = asc_prt_line(cp, leftlen,
+    len = asc_prt_line(cp, leftlen,
 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
-	shp->host_no);
-	ASC_PRT_NEXT();
+    shp->host_no);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" chip_version %u, lib_version %x, lib_serial_no %u, mcode_date %x\n",
+        c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" mcode_version %x, err_code %u\n",
+         c->mcode_version, v->err_code);
+    ASC_PRT_NEXT();
+
+    /* Current number of commands waiting for the host. */
+    len = asc_prt_line(cp, leftlen,
+" Total Command Pending: %d\n", v->cur_total_qng);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Command Queuing:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %d:%c",
+            i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    /* Current number of commands waiting for a device. */
+    len = asc_prt_line(cp, leftlen,
+" Command Queue Pending:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
 
-	len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version %u, lib_serial_no %u, mcode_date %u\n",
-		c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
-	ASC_PRT_NEXT();
-
-	len = asc_prt_line(cp, leftlen,
-" mcode_version %u, err_code %u\n",
-		 c->mcode_version, v->err_code);
-	ASC_PRT_NEXT();
-
-	/* Current number of commands waiting for the host. */
-	len = asc_prt_line(cp, leftlen,
-" Total Command Pending:    %d\n", v->cur_total_qng);
-	ASC_PRT_NEXT();
-
-	len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer:    ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
-
-	len = asc_prt_line(cp, leftlen,
-" Command Queuing:         ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
-
-	/* Current number of commands waiting for a device. */
-	len = asc_prt_line(cp, leftlen,
-" Command Queue Pending:   ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
-
-	/* Current limit on number of commands that can be sent to a device. */
-	len = asc_prt_line(cp, leftlen,
-" Command Queue Limit:     ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
-
-	/* Indicate whether the device has returned queue full status. */
-	len = asc_prt_line(cp, leftlen,
-" Command Queue Full:      ");
-	ASC_PRT_NEXT();
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
-			continue;
-		}
-		if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) {
-			len = asc_prt_line(cp, leftlen, " %d:Y-%d",
-				i, boardp->queue_full_cnt[i]);
-		} else {
-			len = asc_prt_line(cp, leftlen, " %d:N", i);
-		}
-		ASC_PRT_NEXT();
-	}
-	len = asc_prt_line(cp, leftlen, "\n");
-	ASC_PRT_NEXT();
+    /* Current limit on number of commands that can be sent to a device. */
+    len = asc_prt_line(cp, leftlen,
+" Command Queue Limit:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    /* Indicate whether the device has returned queue full status. */
+    len = asc_prt_line(cp, leftlen,
+" Command Queue Full:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
+            len = asc_prt_line(cp, leftlen, " %d:Y-%d",
+                i, boardp->queue_full_cnt[i]);
+        } else {
+            len = asc_prt_line(cp, leftlen, " %d:N", i);
+        }
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %d:%c",
+            i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        uchar syn_period_ix;
+
+        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            continue;
+        }
+        syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
+        len = asc_prt_line(cp, leftlen, "  %d:", i);
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen,
+            " Transfer Period Factor: %d (%d.%d Mhz),",
+            v->sdtr_period_tbl[syn_period_ix],
+            250 / v->sdtr_period_tbl[syn_period_ix],
+            ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
+            boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+        ASC_PRT_NEXT();
+    }
 
- 	return totlen;
+    return totlen;
+}
+
+/*
+ * asc_prt_adv_board_info()
+ *
+ * Print dynamic board configuration information.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t            *boardp;
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    int                    i;
+    ADV_DVC_VAR            *v;
+    ADV_DVC_CFG            *c;
+    AdvPortAddr            iop_base;
+    ushort                 chip_scsi_id;
+    ushort                 lramword;
+    uchar                  lrambyte;
+    ushort                 sdtr_able;
+    ushort                 period;
+
+    boardp = ASC_BOARDP(shp);
+    v = &boardp->dvc_var.adv_dvc_var;
+    c = &boardp->dvc_cfg.adv_dvc_cfg;
+    iop_base = v->iop_base;
+    chip_scsi_id = v->chip_scsi_id;
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+    shp->host_no);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n",
+         v->iop_base,
+         AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
+         v->err_code, v->idle_cmd_done);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" chip_version %u, lib_version %x, mcode_date %x, mcode_version %x\n",
+        c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword);
+    len = asc_prt_line(cp, leftlen,
+" Queuing Enabled:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Queue Limit:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte);
+
+        len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Command Pending:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte);
+
+        len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword);
+    len = asc_prt_line(cp, leftlen,
+" Wide Enabled:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Transfer Bit Width:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+            lramword);
+        len = asc_prt_line(cp, leftlen, " %X:%d",
+            i, (lramword & 0x8000) ? 16 : 8);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    len = asc_prt_line(cp, leftlen,
+" Synchronous Enabled:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+
+        AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+            lramword);
+        lramword &= ~0x8000;
+
+        if ((chip_scsi_id == i) ||
+            ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) ||
+            (lramword == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, "  %X:", i);
+        ASC_PRT_NEXT();
+        
+        period = (((lramword >> 8) * 25) + 50)/4;
+
+        len = asc_prt_line(cp, leftlen,
+            " Transfer Period Factor: %d (%d.%d Mhz),",
+            period, 250/period, ASC_TENTHS(250, period));
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
+            lramword & 0x1F);
+        ASC_PRT_NEXT();
+    }
+
+    return totlen;
 }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 /*
  * asc_proc_copy() 
  *
@@ -6126,30 +9042,29 @@
  */
 STATIC int
 asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
-			  char *cp, int cplen)
+              char *cp, int cplen)
 {
-	int cnt = 0;
-	
-	ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
-			(unsigned) offset, (unsigned) advoffset, cplen);
-	if (offset <= advoffset) {
-		/* Read offset below current offset, copy everything. */
-		cnt = ASC_MIN(cplen, leftlen);
-		ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
-				(unsigned) curbuf, (unsigned) cp, cnt);
-		memcpy(curbuf, cp, cnt);
-	} else if (offset < advoffset + cplen) {
-		/* Read offset within current range, partial copy. */
-		cnt = (advoffset + cplen) - offset;
-		cp = (cp + cplen) - cnt;
-		cnt = ASC_MIN(cnt, leftlen);
-		ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
-				(unsigned) curbuf, (unsigned) cp, cnt);
-		memcpy(curbuf, cp, cnt);
-	}
-	return cnt;
+    int cnt = 0;
+    
+    ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
+            (unsigned) offset, (unsigned) advoffset, cplen);
+    if (offset <= advoffset) {
+        /* Read offset below current offset, copy everything. */
+        cnt = ASC_MIN(cplen, leftlen);
+        ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
+                (unsigned) curbuf, (unsigned) cp, cnt);
+        memcpy(curbuf, cp, cnt);
+    } else if (offset < advoffset + cplen) {
+        /* Read offset within current range, partial copy. */
+        cnt = (advoffset + cplen) - offset;
+        cp = (cp + cplen) - cnt;
+        cnt = ASC_MIN(cnt, leftlen);
+        ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
+                (unsigned) curbuf, (unsigned) cp, cnt);
+        memcpy(curbuf, cp, cnt);
+    }
+    return cnt;
 }
-#endif /* version >= v1.3.0 */
 
 /*
  * asc_prt_line()
@@ -6162,26 +9077,27 @@
  * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
  * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
  */
-int
+STATIC int
 asc_prt_line(char *buf, int buflen, char *fmt, ...)
 {
-	va_list		args;
-	int			ret;
-	char		s[ASC_PRTLINE_SIZE];
-
-	va_start(args, fmt);
-	ret = vsprintf(s, fmt, args);
-	ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
-	if (buf == NULL) {
-		(void) printk(s);
-		ret = 0;
-	} else {
-		ret = ASC_MIN(buflen, ret);
-		memcpy(buf, s, ret);
-	}
-	va_end(args);
-	return ret;
+    va_list        args;
+    int            ret;
+    char        s[ASC_PRTLINE_SIZE];
+
+    va_start(args, fmt);
+    ret = vsprintf(s, fmt, args);
+    ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
+    if (buf == NULL) {
+        (void) printk(s);
+        ret = 0;
+    } else {
+        ret = ASC_MIN(buflen, ret);
+        memcpy(buf, s, ret);
+    }
+    va_end(args);
+    return ret;
 }
+#endif /* version >= v1.3.0 */
 
 
 /*
@@ -6194,70 +9110,48 @@
  * from a timer interrupt, because this function may be
  * called when interrupts are disabled.
  */
-void
+STATIC void
 DvcSleepMilliSecond(ulong n)
 {
-	ulong i;
-
-	ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n);
-	for (i = 0; i < n; i++) {
-		udelay(1000);
-	}
-}
+    ulong i;
 
-void
-DvcDisplayString(uchar *s)
-{
-	printk(s);
+    ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n);
+    for (i = 0; i < n; i++) {
+        udelay(1000);
+    }
 }
 
-int
+STATIC int
 DvcEnterCritical(void)
 {
-	int	flags;
+    int    flags;
 
-	save_flags(flags);
-	cli();
-	return flags;
+    save_flags(flags);
+    cli();
+    return flags;
 }
 
-void
+STATIC void
 DvcLeaveCritical(int flags)
 {
-	restore_flags(flags);
+    restore_flags(flags);
 }
 
-/*
- * Convert a virtual address to a bus address.
- */
-ulong
-DvcGetPhyAddr(uchar *buf_addr, ulong buf_len)
-{
-	ulong bus_addr;
-
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-	bus_addr = (ulong) buf_addr;
-#else /* version >= v2.0.0 */
-	bus_addr = virt_to_bus(buf_addr);
-#endif /* version >= v2.0.0 */
-	return bus_addr;
-}
-
-ulong
+STATIC ulong
 DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ulong buf_len,
-			 ASC_SG_HEAD *asc_sg_head_ptr)
+             ASC_SG_HEAD *asc_sg_head_ptr)
 {
-	ulong buf_size;
+    ulong buf_size;
 
-	buf_size = buf_len;
-	asc_sg_head_ptr->entry_cnt = 1;
+    buf_size = buf_len;
+    asc_sg_head_ptr->entry_cnt = 1;
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-	asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr;
+    asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr;
 #else /* version >= v2.0.0 */
-	asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr);
+    asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr);
 #endif /* version >= v2.0.0 */
-	asc_sg_head_ptr->sg_list[0].bytes = buf_size;
-	return buf_size;
+    asc_sg_head_ptr->sg_list[0].bytes = buf_size;
+    return buf_size;
 }
 
 /*
@@ -6265,24 +9159,24 @@
  * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words)
  *
  * Calling/Exit State:
- *	none
+ *    none
  *
  * Description:
- * 	Output an ASC_SCSI_Q structure to the chip
+ *     Output an ASC_SCSI_Q structure to the chip
  */
-void
+STATIC void
 DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words)
 {
-	int	i;
+    int    i;
 
-	ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words);
-	AscSetChipLramAddr(iop_base, s_addr);
-	for (i = 0; i < words; i++, outbuf++) {
-		if (i == 2 || i == 10) {
-			continue;
-		}
-		AscSetChipLramDataNoSwap(iop_base, *outbuf);
-	}
+    ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words);
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < words; i++, outbuf++) {
+        if (i == 2 || i == 10) {
+            continue;
+        }
+        AscSetChipLramDataNoSwap(iop_base, *outbuf);
+    }
 }
 
 /*
@@ -6290,97 +9184,98 @@
  * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words)
  *
  * Calling/Exit State:
- *	none
+ *    none
  *
  * Description:
- * 	Input an ASC_QDONE_INFO structure from the chip
+ *     Input an ASC_QDONE_INFO structure from the chip
  */
-void
+STATIC void
 DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words)
 {
-	int	i;
+    int    i;
 
-	AscSetChipLramAddr(iop_base, s_addr);
-	for (i = 0; i < words; i++, inbuf++) {
-		if (i == 5) {
-			continue;
-		}
-		*inbuf = AscGetChipLramDataNoSwap(iop_base);
-	}
-	ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words);
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < words; i++, inbuf++) {
+        if (i == 5) {
+            continue;
+        }
+        *inbuf = AscGetChipLramDataNoSwap(iop_base);
+    }
+    ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words);
 }
 
 /*
- * void	DvcOutPortWords(ushort iop_base, ushort &outbuf, int words)
+ * void    DvcOutPortWords(ushort iop_base, ushort &outbuf, int words)
  *
  * Calling/Exit State:
- *	none
+ *    none
  *
  * Description:
- * 	output a buffer to an i/o port address
+ *     output a buffer to an i/o port address
  */
-void
+STATIC void
 DvcOutPortWords(ushort iop_base, ushort *outbuf, int words)
 {
-	int	i;
+    int    i;
 
-	for (i = 0; i < words; i++, outbuf++)
-		outpw(iop_base, *outbuf);
+    for (i = 0; i < words; i++, outbuf++)
+        outpw(iop_base, *outbuf);
 }
 
 /*
- * void	DvcInPortWords(ushort iop_base, ushort &outbuf, int words)
+ * void    DvcInPortWords(ushort iop_base, ushort &outbuf, int words)
  *
  * Calling/Exit State:
- *	none
+ *    none
  *
  * Description:
- * 	input a buffer from an i/o port address
+ *     input a buffer from an i/o port address
  */
-void
+STATIC void
 DvcInPortWords(ushort iop_base, ushort *inbuf, int words)
 {
-	int	i;
+    int    i;
 
-	for (i = 0; i < words; i++, inbuf++)
-		*inbuf = inpw(iop_base);
+    for (i = 0; i < words; i++, inbuf++)
+        *inbuf = inpw(iop_base);
 }
 
-
 /*
  * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
  *
  * Calling/Exit State:
- *	none
+ *    none
  *
  * Description:
- * 	output a buffer of 32-bit integers to an i/o port address in
+ *     output a buffer of 32-bit integers to an i/o port address in
  *  16 bit integer units
  */
-void  
+STATIC void  
 DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
 {
-	int		i;
-	int		words;
-	ushort	*pw;
-
-	pw = (ushort *) pdw;
-	words = dwords << 1;
-	for(i = 0; i < words; i++, pw++) {
-		outpw(port, *pw);
-	}
-	return;
+    int        i;
+    int        words;
+    ushort    *pw;
+
+    pw = (ushort *) pdw;
+    words = dwords << 1;
+    for(i = 0; i < words; i++, pw++) {
+        outpw(port, *pw);
+    }
+    return;
 }
 
 /*
  * Read a PCI configuration byte.
  */
-uchar
-DvcReadPCIConfigByte( 
+ASC_INITFUNC(
+STATIC uchar
+DvcReadPCIConfigByte(
         ASC_DVC_VAR asc_ptr_type *asc_dvc, 
-        ushort offset )
+        ushort offset)
+)
 {
-    PCI_DATA	pciData;
+    PCI_DATA    pciData;
 
     pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
     pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
@@ -6393,13 +9288,15 @@
 /*
  * Write a PCI configuration byte.
  */
-void
+ASC_INITFUNC(
+STATIC void
 DvcWritePCIConfigByte(
         ASC_DVC_VAR asc_ptr_type *asc_dvc, 
         ushort offset, 
-        uchar  byte_data )
+        uchar  byte_data)
+)
 {
-    PCI_DATA	pciData;
+    PCI_DATA    pciData;
 
     pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
     pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
@@ -6413,49 +9310,126 @@
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  */
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscGetChipBiosAddress(
         PortAddr iop_base,
         ushort bus_type
-    )
+)
+)
 {
     ushort  cfg_lsw ;
     ushort  bios_addr ;
 
-	/*
-	 * The PCI BIOS is re-located by the motherboard BIOS. Because
-	 * of this the driver can not determine where a PCI BIOS is
-	 * loaded and executes.
-	 */
-	if ( bus_type & ASC_IS_PCI )
-	{
-		return( 0 );
-	}
+    /*
+     * The PCI BIOS is re-located by the motherboard BIOS. Because
+     * of this the driver can not determine where a PCI BIOS is
+     * loaded and executes.
+     */
+    if (bus_type & ASC_IS_PCI)
+    {
+        return(0);
+    }
 
-    if( ( bus_type & ASC_IS_EISA ) != 0 )
+    if((bus_type & ASC_IS_EISA) != 0)
     {
-        cfg_lsw = AscGetEisaChipCfg( iop_base ) ;
+        cfg_lsw = AscGetEisaChipCfg(iop_base) ;
         cfg_lsw &= 0x000F ;
-        bios_addr = ( ushort )( ASC_BIOS_MIN_ADDR  +
-                                ( cfg_lsw * ASC_BIOS_BANK_SIZE ) ) ;
-        return( bios_addr ) ;
+        bios_addr = (ushort)(ASC_BIOS_MIN_ADDR  +
+                                (cfg_lsw * ASC_BIOS_BANK_SIZE)) ;
+        return(bios_addr) ;
     }/* if */
 
-    cfg_lsw = AscGetChipCfgLsw( iop_base ) ;
+    cfg_lsw = AscGetChipCfgLsw(iop_base) ;
 
     /*
     *  ISA PnP uses the top bit as the 32K BIOS flag
     */
-    if ( bus_type == ASC_IS_ISAPNP )
+    if (bus_type == ASC_IS_ISAPNP)
     {
         cfg_lsw &= 0x7FFF;
     }/* if */
 
-    bios_addr = ( ushort )( ( ( cfg_lsw >> 12 ) * ASC_BIOS_BANK_SIZE ) +
-			ASC_BIOS_MIN_ADDR ) ;
-    return( bios_addr ) ;
+    bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
+            ASC_BIOS_MIN_ADDR) ;
+    return(bios_addr) ;
+}
+
+
+/*
+ * --- Functions Required by the Adv Library
+ */
+
+/*
+ * DvcGetPhyAddr()
+ *
+ * Return the physical address of 'vaddr' and set '*lenp' to the
+ * number of physically contiguous bytes that follow 'vaddr'.
+ * 'flag' indicates the type of structure whose physical address
+ * is being translated.
+ *
+ * Note: Because Linux currently doesn't page the kernel and all
+ * kernel buffers are physically contiguous, leave '*lenp' unchanged.
+ */
+ulong
+DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
+        uchar *vaddr, long *lenp, int flag)
+{
+    ulong                paddr;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+    paddr = (ulong) vaddr;
+#else /* version >= v2.0.0 */
+    paddr = virt_to_bus(vaddr);
+#endif /* version >= v2.0.0 */
+
+    ASC_DBG4(4,
+        "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", 
+        (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), paddr);
+
+    return paddr;
+}
+
+/*
+ * Read a PCI configuration byte.
+ */
+ASC_INITFUNC(
+STATIC uchar
+DvcAdvReadPCIConfigByte(
+        ADV_DVC_VAR *asc_dvc, 
+        ushort offset)
+)
+{
+    PCI_DATA    pciData;
+
+    pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
+    pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
+    pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
+    pciData.offset = offset;
+    pciData.type = pci_scan_method;
+    return asc_get_cfg_byte(&pciData);
 }
 
+/*
+ * Write a PCI configuration byte.
+ */
+ASC_INITFUNC(
+STATIC void
+DvcAdvWritePCIConfigByte(
+        ADV_DVC_VAR *asc_dvc, 
+        ushort offset, 
+        uchar  byte_data)
+)
+{
+    PCI_DATA    pciData;
+
+    pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
+    pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
+    pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
+    pciData.offset = offset;
+    pciData.type = pci_scan_method;
+    asc_put_cfg_byte(&pciData, byte_data);
+}
 
 /*
  * --- Tracing and Debugging Functions
@@ -6474,123 +9448,151 @@
 STATIC int
 asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	int					leftlen;
-	int					totlen;
-	int					len;
-	struct asc_stats	*s;
-	int					i;
-	asc_queue_t			*active;
-	asc_queue_t			*waiting;
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    struct asc_stats       *s;
+    int                    i;
+    ushort                 chip_scsi_id;
+    asc_board_t            *boardp;
+    asc_queue_t            *active;
+    asc_queue_t            *waiting;
 
-	leftlen = cplen;
-	totlen = len = 0;
+    leftlen = cplen;
+    totlen = len = 0;
 
-	s = &ASC_BOARDP(shp)->asc_stats;
-	len = asc_prt_line(cp, leftlen,
+    boardp = ASC_BOARDP(shp);
+    s = &boardp->asc_stats;
+
+    len = asc_prt_line(cp, leftlen,
 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no);
-	ASC_PRT_NEXT();
-	
-	len = asc_prt_line(cp, leftlen,
+    ASC_PRT_NEXT();
+    
+    len = asc_prt_line(cp, leftlen,
 " command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu\n",
-		s->command, s->queuecommand, s->abort, s->reset, s->biosparam);
-	ASC_PRT_NEXT();
+        s->command, s->queuecommand, s->abort, s->reset, s->biosparam);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" interrupt %lu, callback %lu, done %lu\n",
+        s->interrupt, s->callback, s->done);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+        s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown);
+    ASC_PRT_NEXT();
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        len = asc_prt_line(cp, leftlen,
+" build_error %lu\n",
+         s->build_error);
+    } else {
+        len = asc_prt_line(cp, leftlen,
+" build_error %lu, build_noreq %lu, build_nosg %lu\n",
+         s->build_error, s->adv_build_noreq, s->adv_build_nosg);
+    }
+    ASC_PRT_NEXT();
+
+    /*
+     * Display data transfer statistics.
+     */
+    if (s->cont_cnt > 0) {
+        len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
+                    s->cont_xfer/2,
+                    ASC_TENTHS(s->cont_xfer, 2));
+        ASC_PRT_NEXT();
+
+        /* Contiguous transfer average size */
+        len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
+                    (s->cont_xfer/2)/s->cont_cnt,
+                    ASC_TENTHS((s->cont_xfer/2), s->cont_cnt));
+        ASC_PRT_NEXT();
+    }
+
+    if (s->sg_cnt > 0) {
+
+        len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
+                    s->sg_cnt, s->sg_elem);
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
+                    s->sg_xfer/2,
+                    ASC_TENTHS(s->sg_xfer, 2));
+        ASC_PRT_NEXT();
+
+        /* Scatter gather transfer statistics */
+        len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
+                    s->sg_elem/s->sg_cnt,
+                    ASC_TENTHS(s->sg_elem, s->sg_cnt));
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
+                    (s->sg_xfer/2)/s->sg_elem,
+                    ASC_TENTHS((s->sg_xfer/2), s->sg_elem));
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
+                    (s->sg_xfer/2)/s->sg_cnt,
+                    ASC_TENTHS((s->sg_xfer/2), s->sg_cnt));
+        ASC_PRT_NEXT();
+    }
+
+    /*
+     * Display request queuing statistics.
+     */
+    len = asc_prt_line(cp, leftlen,
+" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ);
+    ASC_PRT_NEXT();
+
+    active = &ASC_BOARDP(shp)->active;
+    waiting = &ASC_BOARDP(shp)->waiting;
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+    } else {
+        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+    }
+
+    for (i = 0; i <= ADV_MAX_TID; i++) {
 
-	len = asc_prt_line(cp, leftlen,
-" check_interrupt %lu, interrupt %lu, callback %lu, done %lu\n",
-		s->check_interrupt, s->interrupt, s->callback, s->done);
-	ASC_PRT_NEXT();
-
-	len = asc_prt_line(cp, leftlen,
-" asc_noerror %lu, asc_busy %lu, asc_error %lu, asc_unknown %lu\n",
-		s->asc_noerror, s->asc_busy, s->asc_error, s->asc_unknown);
-	ASC_PRT_NEXT();
-
-	/*
-	 * Display data transfer statistics.
-	 */
-	if (s->cont_cnt > 0) {
-		len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
-		ASC_PRT_NEXT();
-
-		len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
-					s->cont_xfer/2,
-					ASC_TENTHS(s->cont_xfer, 2));
-		ASC_PRT_NEXT();
-
-		/* Contiguous transfer average size */
-		len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
-					(s->cont_xfer/2)/s->cont_cnt,
-					ASC_TENTHS((s->cont_xfer/2), s->cont_cnt));
-		ASC_PRT_NEXT();
-	}
-
-	if (s->sg_cnt > 0) {
-
-		len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
-					s->sg_cnt, s->sg_elem);
-		ASC_PRT_NEXT();
-
-		len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
-					s->sg_xfer/2,
-					ASC_TENTHS(s->sg_xfer, 2));
-		ASC_PRT_NEXT();
-
-		/* Scatter gather transfer statistics */
-		len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
-					s->sg_elem/s->sg_cnt,
-					ASC_TENTHS(s->sg_elem, s->sg_cnt));
-		ASC_PRT_NEXT();
-
-		len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
-					(s->sg_xfer/2)/s->sg_elem,
-					ASC_TENTHS((s->sg_xfer/2), s->sg_elem));
-		ASC_PRT_NEXT();
-
-		len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
-					(s->sg_xfer/2)/s->sg_cnt,
-					ASC_TENTHS((s->sg_xfer/2), s->sg_cnt));
-		ASC_PRT_NEXT();
-	}
-
-	/*
-	 * Display request queuing statistics.
-	 */
-	len = asc_prt_line(cp, leftlen,
-" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ);
-	ASC_PRT_NEXT();
-
-	active = &ASC_BOARDP(shp)->active;
-	waiting = &ASC_BOARDP(shp)->waiting;
-	for (i = 0; i < ASC_MAX_TID + 1; i++) {
-		if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) {
-			len = asc_prt_line(cp, leftlen, " target %d\n", i);
-			ASC_PRT_NEXT();
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) {
+            len = asc_prt_line(cp, leftlen, " target %d\n", i);
+            ASC_PRT_NEXT();
 
-			len = asc_prt_line(cp, leftlen,
+            len = asc_prt_line(cp, leftlen,
 "   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
-				active->q_cur_cnt[i], active->q_max_cnt[i],
-				active->q_tot_cnt[i],
-				active->q_min_tim[i], active->q_max_tim[i],
-				(active->q_tot_cnt[i] == 0) ? 0 :
-				(active->q_tot_tim[i]/active->q_tot_cnt[i]),
-				(active->q_tot_cnt[i] == 0) ? 0 :
-				ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i]));
-			ASC_PRT_NEXT();
+                active->q_cur_cnt[i], active->q_max_cnt[i],
+                active->q_tot_cnt[i],
+                active->q_min_tim[i], active->q_max_tim[i],
+                (active->q_tot_cnt[i] == 0) ? 0 :
+                (active->q_tot_tim[i]/active->q_tot_cnt[i]),
+                (active->q_tot_cnt[i] == 0) ? 0 :
+                ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i]));
+            ASC_PRT_NEXT();
 
-			len = asc_prt_line(cp, leftlen,
+            len = asc_prt_line(cp, leftlen,
 "   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
-				waiting->q_cur_cnt[i], waiting->q_max_cnt[i],
-				waiting->q_tot_cnt[i],
-				waiting->q_min_tim[i], waiting->q_max_tim[i],
-				(waiting->q_tot_cnt[i] == 0) ? 0 :
-				(waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]),
-				(waiting->q_tot_cnt[i] == 0) ? 0 :
-				ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i]));
-			ASC_PRT_NEXT();
-		}
-	}
+                waiting->q_cur_cnt[i], waiting->q_max_cnt[i],
+                waiting->q_tot_cnt[i],
+                waiting->q_min_tim[i], waiting->q_max_tim[i],
+                (waiting->q_tot_cnt[i] == 0) ? 0 :
+                (waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]),
+                (waiting->q_tot_cnt[i] == 0) ? 0 :
+                ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i]));
+            ASC_PRT_NEXT();
+        }
+    }
 
- 	return totlen;
+     return totlen;
 }
 #endif /* ADVANSYS_STATS */
 
@@ -6601,32 +9603,41 @@
 STATIC void 
 asc_prt_scsi_host(struct Scsi_Host *s)
 {
-	printk("Scsi_Host at addr %x\n", (unsigned) s);
-	printk(
+    asc_board_t         *boardp;
+
+    boardp = ASC_BOARDP(s);
+
+    printk("Scsi_Host at addr %x\n", (unsigned) s);
+    printk(
 " next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n",
-		(unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no,
-		(unsigned) s->last_reset);
+        (unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no,
+        (unsigned) s->last_reset);
 
-	printk(
+    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);
+        (unsigned) s->host_wait, (unsigned) s->host_queue,
+        (unsigned) s->hostt, (unsigned) s->block);
 
-	printk(
+    printk(
 " wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n",
-		s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port,
-		s->irq, s->dma_channel);
+        s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port,
+        s->irq, s->dma_channel);
 
-	printk(
+    printk(
 " this_id %d, can_queue %d,\n", s->this_id, s->can_queue);
 
-	printk(
+    printk(
 " cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
-		s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
-		s->loaded_as_module);
+        s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
+        s->loaded_as_module);
 
-	asc_prt_dvc_var(&ASC_BOARDP(s)->asc_dvc_var);
-	asc_prt_dvc_cfg(&ASC_BOARDP(s)->asc_dvc_cfg);
+    if (ASC_NARROW_BOARD(boardp)) {
+        asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
+        asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
+    } else {
+        asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
+        asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
+    }
 }
 
 /*
@@ -6635,4310 +9646,6208 @@
 STATIC void 
 asc_prt_scsi_cmnd(Scsi_Cmnd *s)
 {
-	printk("Scsi_Cmnd at addr %x\n", (unsigned) s);
+    printk("Scsi_Cmnd at addr %x\n", (unsigned) s);
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-	printk(
+    printk(
 " host %x, device %x, target %u, lun %u\n",
-		(unsigned) s->host, (unsigned) s->device, s->target, s->lun);
+        (unsigned) s->host, (unsigned) s->device, s->target, s->lun);
 #else /* version >= v1.3.0 */
-	printk(
+    printk(
 " host %x, device %x, target %u, lun %u, channel %u,\n",
-		(unsigned) s->host, (unsigned) s->device, s->target, s->lun,
-		s->channel);
+        (unsigned) s->host, (unsigned) s->device, s->target, s->lun,
+        s->channel);
 #endif /* version >= v1.3.0 */
 
-	asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+    asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
 
-	printk(
+    printk(
 " use_sg %u, sglist_len %u, abort_reason %x\n",
-		s->use_sg, s->sglist_len, s->abort_reason);
+        s->use_sg, s->sglist_len, s->abort_reason);
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
-	printk(
+    printk(
 " retries %d, allowed %d\n",
-		 s->retries, s->allowed);
+         s->retries, s->allowed);
 #else /* version >= v1.3.89 */
-	printk(
+    printk(
 " serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n",
-		(unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout,
-		 s->retries, s->allowed);
+        (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout,
+         s->retries, s->allowed);
 #endif /* version >= v1.3.89 */
 
-	printk(
+    printk(
 " timeout_per_command %d, timeout_total %d, timeout %d\n",
-		s->timeout_per_command, s->timeout_total, s->timeout);
+        s->timeout_per_command, s->timeout_total, s->timeout);
 
-	printk(
+    printk(
 " internal_timeout %u, flags %u, this_count %d\n",
-		s->internal_timeout, s->flags, s->this_count);
+        s->internal_timeout, s->flags, s->this_count);
 
-	printk(
+    printk(
 " scsi_done %x, done %x, host_scribble %x, result %x\n",
-		(unsigned) s->scsi_done, (unsigned) s->done,
-		(unsigned) s->host_scribble, s->result);
+        (unsigned) s->scsi_done, (unsigned) s->done,
+        (unsigned) s->host_scribble, s->result);
 
-	printk(
+    printk(
 " tag %u, pid %u\n",
-		(unsigned) s->tag, (unsigned) s->pid);
+        (unsigned) s->tag, (unsigned) s->pid);
 }
 
 /*
- * asc_prt_dvc_var()
+ * asc_prt_asc_dvc_var()
  */
 STATIC void 
-asc_prt_dvc_var(ASC_DVC_VAR *h)
+asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
 {
-	printk("ASC_DVC_VAR at addr %x\n", (unsigned) h);
+    printk("ASC_DVC_VAR at addr %x\n", (unsigned) h);
 
-	printk(
+    printk(
 " iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n",
-		h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+        h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
 
-	printk(
+    printk(
 " bus_type %d, isr_callback %x, exe_callback %x, init_sdtr %x,\n",
-		h->bus_type, (unsigned) h->isr_callback, (unsigned) h->exe_callback,
-		(unsigned) h->init_sdtr);
+        h->bus_type, (unsigned) h->isr_callback, (unsigned) h->exe_callback,
+        (unsigned) h->init_sdtr);
 
-	printk(
+    printk(
 " sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n",
-		(unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng,
-		(unsigned) h->unit_not_ready, (unsigned) h->chip_no);
-		
-	printk(
+        (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng,
+        (unsigned) h->unit_not_ready, (unsigned) h->chip_no);
+        
+    printk(
 " queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n",
-		(unsigned) h->queue_full_or_busy, (unsigned) h->start_motor,
-		(unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
+        (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor,
+        (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
 
-	printk(
+    printk(
 " is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n",
-		(unsigned) h->is_in_int, (unsigned) h->max_total_qng,
-		(unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt);
+        (unsigned) h->is_in_int, (unsigned) h->max_total_qng,
+        (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt);
 
-	printk(
+    printk(
 " last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n",
-		(unsigned) h->last_q_shortage, (unsigned) h->init_state,
-		(unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
+        (unsigned) h->last_q_shortage, (unsigned) h->init_state,
+        (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
 
-	printk(
+    printk(
 " cfg %x, saved_ptr2func %x\n",
-		(unsigned) h->cfg, (unsigned) h->saved_ptr2func);
+        (unsigned) h->cfg, (unsigned) h->saved_ptr2func);
 }
 
 /*
- * asc_prt_dvc_cfg()
+ * asc_prt_asc_dvc_cfg()
  */
 STATIC void 
-asc_prt_dvc_cfg(ASC_DVC_CFG *h)
+asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
 {
-	printk("ASC_DVC_CFG at addr %x\n", (unsigned) h);
+    printk("ASC_DVC_CFG at addr %x\n", (unsigned) h);
 
-	printk(
+    printk(
 " can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, res %x,\n",
-			h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, h->res);
+            h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, h->res);
 
-	printk(
+    printk(
 " chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
-			 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
-			 h->chip_version);
+             h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
+             h->chip_version);
 
-	printk(
-" pci_device_id %d, lib_serial_no %d, lib_version %d, mcode_date %d,\n",
-		  h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date);
+    printk(
+" pci_device_id %d, lib_serial_no %x, lib_version %x, mcode_date %x,\n",
+          h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date);
 
-	printk(
+    printk(
 " mcode_version %d, overrun_buf %x\n",
-			h->mcode_version, (unsigned) h->overrun_buf);
+            h->mcode_version, (unsigned) h->overrun_buf);
 }
 
 /*
- * asc_prt_scsi_q()
+ * asc_prt_asc_scsi_q()
  */
 STATIC void 
-asc_prt_scsi_q(ASC_SCSI_Q *q)
+asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
 {
-	ASC_SG_HEAD	*sgp;
-	int i;
+    ASC_SG_HEAD    *sgp;
+    int i;
 
-	printk("ASC_SCSI_Q at addr %x\n", (unsigned) q);
+    printk("ASC_SCSI_Q at addr %x\n", (unsigned) q);
 
-	printk(
+    printk(
 " target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n",
-			q->q2.target_ix, q->q1.target_lun,
-			(unsigned) q->q2.srb_ptr, q->q2.tag_code);
+            q->q2.target_ix, q->q1.target_lun,
+            (unsigned) q->q2.srb_ptr, q->q2.tag_code);
 
-	printk(
+    printk(
 " data_addr %x, data_cnt %lu, sense_addr %x, sense_len %u,\n",
-			(unsigned) q->q1.data_addr, q->q1.data_cnt,
-			(unsigned) q->q1.sense_addr, q->q1.sense_len);
+            (unsigned) q->q1.data_addr, q->q1.data_cnt,
+            (unsigned) q->q1.sense_addr, q->q1.sense_len);
 
-	printk(
+    printk(
 " cdbptr %x, cdb_len %u, sg_head %x, sg_queue_cnt %u\n",
-			(unsigned) q->cdbptr, q->q2.cdb_len,
-			(unsigned) q->sg_head, q->q1.sg_queue_cnt);
+            (unsigned) q->cdbptr, q->q2.cdb_len,
+            (unsigned) q->sg_head, q->q1.sg_queue_cnt);
 
-	if (q->sg_head) {
-		sgp = q->sg_head;
-		printk("ASC_SG_HEAD at addr %x\n", (unsigned) sgp);
-		printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
-		for (i = 0; i < sgp->entry_cnt; i++) {
-			printk(" [%u]: addr %x, bytes %lu\n",
-				i, (unsigned) sgp->sg_list[i].addr, sgp->sg_list[i].bytes);
-		}
+    if (q->sg_head) {
+        sgp = q->sg_head;
+        printk("ASC_SG_HEAD at addr %x\n", (unsigned) sgp);
+        printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
+        for (i = 0; i < sgp->entry_cnt; i++) {
+            printk(" [%u]: addr %x, bytes %lu\n",
+                i, (unsigned) sgp->sg_list[i].addr, sgp->sg_list[i].bytes);
+        }
 
-	}
+    }
 }
 
 /*
- * asc_prt_qdone_info()
+ * asc_prt_asc_qdone_info()
  */
 STATIC void 
-asc_prt_qdone_info(ASC_QDONE_INFO *q)
+asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
 {
-	printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q);
-	printk(
+    printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q);
+    printk(
 " srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n",
-			(unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
-			q->d2.tag_code, q->d3.done_stat);
-	printk(
+            (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+            q->d2.tag_code, q->d3.done_stat);
+    printk(
 " host_stat %x, scsi_stat %x, scsi_msg %x\n",
-			q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
+            q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
 }
 
 /*
- * asc_prt_hex()
+ * asc_prt_adv_dvc_var()
  *
- * Print hexadecimal output in 4 byte groupings 32 bytes 
- * or 8 double-words per line.
+ * Display an ADV_DVC_VAR structure.
  */
 STATIC void 
-asc_prt_hex(char *f, uchar *s, int l)
+asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
 {
-	int			i;
-	int			j;
-	int			k;
-	int			m;
-
-	printk("%s: (%d bytes)\n", f, l);
-
-	for (i = 0; i < l; i += 32) {
-		
-		/* Display a maximum of 8 double-words per line. */
-		if ((k = (l - i) / 4) >= 8) {
-			k = 8;
-			m = 0;
-		} else {
-			m = (l - i) % 4 ;
-		}
-
-		for (j = 0; j < k; j++) {
-			printk(" %2.2X%2.2X%2.2X%2.2X",
-				(unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1],
-				(unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]);
-		}
-
-		switch (m) {
-		case 0:
-		default:
-			break;
-		case 1:
-			printk(" %2.2X",
-				(unsigned) s[i+(j*4)]);
-			break;
-		case 2:
-			printk(" %2.2X%2.2X",
-				(unsigned) s[i+(j*4)],
-				(unsigned) s[i+(j*4)+1]);
-			break;
-		case 3:
-			printk(" %2.2X%2.2X%2.2X",
-				(unsigned) s[i+(j*4)+1],
-				(unsigned) s[i+(j*4)+2],
-				(unsigned) s[i+(j*4)+3]);
-			break;
-		}
+    printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h);
+
+    printk(
+"  iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+        (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able);
+
+    printk(
+"  isr_callback 0x%x, sdtr_able 0x%x, wdtr_able 0x%x\n",
+        (unsigned) h->isr_callback, (unsigned) h->wdtr_able,
+        (unsigned) h->sdtr_able);
+
+    printk(
+"  start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
+        (unsigned) h->start_motor,
+        (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
+
+    printk(
+"  max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n",
+        (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng,
+        (unsigned) h->max_dvc_qng);
+
+    printk(
+"  no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n",
+        (unsigned) h->no_scam, (unsigned) h->tagqng_able,
+        (unsigned) h->chip_scsi_id, (ulong) h->cfg);
 
-		printk("\n");
-	}
 }
 
 /*
- * interrupts_enabled()
+ * asc_prt_adv_dvc_cfg()
  *
- * Return 1 if interrupts are enabled, otherwise return 0.
+ * Display an ADV_DVC_CFG structure.
  */
-STATIC int
-interrupts_enabled(void)
+STATIC void 
+asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
 {
-	int flags;
+    printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h);
 
-	save_flags(flags);
-	if (flags & 0x0200) {
-		return ASC_TRUE;
-	} else {
-		return ASC_FALSE;
-	}
-}
+    printk(
+"  disc_enable 0x%x, termination 0x%x\n",
+        h->disc_enable, h->termination);
 
-#endif /* ADVANSYS_DEBUG */
+    printk(
+"  chip_version 0x%x, mcode_date 0x%x\n",
+        h->chip_version, h->mcode_date);
 
+    printk(
+"  mcode_version 0x%x, pci_device_id 0x%x, lib_version 0x%x\n",
+       h->mcode_version, h->pci_device_id, h->lib_version);
+
+    printk(
+"  control_flag 0x%x, pci_slot_info 0x%x\n",
+       h->control_flag, h->pci_slot_info);
+}
 
 /*
- * --- Asc Library Functions
+ * asc_prt_adv_scsi_req_q()
+ *
+ * Display an ADV_SCSI_REQ_Q structure.
  */
-
-ushort
-AscGetEisaChipCfg(
-					 PortAddr iop_base
-)
+STATIC void 
+asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
 {
-	PortAddr            eisa_cfg_iop;
-	eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
-	  (PortAddr) (ASC_EISA_CFG_IOP_MASK);
-	return (inpw(eisa_cfg_iop));
-}
+    int                 i;
+    struct asc_sg_block *sg_ptr;
 
-uchar
-AscSetChipScsiID(
-					PortAddr iop_base,
-					uchar new_host_id
+    printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q);
+
+    printk(
+"  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+            q->target_id, q->target_lun, q->srb_ptr, q->a_flag);
+
+    printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+            q->cntl, q->data_addr, q->vdata_addr);
+
+    printk(
+"  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+            q->data_cnt, q->sense_addr, q->sense_len);
+
+    printk(
+"  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+            q->cdb_len, q->done_status, q->host_status, q->scsi_status);
+
+    printk(
+"  vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n",
+            (ulong) q->vsense_addr, (ulong) q->scsiq_ptr,
+            (ulong) q->ux_wk_data_cnt);
+
+    printk(
+"  sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n",
+            (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt);
+
+    printk(
+"  ux_sg_ix %u, orig_sense_len %u\n",
+            q->ux_sg_ix, q->orig_sense_len);
+
+    /* Display the request's ADV_SG_BLOCK structures. */
+    for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL;
+        sg_ptr = sg_ptr->sg_ptr, i++) {
+        /*
+         * 'sg_ptr' is a physical address. Convert it to a virtual
+         * address by indexing 'i' into the virtual address array
+         * 'sg_list_ptr'.
+         *
+         * At the end of the each iteration of the loop 'sg_ptr' is
+         * converted back into a physical address by setting 'sg_ptr'
+         *  to the next pointer 'sg_ptr->sg_ptr'.
+         */
+        sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]);
+        asc_prt_adv_sgblock(i, sg_ptr);
+    }
+}
+
+/*
+ * asc_prt_adv_sgblock()
+ *
+ * Display an ADV_SG_BLOCK structure.
+ */
+STATIC void
+asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+{
+    int i, s;
+
+    /* Calculate starting entry number for the current block. */
+    s = sgblockno * NO_OF_SG_PER_BLOCK;
+
+    printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n",
+        (ulong) b, (ulong) sgblockno);
+    printk(
+"  first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n",
+        (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr);
+    ASC_ASSERT(b->first_entry_no - s >= 0);
+    ASC_ASSERT(b->last_entry_no - s >= 0);
+    ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK);
+    ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
+    ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
+    ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s);
+    for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) {
+        printk("  [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n",
+            (ulong) i, (ulong) b->sg_list[i].sg_addr,
+            (ulong) b->sg_list[i].sg_count);
+    }
+}
+
+/*
+ * asc_prt_hex()
+ *
+ * Print hexadecimal output in 4 byte groupings 32 bytes 
+ * or 8 double-words per line.
+ */
+STATIC void 
+asc_prt_hex(char *f, uchar *s, int l)
+{
+    int            i;
+    int            j;
+    int            k;
+    int            m;
+
+    printk("%s: (%d bytes)\n", f, l);
+
+    for (i = 0; i < l; i += 32) {
+        
+        /* Display a maximum of 8 double-words per line. */
+        if ((k = (l - i) / 4) >= 8) {
+            k = 8;
+            m = 0;
+        } else {
+            m = (l - i) % 4 ;
+        }
+
+        for (j = 0; j < k; j++) {
+            printk(" %2.2X%2.2X%2.2X%2.2X",
+                (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1],
+                (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]);
+        }
+
+        switch (m) {
+        case 0:
+        default:
+            break;
+        case 1:
+            printk(" %2.2X",
+                (unsigned) s[i+(j*4)]);
+            break;
+        case 2:
+            printk(" %2.2X%2.2X",
+                (unsigned) s[i+(j*4)],
+                (unsigned) s[i+(j*4)+1]);
+            break;
+        case 3:
+            printk(" %2.2X%2.2X%2.2X",
+                (unsigned) s[i+(j*4)+1],
+                (unsigned) s[i+(j*4)+2],
+                (unsigned) s[i+(j*4)+3]);
+            break;
+        }
+
+        printk("\n");
+    }
+}
+#endif /* ADVANSYS_DEBUG */
+
+#ifdef ADVANSYS_ASSERT
+/*
+ * interrupts_enabled()
+ *
+ * Return 1 if interrupts are enabled, otherwise return 0.
+ */
+STATIC int
+interrupts_enabled(void)
+{
+    int flags;
+
+    save_flags(flags);
+    if (flags & 0x0200) {
+        return ASC_TRUE;
+    } else {
+        return ASC_FALSE;
+    }
+}
+#endif /* ADVANSYS_ASSERT */
+
+
+/*
+ * --- Asc Library Functions
+ */
+
+ASC_INITFUNC(
+STATIC ushort
+AscGetEisaChipCfg(
+                     PortAddr iop_base
+)
+)
+{
+    PortAddr            eisa_cfg_iop;
+
+    eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+      (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+    return (inpw(eisa_cfg_iop));
+}
+
+ASC_INITFUNC(
+STATIC uchar
+AscSetChipScsiID(
+                    PortAddr iop_base,
+                    uchar new_host_id
+)
 )
 {
-	ushort              cfg_lsw;
-	if (AscGetChipScsiID(iop_base) == new_host_id) {
-		return (new_host_id);
-	}
-	cfg_lsw = AscGetChipCfgLsw(iop_base);
-	cfg_lsw &= 0xF8FF;
-	cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8);
-	AscSetChipCfgLsw(iop_base, cfg_lsw);
-	return (AscGetChipScsiID(iop_base));
+    ushort              cfg_lsw;
+
+    if (AscGetChipScsiID(iop_base) == new_host_id) {
+        return (new_host_id);
+    }
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
+    cfg_lsw &= 0xF8FF;
+    cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8);
+    AscSetChipCfgLsw(iop_base, cfg_lsw);
+    return (AscGetChipScsiID(iop_base));
 }
 
-uchar
+ASC_INITFUNC(
+STATIC uchar
 AscGetChipScsiCtrl(
-					  PortAddr iop_base
+                      PortAddr iop_base
+)
 )
 {
-	uchar               sc;
-	AscSetBank(iop_base, 1);
-	sc = inp(iop_base + IOP_REG_SC);
-	AscSetBank(iop_base, 0);
-	return (sc);
+    uchar               sc;
+
+    AscSetBank(iop_base, 1);
+    sc = inp(iop_base + IOP_REG_SC);
+    AscSetBank(iop_base, 0);
+    return (sc);
 }
 
-uchar
+ASC_INITFUNC(
+STATIC uchar
 AscGetChipVersion(
-					 PortAddr iop_base,
-					 ushort bus_type
+                     PortAddr iop_base,
+                     ushort bus_type
+)
 )
 {
-	if ((bus_type & ASC_IS_EISA) != 0) {
-		PortAddr            eisa_iop;
-		uchar               revision;
-		eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
-		  (PortAddr) ASC_EISA_REV_IOP_MASK;
-		revision = inp(eisa_iop);
-		return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision));
-	}
-	return (AscGetChipVerNo(iop_base));
+    if ((bus_type & ASC_IS_EISA) != 0) {
+        PortAddr            eisa_iop;
+        uchar               revision;
+        eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+          (PortAddr) ASC_EISA_REV_IOP_MASK;
+        revision = inp(eisa_iop);
+        return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision));
+    }
+    return (AscGetChipVerNo(iop_base));
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscGetChipBusType(
-					 PortAddr iop_base
+                     PortAddr iop_base
+)
 )
 {
-	ushort              chip_ver;
-	chip_ver = AscGetChipVerNo(iop_base);
-	if (
-		   (chip_ver >= ASC_CHIP_MIN_VER_VL)
-		   && (chip_ver <= ASC_CHIP_MAX_VER_VL)
-	  ) {
-		if (
-			   ((iop_base & 0x0C30) == 0x0C30)
-			   || ((iop_base & 0x0C50) == 0x0C50)
-		  ) {
-			return (ASC_IS_EISA);
-		}
-		return (ASC_IS_VL);
-	}
-	if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
-		(chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
-		if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
-			return (ASC_IS_ISAPNP);
-		}
-		return (ASC_IS_ISA);
-	} else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
-			   (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
-		return (ASC_IS_PCI);
-	}
-	return (0);
+    ushort              chip_ver;
+
+    chip_ver = AscGetChipVerNo(iop_base);
+    if (
+           (chip_ver >= ASC_CHIP_MIN_VER_VL)
+           && (chip_ver <= ASC_CHIP_MAX_VER_VL)
+) {
+        if (
+               ((iop_base & 0x0C30) == 0x0C30)
+               || ((iop_base & 0x0C50) == 0x0C50)
+) {
+            return (ASC_IS_EISA);
+        }
+        return (ASC_IS_VL);
+    }
+    if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
+        (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
+        if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
+            return (ASC_IS_ISAPNP);
+        }
+        return (ASC_IS_ISA);
+    } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
+               (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
+        return (ASC_IS_PCI);
+    }
+    return (0);
 }
 
-ulong
+ASC_INITFUNC(
+STATIC ulong
 AscLoadMicroCode(
-					PortAddr iop_base,
-					ushort s_addr,
-					ushort dosfar * mcode_buf,
-					ushort mcode_size
-)
-{
-	ulong               chksum;
-	ushort              mcode_word_size;
-	ushort              mcode_chksum;
-	mcode_word_size = (ushort) (mcode_size >> 1);
-	AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
-	AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
-	chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
-	mcode_chksum = (ushort) AscMemSumLramWord(iop_base,
-											  (ushort) ASC_CODE_SEC_BEG,
-		  (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2));
-	AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
-	AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
-	return (chksum);
+                    PortAddr iop_base,
+                    ushort s_addr,
+                    ushort *mcode_buf,
+                    ushort mcode_size
+)
+)
+{
+    ulong               chksum;
+    ushort              mcode_word_size;
+    ushort              mcode_chksum;
+
+    mcode_word_size = (ushort) (mcode_size >> 1);
+    AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+    AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+    chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+    mcode_chksum = (ushort) AscMemSumLramWord(iop_base,
+                                              (ushort) ASC_CODE_SEC_BEG,
+          (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2));
+    AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+    AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+    return (chksum);
 }
 
-int
+ASC_INITFUNC(
+STATIC int
 AscFindSignature(
-					PortAddr iop_base
+                    PortAddr iop_base
+)
 )
 {
-	ushort              sig_word;
-	if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) {
-		sig_word = AscGetChipSignatureWord(iop_base);
-		if ((sig_word == (ushort) ASC_1000_ID0W) ||
-			(sig_word == (ushort) ASC_1000_ID0W_FIX)) {
-			return (1);
-		}
-	}
-	return (0);
+    ushort              sig_word;
+
+    if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) {
+        sig_word = AscGetChipSignatureWord(iop_base);
+        if ((sig_word == (ushort) ASC_1000_ID0W) ||
+            (sig_word == (ushort) ASC_1000_ID0W_FIX)) {
+            return (1);
+        }
+    }
+    return (0);
 }
 
-uchar               _isa_pnp_inited = 0;
-PortAddr            _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] =
+STATIC uchar _isa_pnp_inited ASC_INITDATA = 0;
+STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA =
 {
-	0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
-	ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
+    0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
+    ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
 };
 
-PortAddr
+ASC_INITFUNC(
+STATIC PortAddr
 AscSearchIOPortAddr(
-					   PortAddr iop_beg,
-					   ushort bus_type
+                       PortAddr iop_beg,
+                       ushort bus_type
+)
 )
 {
-	if (bus_type & ASC_IS_VL) {
-		while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
-			if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) {
-				return (iop_beg);
-			}
-		}
-		return (0);
-	}
-	if (bus_type & ASC_IS_ISA) {
-		if (_isa_pnp_inited == 0) {
-			AscSetISAPNPWaitForKey();
-			_isa_pnp_inited++;
-		}
-		while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
-			if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) {
-				return (iop_beg);
-			}
-		}
-		return (0);
-	}
-	if (bus_type & ASC_IS_EISA) {
-		if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
-			return (iop_beg);
-		}
-		return (0);
-	}
-	return (0);
+    if (bus_type & ASC_IS_VL) {
+        while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+            if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) {
+                return (iop_beg);
+            }
+        }
+        return (0);
+    }
+    if (bus_type & ASC_IS_ISA) {
+        if (_isa_pnp_inited == 0) {
+            AscSetISAPNPWaitForKey();
+            _isa_pnp_inited++;
+        }
+        while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+            if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) {
+                return (iop_beg);
+            }
+        }
+        return (0);
+    }
+    if (bus_type & ASC_IS_EISA) {
+        if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
+            return (iop_beg);
+        }
+        return (0);
+    }
+    return (0);
 }
 
-PortAddr
+ASC_INITFUNC(
+STATIC PortAddr
 AscSearchIOPortAddr11(
-						 PortAddr s_addr
+                         PortAddr s_addr
+)
 )
 {
-	int                 i;
-	PortAddr            iop_base;
-	for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
-		if (_asc_def_iop_base[i] > s_addr) {
-			break;
-		}
-	}
-	for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
-		iop_base = _asc_def_iop_base[i];
-		if (check_region(iop_base, ASC_IOADR_GAP) != 0) {
-			ASC_DBG1(1,
-			   "AscSearchIOPortAddr11: check_region() failed I/O port %x\n",
-					 iop_base);
-			continue;
-		}
-		ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base);
-		if (AscFindSignature(iop_base)) {
-			return (iop_base);
-		}
-	}
-	return (0);
+    int                 i;
+    PortAddr            iop_base;
+
+    for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+        if (_asc_def_iop_base[i] > s_addr) {
+            break;
+        }
+    }
+    for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+        iop_base = _asc_def_iop_base[i];
+        if (check_region(iop_base, ASC_IOADR_GAP) != 0) {
+            ASC_DBG1(1,
+               "AscSearchIOPortAddr11: check_region() failed I/O port %x\n",
+                     iop_base);
+            continue;
+        }
+        ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base);
+        if (AscFindSignature(iop_base)) {
+            return (iop_base);
+        }
+    }
+    return (0);
 }
 
-void
+ASC_INITFUNC(
+STATIC void
 AscToggleIRQAct(
-				   PortAddr iop_base
+                   PortAddr iop_base
+)
 )
 {
-	AscSetChipStatus(iop_base, CIW_IRQ_ACT);
-	AscSetChipStatus(iop_base, 0);
-	return;
+    AscSetChipStatus(iop_base, CIW_IRQ_ACT);
+    AscSetChipStatus(iop_base, 0);
+    return;
 }
 
-#if CC_INIT_INQ_DISPLAY
-uchar               _hextbl_[16] =
-{
-	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-	'A', 'B', 'C', 'D', 'E', 'F'
-};
-#endif
-
-void
+ASC_INITFUNC(
+STATIC void
 AscSetISAPNPWaitForKey(
-	void)
+    void)
+)
 {
-	outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
-	outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
-	return;
+    outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
+    outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
+    return;
 }
 
-uchar
+ASC_INITFUNC(
+STATIC uchar
 AscGetChipIRQ(
-				 PortAddr iop_base,
-				 ushort bus_type
+                 PortAddr iop_base,
+                 ushort bus_type
+)
 )
 {
-	ushort              cfg_lsw;
-	uchar               chip_irq;
-	if ((bus_type & ASC_IS_EISA) != 0) {
-		cfg_lsw = AscGetEisaChipCfg(iop_base);
-		chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10);
-		if ((chip_irq == 13) || (chip_irq > 15)) {
-			return (0);
-		}
-		return (chip_irq);
-	}
-	if ((bus_type & ASC_IS_VL) != 0) {
-		cfg_lsw = AscGetChipCfgLsw(iop_base);
-		chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07));
-		if ((chip_irq == 0) ||
-			(chip_irq == 4) ||
-			(chip_irq == 7)) {
-			return (0);
-		}
-#if CC_PLEXTOR_VL
-		if (chip_irq == 5) {
-			return (9);
-		}
-#endif
-		return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1)));
-	}
-	cfg_lsw = AscGetChipCfgLsw(iop_base);
-	chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03));
-	if (chip_irq == 3)
-		chip_irq += (uchar) 2;
-	return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
+    ushort              cfg_lsw;
+    uchar               chip_irq;
+
+    if ((bus_type & ASC_IS_EISA) != 0) {
+        cfg_lsw = AscGetEisaChipCfg(iop_base);
+        chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10);
+        if ((chip_irq == 13) || (chip_irq > 15)) {
+            return (0);
+        }
+        return (chip_irq);
+    }
+    if ((bus_type & ASC_IS_VL) != 0) {
+        cfg_lsw = AscGetChipCfgLsw(iop_base);
+        chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07));
+        if ((chip_irq == 0) ||
+            (chip_irq == 4) ||
+            (chip_irq == 7)) {
+            return (0);
+        }
+        return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1)));
+    }
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
+    chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03));
+    if (chip_irq == 3)
+        chip_irq += (uchar) 2;
+    return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
 }
 
-uchar
+ASC_INITFUNC(
+STATIC uchar
 AscSetChipIRQ(
-				 PortAddr iop_base,
-				 uchar irq_no,
-				 ushort bus_type
+                 PortAddr iop_base,
+                 uchar irq_no,
+                 ushort bus_type
+)
 )
 {
-	ushort              cfg_lsw;
-	if ((bus_type & ASC_IS_VL) != 0) {
-		if (irq_no != 0) {
-#if CC_PLEXTOR_VL
-			if (irq_no == 9) {
-				irq_no = 14;
-			}
-#endif
-			if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) {
-				irq_no = 0;
-			} else {
-				irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1));
-			}
-		}
-		cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3);
-		cfg_lsw |= (ushort) 0x0010;
-		AscSetChipCfgLsw(iop_base, cfg_lsw);
-		AscToggleIRQAct(iop_base);
-		cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0);
-		cfg_lsw |= (ushort) ((irq_no & 0x07) << 2);
-		AscSetChipCfgLsw(iop_base, cfg_lsw);
-		AscToggleIRQAct(iop_base);
-		return (AscGetChipIRQ(iop_base, bus_type));
-	}
-	if ((bus_type & (ASC_IS_ISA)) != 0) {
-		if (irq_no == 15)
-			irq_no -= (uchar) 2;
-		irq_no -= (uchar) ASC_MIN_IRQ_NO;
-		cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3);
-		cfg_lsw |= (ushort) ((irq_no & 0x03) << 2);
-		AscSetChipCfgLsw(iop_base, cfg_lsw);
-		return (AscGetChipIRQ(iop_base, bus_type));
-	}
-	return (0);
+    ushort              cfg_lsw;
+
+    if ((bus_type & ASC_IS_VL) != 0) {
+        if (irq_no != 0) {
+            if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) {
+                irq_no = 0;
+            } else {
+                irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1));
+            }
+        }
+        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3);
+        cfg_lsw |= (ushort) 0x0010;
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        AscToggleIRQAct(iop_base);
+        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0);
+        cfg_lsw |= (ushort) ((irq_no & 0x07) << 2);
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        AscToggleIRQAct(iop_base);
+        return (AscGetChipIRQ(iop_base, bus_type));
+    }
+    if ((bus_type & (ASC_IS_ISA)) != 0) {
+        if (irq_no == 15)
+            irq_no -= (uchar) 2;
+        irq_no -= (uchar) ASC_MIN_IRQ_NO;
+        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3);
+        cfg_lsw |= (ushort) ((irq_no & 0x03) << 2);
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        return (AscGetChipIRQ(iop_base, bus_type));
+    }
+    return (0);
 }
 
-void
+ASC_INITFUNC(
+STATIC void
 AscEnableIsaDma(
-				   uchar dma_channel
+                   uchar dma_channel
+)
 )
 {
-	if (dma_channel < 4) {
-		outp(0x000B, (ushort) (0xC0 | dma_channel));
-		outp(0x000A, dma_channel);
-	} else if (dma_channel < 8) {
-		outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4)));
-		outp(0x00D4, (ushort) (dma_channel - 4));
-	}
-	return;
+    if (dma_channel < 4) {
+        outp(0x000B, (ushort) (0xC0 | dma_channel));
+        outp(0x000A, dma_channel);
+    } else if (dma_channel < 8) {
+        outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4)));
+        outp(0x00D4, (ushort) (dma_channel - 4));
+    }
+    return;
 }
 
-int
+STATIC int 
 AscIsrChipHalted(
-					REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	SDTR_XMSG           sdtr_xmsg;
-	SDTR_XMSG           out_msg;
-	ushort              halt_q_addr;
-	int                 sdtr_accept;
-	ushort              int_halt_code;
-	ASC_SCSI_BIT_ID_TYPE scsi_busy;
-	ASC_SCSI_BIT_ID_TYPE target_id;
-	PortAddr            iop_base;
-	uchar               tag_code;
-	uchar               q_status;
-	uchar               halt_qp;
-	uchar               sdtr_data = 0;
-	uchar               target_ix;
-	uchar               q_cntl, tid_no;
-	uchar               cur_dvc_qng;
-	uchar               asyn_sdtr;
-	uchar               scsi_status;
-	iop_base = asc_dvc->iop_base;
-	int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
-	halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
-	halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
-	target_ix = AscReadLramByte(iop_base,
-				   (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX));
-	q_cntl = AscReadLramByte(iop_base,
-						(ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL));
-	tid_no = ASC_TIX_TO_TID(target_ix);
-	target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
-	if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-		asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
-	} else {
-		asyn_sdtr = 0;
-	}
-	if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
-		if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-			AscSetChipSDTR(iop_base, 0, tid_no);
-		}
-		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-		return (0);
-	} else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
-		if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-			AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-		}
-		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-		return (0);
-	} else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
-		AscMemWordCopyFromLram(iop_base,
-							   ASCV_MSGIN_BEG,
-							   (ushort dosfar *) & sdtr_xmsg,
-							   (ushort) (sizeof (SDTR_XMSG) >> 1));
-		if (
-			   (sdtr_xmsg.msg_type == MS_EXTEND)
-			   && (sdtr_xmsg.msg_len == MS_SDTR_LEN)
-		  ) {
-			sdtr_accept = TRUE;
-			if (sdtr_xmsg.msg_req == MS_SDTR_CODE) {
-				if (
-					   (sdtr_xmsg.req_ack_offset > ASC_SYN_MAX_OFFSET)
-				  ) {
-					sdtr_accept = FALSE;
-					sdtr_xmsg.req_ack_offset = ASC_SYN_MAX_OFFSET;
-				}
-				if (
-					   (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index])
-					   || (sdtr_xmsg.xfer_period > asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])
-				  ) {
-					sdtr_accept = FALSE;
-					sdtr_xmsg.xfer_period = asc_dvc->sdtr_period_tbl[ asc_dvc->host_init_sdtr_index ] ;
-				}
-				if (sdtr_accept) {
-					sdtr_data = AscCalSDTRData(asc_dvc, sdtr_xmsg.xfer_period,
-											   sdtr_xmsg.req_ack_offset);
-					if ((sdtr_data == 0xFF)) {
-						q_cntl |= QC_MSG_OUT;
-						asc_dvc->init_sdtr &= ~target_id;
-						asc_dvc->sdtr_done &= ~target_id;
-						AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-					}
-				}
-				if (sdtr_xmsg.req_ack_offset == 0) {
-					q_cntl &= ~QC_MSG_OUT;
-					asc_dvc->init_sdtr &= ~target_id;
-					asc_dvc->sdtr_done &= ~target_id;
-					AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-				} else {
-					if (
-						   sdtr_accept
-						   && (q_cntl & QC_MSG_OUT)
-					  ) {
-						q_cntl &= ~QC_MSG_OUT;
-						asc_dvc->sdtr_done |= target_id;
-						asc_dvc->init_sdtr |= target_id;
-						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
-						sdtr_data = AscCalSDTRData(asc_dvc,
-							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
-						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
-					} else {
-						q_cntl |= QC_MSG_OUT;
-						AscMsgOutSDTR(asc_dvc,
-									  sdtr_xmsg.xfer_period,
-									  sdtr_xmsg.req_ack_offset);
-						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
-						sdtr_data = AscCalSDTRData(asc_dvc,
-							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
-						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
-						asc_dvc->sdtr_done |= target_id;
-						asc_dvc->init_sdtr |= target_id;
-					}
-				}
-				AscWriteLramByte(iop_base,
-						 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-								 q_cntl);
-				AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-				return (0);
-			}
-		}
-	} else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
-		q_cntl |= QC_REQ_SENSE;
-#if CC_CHK_COND_REDO_SDTR
-		if (((asc_dvc->init_sdtr & target_id) != 0) &&
-			((asc_dvc->sdtr_done & target_id) != 0)) {
-			asc_dvc->sdtr_done &= ~target_id;
-			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-			q_cntl |= QC_MSG_OUT;
-			AscMsgOutSDTR(asc_dvc,
-						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
-						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
-		}
-#endif
-		AscWriteLramByte(iop_base,
-						 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-						 q_cntl);
-		tag_code = AscReadLramByte(iop_base,
-					(ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE));
-		tag_code &= 0xDC;
-		if (
-			   (asc_dvc->pci_fix_asyn_xfer & target_id)
-			   && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
-		  ) {
-			tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
-						 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
-		}
-		AscWriteLramByte(iop_base,
-					 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE),
-						 tag_code);
-		q_status = AscReadLramByte(iop_base,
-					  (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS));
-		q_status |= (QS_READY | QS_BUSY);
-		AscWriteLramByte(iop_base,
-					   (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-						 q_status);
-		scsi_busy = AscReadLramByte(iop_base,
-									(ushort) ASCV_SCSIBUSY_B);
-		scsi_busy &= ~target_id;
-		AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy);
-		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-		return (0);
-	} else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
-		AscMemWordCopyFromLram(iop_base,
-							   ASCV_MSGOUT_BEG,
-							   (ushort dosfar *) & out_msg,
-							   (ushort) (sizeof (SDTR_XMSG) >> 1));
-		if ((out_msg.msg_type == MS_EXTEND) &&
-			(out_msg.msg_len == MS_SDTR_LEN) &&
-			(out_msg.msg_req == MS_SDTR_CODE)) {
-			asc_dvc->init_sdtr &= ~target_id;
-			asc_dvc->sdtr_done &= ~target_id;
-			AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-		} else {
-		}
-		q_cntl &= ~QC_MSG_OUT;
-		AscWriteLramByte(iop_base,
-						 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-						 q_cntl);
-		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-		return (0);
-	} else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
-		scsi_status = AscReadLramByte(iop_base,
-		  (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS));
-		cur_dvc_qng = AscReadLramByte(iop_base,
-					 (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix));
-		if ((cur_dvc_qng > 0) &&
-			(asc_dvc->cur_dvc_qng[tid_no] > 0)) {
-			scsi_busy = AscReadLramByte(iop_base,
-										(ushort) ASCV_SCSIBUSY_B);
-			scsi_busy |= target_id;
-			AscWriteLramByte(iop_base,
-							 (ushort) ASCV_SCSIBUSY_B, scsi_busy);
-			asc_dvc->queue_full_or_busy |= target_id;
-			if (scsi_status == SS_QUEUE_FULL) {
-				if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
-					cur_dvc_qng -= 1;
-					asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
-					AscWriteLramByte(iop_base,
-									 (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no),
-									 cur_dvc_qng);
-				}
-				{
-				asc_board_t		*boardp;
-				boardp = (asc_board_t *) asc_dvc->drv_ptr;
-
-				/*
-				 * Set the device queue depth to the number of
-				 * active requests when the QUEUE FULL condition
-				 * was encountered.
-				 */
-				boardp->queue_full |= target_id;
-				boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
+    EXT_MSG             ext_msg;
+    EXT_MSG             out_msg;
+    ushort              halt_q_addr;
+    int                 sdtr_accept;
+    ushort              int_halt_code;
+    ASC_SCSI_BIT_ID_TYPE scsi_busy;
+    ASC_SCSI_BIT_ID_TYPE target_id;
+    PortAddr            iop_base;
+    uchar               tag_code;
+    uchar               q_status;
+    uchar               halt_qp;
+    uchar               sdtr_data;
+    uchar               target_ix;
+    uchar               q_cntl, tid_no;
+    uchar               cur_dvc_qng;
+    uchar               asyn_sdtr;
+    uchar               scsi_status;
+    asc_board_t            *boardp;
+
+    ASC_ASSERT(asc_dvc->drv_ptr != 0);
+    boardp = (asc_board_t *) asc_dvc->drv_ptr;
+
+    iop_base = asc_dvc->iop_base;
+    int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
+
+    halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
+    halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
+    target_ix = AscReadLramByte(iop_base,
+                   (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX));
+    q_cntl = AscReadLramByte(iop_base,
+                        (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL));
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
+    if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+
+        asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
+    } else {
+        asyn_sdtr = 0;
+    }
+    if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
+        if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+            AscSetChipSDTR(iop_base, 0, tid_no);
+            boardp->sdtr_data[tid_no] = 0;
+        }
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
+        if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+            AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+            boardp->sdtr_data[tid_no] = asyn_sdtr;
+        }
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
+
+        AscMemWordCopyFromLram(iop_base,
+                               ASCV_MSGIN_BEG,
+                               (ushort *) & ext_msg,
+                               (ushort) (sizeof (EXT_MSG) >> 1));
+
+        if (ext_msg.msg_type == MS_EXTEND &&
+            ext_msg.msg_req == MS_SDTR_CODE &&
+            ext_msg.msg_len == MS_SDTR_LEN) {
+            sdtr_accept = TRUE;
+            if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
+
+                sdtr_accept = FALSE;
+                ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
+            }
+            if ((ext_msg.xfer_period <
+                 asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]) ||
+                (ext_msg.xfer_period >
+                 asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])) {
+                sdtr_accept = FALSE;
+                ext_msg.xfer_period =
+                    asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index];
+            }
+            if (sdtr_accept) {
+                sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+                                           ext_msg.req_ack_offset);
+                if ((sdtr_data == 0xFF)) {
+
+                    q_cntl |= QC_MSG_OUT;
+                    asc_dvc->init_sdtr &= ~target_id;
+                    asc_dvc->sdtr_done &= ~target_id;
+                    AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+                    boardp->sdtr_data[tid_no] = asyn_sdtr;
+                }
+            }
+            if (ext_msg.req_ack_offset == 0) {
+
+                q_cntl &= ~QC_MSG_OUT;
+                asc_dvc->init_sdtr &= ~target_id;
+                asc_dvc->sdtr_done &= ~target_id;
+                AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+            } else {
+                if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
+
+                    q_cntl &= ~QC_MSG_OUT;
+                    asc_dvc->sdtr_done |= target_id;
+                    asc_dvc->init_sdtr |= target_id;
+                    asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+                    sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+                                               ext_msg.req_ack_offset);
+                    AscSetChipSDTR(iop_base, sdtr_data, tid_no);
+                    boardp->sdtr_data[tid_no] = sdtr_data;
+                } else {
+
+                    q_cntl |= QC_MSG_OUT;
+                    AscMsgOutSDTR(asc_dvc,
+                                  ext_msg.xfer_period,
+                                  ext_msg.req_ack_offset);
+                    asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+                    sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+                                               ext_msg.req_ack_offset);
+                    AscSetChipSDTR(iop_base, sdtr_data, tid_no);
+                    boardp->sdtr_data[tid_no] = sdtr_data;
+                    asc_dvc->sdtr_done |= target_id;
+                    asc_dvc->init_sdtr |= target_id;
+                }
+            }
+
+            AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                             q_cntl);
+            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+            return (0);
+        } else if (ext_msg.msg_type == MS_EXTEND &&
+                   ext_msg.msg_req == MS_WDTR_CODE &&
+                   ext_msg.msg_len == MS_WDTR_LEN) {
+
+            ext_msg.wdtr_width = 0;
+            AscMemWordCopyToLram(iop_base,
+                                 ASCV_MSGOUT_BEG,
+                                 (ushort *) & ext_msg,
+                                 (ushort) (sizeof (EXT_MSG) >> 1));
+            q_cntl |= QC_MSG_OUT;
+            AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                             q_cntl);
+            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+            return (0);
+        } else {
+
+            ext_msg.msg_type = M1_MSG_REJECT;
+            AscMemWordCopyToLram(iop_base,
+                                 ASCV_MSGOUT_BEG,
+                                 (ushort *) & ext_msg,
+                                 (ushort) (sizeof (EXT_MSG) >> 1));
+            q_cntl |= QC_MSG_OUT;
+            AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                             q_cntl);
+            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+            return (0);
+        }
+    } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
+
+        q_cntl |= QC_REQ_SENSE;
+
+        if ((asc_dvc->init_sdtr & target_id) != 0) {
+
+            asc_dvc->sdtr_done &= ~target_id;
+
+            sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+            q_cntl |= QC_MSG_OUT;
+            AscMsgOutSDTR(asc_dvc,
+                          asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
+                           (uchar) (asc_dvc->max_sdtr_index - 1)],
+                          (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
+        }
+
+        AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                         q_cntl);
+
+        tag_code = AscReadLramByte(iop_base,
+                    (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE));
+        tag_code &= 0xDC;
+        if (
+               (asc_dvc->pci_fix_asyn_xfer & target_id)
+               && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
+) {
+
+            tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
+                         | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
+
+        }
+        AscWriteLramByte(iop_base,
+                     (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE),
+                         tag_code);
+
+        q_status = AscReadLramByte(iop_base,
+                      (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS));
+        q_status |= (QS_READY | QS_BUSY);
+        AscWriteLramByte(iop_base,
+                       (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+                         q_status);
+
+        scsi_busy = AscReadLramByte(iop_base,
+                                    (ushort) ASCV_SCSIBUSY_B);
+        scsi_busy &= ~target_id;
+        AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
+
+        AscMemWordCopyFromLram(iop_base,
+                               ASCV_MSGOUT_BEG,
+                               (ushort *) & out_msg,
+                               (ushort) (sizeof (EXT_MSG) >> 1));
+
+        if ((out_msg.msg_type == MS_EXTEND) &&
+            (out_msg.msg_len == MS_SDTR_LEN) &&
+            (out_msg.msg_req == MS_SDTR_CODE)) {
+
+            asc_dvc->init_sdtr &= ~target_id;
+            asc_dvc->sdtr_done &= ~target_id;
+            AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+            boardp->sdtr_data[tid_no] = asyn_sdtr;
+        }
+        q_cntl &= ~QC_MSG_OUT;
+        AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                         q_cntl);
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
+
+        scsi_status = AscReadLramByte(iop_base,
+          (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS));
+        cur_dvc_qng = AscReadLramByte(iop_base,
+                     (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix));
+        if ((cur_dvc_qng > 0) &&
+            (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
+
+            scsi_busy = AscReadLramByte(iop_base,
+                                        (ushort) ASCV_SCSIBUSY_B);
+            scsi_busy |= target_id;
+            AscWriteLramByte(iop_base,
+                             (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+            asc_dvc->queue_full_or_busy |= target_id;
+
+            if (scsi_status == SS_QUEUE_FULL) {
+                if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
+                    cur_dvc_qng -= 1;
+                    asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
+
+                    AscWriteLramByte(iop_base,
+                          (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG +
+                           (ushort) tid_no),
+                          cur_dvc_qng);
+
+                    /*
+                     * Set the device queue depth to the number of
+                     * active requests when the QUEUE FULL condition
+                     * was encountered.
+                     */
+                    boardp->queue_full |= target_id;
+                    boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
 #if ASC_QUEUE_FLOW_CONTROL
-				if (boardp->device[tid_no]->queue_curr_depth > cur_dvc_qng) {
-					boardp->device[tid_no]->queue_curr_depth = cur_dvc_qng;
-				}
+                    if (boardp->device[tid_no] != NULL &&
+                        boardp->device[tid_no]->queue_curr_depth >
+                        cur_dvc_qng) {
+                        boardp->device[tid_no]->queue_curr_depth =
+                            cur_dvc_qng;
+                    }
 #endif /* ASC_QUEUE_FLOW_CONTROL */
-				}
-			}
-		}
-		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-		return (0);
-	}
-	return (0);
+                }
+            }
+        }
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    }
+    return (0);
 }
 
-uchar
+STATIC uchar
 _AscCopyLramScsiDoneQ(
-						 PortAddr iop_base,
-						 ushort q_addr,
-						 REG ASC_QDONE_INFO dosfar * scsiq,
-						 ulong max_dma_count
-)
-{
-	ushort              _val;
-	uchar               sg_queue_cnt;
-	DvcGetQinfo(iop_base,
-				(ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG),
-				(ushort dosfar *) scsiq,
-			  (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2));
-#if !CC_LITTLE_ENDIAN_HOST
-	AscAdjEndianQDoneInfo(scsiq);
-#endif
-	_val = AscReadLramWord(iop_base,
-						   (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
-	scsiq->q_status = (uchar) _val;
-	scsiq->q_no = (uchar) (_val >> 8);
-	_val = AscReadLramWord(iop_base,
-						   (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL));
-	scsiq->cntl = (uchar) _val;
-	sg_queue_cnt = (uchar) (_val >> 8);
-	_val = AscReadLramWord(iop_base,
-						(ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
-	scsiq->sense_len = (uchar) _val;
-	scsiq->extra_bytes = (uchar) (_val >> 8);
-	scsiq->remain_bytes = AscReadLramDWord(iop_base,
-				 (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
-	scsiq->remain_bytes &= max_dma_count;
-	return (sg_queue_cnt);
+                         PortAddr iop_base,
+                         ushort q_addr,
+                         REG ASC_QDONE_INFO * scsiq,
+                         ulong max_dma_count
+)
+{
+    ushort              _val;
+    uchar               sg_queue_cnt;
+
+    DvcGetQinfo(iop_base,
+                (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG),
+                (ushort *) scsiq,
+              (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2));
+    _val = AscReadLramWord(iop_base,
+                           (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
+    scsiq->q_status = (uchar) _val;
+    scsiq->q_no = (uchar) (_val >> 8);
+    _val = AscReadLramWord(iop_base,
+                           (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL));
+    scsiq->cntl = (uchar) _val;
+    sg_queue_cnt = (uchar) (_val >> 8);
+    _val = AscReadLramWord(iop_base,
+                        (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
+    scsiq->sense_len = (uchar) _val;
+    scsiq->extra_bytes = (uchar) (_val >> 8);
+    scsiq->remain_bytes = AscReadLramWord(iop_base,
+                 (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+    scsiq->remain_bytes &= max_dma_count;
+    return (sg_queue_cnt);
 }
 
-int
+STATIC int
 AscIsrQDone(
-			   REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+               REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	uchar               next_qp;
-	uchar               n_q_used;
-	uchar               sg_list_qp;
-	uchar               sg_queue_cnt;
-	uchar               q_cnt;
-	uchar               done_q_tail;
-	uchar               tid_no;
-#if CC_LINK_BUSY_Q
-	uchar               exe_tid_no;
-#endif
-	ASC_SCSI_BIT_ID_TYPE scsi_busy;
-	ASC_SCSI_BIT_ID_TYPE target_id;
-	PortAddr            iop_base;
-	ushort              q_addr;
-	ushort              sg_q_addr;
-	uchar               cur_target_qng;
-	ASC_QDONE_INFO      scsiq_buf;
-	REG ASC_QDONE_INFO dosfar *scsiq;
-	int                 false_overrun;
-	ASC_ISR_CALLBACK    asc_isr_callback;
-#if CC_LINK_BUSY_Q
-	ushort              n_busy_q_done;
-#endif
-	iop_base = asc_dvc->iop_base;
-	asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
-	n_q_used = 1;
-	scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf;
-	done_q_tail = (uchar) AscGetVarDoneQTail(iop_base);
-	q_addr = ASC_QNO_TO_QADDR(done_q_tail);
-	next_qp = AscReadLramByte(iop_base,
-							  (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD));
-	if (next_qp != ASC_QLINK_END) {
-		AscPutVarDoneQTail(iop_base, next_qp);
-		q_addr = ASC_QNO_TO_QADDR(next_qp);
-		sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
-		AscWriteLramByte(iop_base,
-						 (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-			 (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED)));
-		tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
-		target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
-		if ((scsiq->cntl & QC_SG_HEAD) != 0) {
-			sg_q_addr = q_addr;
-			sg_list_qp = next_qp;
-			for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
-				sg_list_qp = AscReadLramByte(iop_base,
-						   (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD));
-				sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
-				if (sg_list_qp == ASC_QLINK_END) {
-					AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS);
-					scsiq->d3.done_stat = QD_WITH_ERROR;
-					scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED;
-					goto FATAL_ERR_QDONE;
-				}
-				AscWriteLramByte(iop_base,
-						 (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-								 QS_FREE);
-			}
-			n_q_used = sg_queue_cnt + 1;
-			AscPutVarDoneQTail(iop_base, sg_list_qp);
-		}
-		if (asc_dvc->queue_full_or_busy & target_id) {
-			cur_target_qng = AscReadLramByte(iop_base,
-			(ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix));
-			if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
-				scsi_busy = AscReadLramByte(iop_base,
-											(ushort) ASCV_SCSIBUSY_B);
-				scsi_busy &= ~target_id;
-				AscWriteLramByte(iop_base,
-								 (ushort) ASCV_SCSIBUSY_B, scsi_busy);
-				asc_dvc->queue_full_or_busy &= ~target_id;
-			}
-		}
-		if (asc_dvc->cur_total_qng >= n_q_used) {
-			asc_dvc->cur_total_qng -= n_q_used;
-			if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
-				asc_dvc->cur_dvc_qng[tid_no]--;
-			}
-		} else {
-			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
-			scsiq->d3.done_stat = QD_WITH_ERROR;
-			goto FATAL_ERR_QDONE;
-		}
-		if ((scsiq->d2.srb_ptr == 0UL) ||
-			((scsiq->q_status & QS_ABORTED) != 0)) {
-			return (0x11);
-		} else if (scsiq->q_status == QS_DONE) {
-			false_overrun = FALSE;
-			if (scsiq->extra_bytes != 0) {
-				scsiq->remain_bytes += (ulong) scsiq->extra_bytes;
-			}
-			if (scsiq->d3.done_stat == QD_WITH_ERROR) {
-				if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) {
-					if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) {
-						scsiq->d3.done_stat = QD_NO_ERROR;
-						scsiq->d3.host_stat = QHSTA_NO_ERROR;
-					} else if (false_overrun) {
-						scsiq->d3.done_stat = QD_NO_ERROR;
-						scsiq->d3.host_stat = QHSTA_NO_ERROR;
-					}
-				} else if (scsiq->d3.host_stat == QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
-					AscStopChip(iop_base);
-					AscSetChipControl(iop_base, (uchar) (CC_SCSI_RESET | CC_HALT));
-					DvcDelayNanoSecond(asc_dvc, 30000);
-					AscSetChipControl(iop_base, CC_HALT);
-					AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-					AscSetChipStatus(iop_base, 0);
-					AscSetChipControl(iop_base, 0);
-				}
-			}
-#if CC_CLEAR_LRAM_SRB_PTR
-			AscWriteLramDWord(iop_base,
-							(ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
-							  asc_dvc->int_count);
-#endif
-			if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
-				(*asc_isr_callback) (asc_dvc, scsiq);
-			} else {
-				if ((AscReadLramByte(iop_base,
-						  (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) ==
-					 SCSICMD_StartStopUnit)) {
-					asc_dvc->unit_not_ready &= ~target_id;
-					if (scsiq->d3.done_stat != QD_NO_ERROR) {
-						asc_dvc->start_motor &= ~target_id;
-					}
-				}
-			}
-#if CC_LINK_BUSY_Q
-			n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, tid_no);
-			if (n_busy_q_done == 0) {
-				exe_tid_no = (uint) tid_no + 1;
-				while (TRUE) {
-					if (exe_tid_no > ASC_MAX_TID)
-						exe_tid_no = 0;
-					if (exe_tid_no == (uint) tid_no)
-						break;
-					n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, exe_tid_no);
-					if (n_busy_q_done != 0)
-						break;
-					exe_tid_no++;
-				}
-			}
-			if (n_busy_q_done == 0xFFFF)
-				return (0x80);
-#endif
-			return (1);
-		} else {
-			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
-		  FATAL_ERR_QDONE:
-			if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
-				(*asc_isr_callback) (asc_dvc, scsiq);
-			}
-			return (0x80);
-		}
-	}
-	return (0);
+    uchar               next_qp;
+    uchar               n_q_used;
+    uchar               sg_list_qp;
+    uchar               sg_queue_cnt;
+    uchar               q_cnt;
+    uchar               done_q_tail;
+    uchar               tid_no;
+    ASC_SCSI_BIT_ID_TYPE scsi_busy;
+    ASC_SCSI_BIT_ID_TYPE target_id;
+    PortAddr            iop_base;
+    ushort              q_addr;
+    ushort              sg_q_addr;
+    uchar               cur_target_qng;
+    ASC_QDONE_INFO      scsiq_buf;
+    REG ASC_QDONE_INFO *scsiq;
+    int                 false_overrun;
+    ASC_ISR_CALLBACK    asc_isr_callback;
+
+    iop_base = asc_dvc->iop_base;
+    asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+    n_q_used = 1;
+    scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
+    done_q_tail = (uchar) AscGetVarDoneQTail(iop_base);
+    q_addr = ASC_QNO_TO_QADDR(done_q_tail);
+    next_qp = AscReadLramByte(iop_base,
+                              (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD));
+    if (next_qp != ASC_QLINK_END) {
+        AscPutVarDoneQTail(iop_base, next_qp);
+        q_addr = ASC_QNO_TO_QADDR(next_qp);
+        sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
+            asc_dvc->max_dma_count);
+        AscWriteLramByte(iop_base,
+                         (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+             (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED)));
+        tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
+        target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
+        if ((scsiq->cntl & QC_SG_HEAD) != 0) {
+            sg_q_addr = q_addr;
+            sg_list_qp = next_qp;
+            for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
+                sg_list_qp = AscReadLramByte(iop_base,
+                           (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD));
+                sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
+                if (sg_list_qp == ASC_QLINK_END) {
+                    AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS);
+                    scsiq->d3.done_stat = QD_WITH_ERROR;
+                    scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED;
+                    goto FATAL_ERR_QDONE;
+                }
+                AscWriteLramByte(iop_base,
+                         (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+                                 QS_FREE);
+            }
+            n_q_used = sg_queue_cnt + 1;
+            AscPutVarDoneQTail(iop_base, sg_list_qp);
+        }
+        if (asc_dvc->queue_full_or_busy & target_id) {
+            cur_target_qng = AscReadLramByte(iop_base,
+            (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix));
+            if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
+                scsi_busy = AscReadLramByte(iop_base,
+                                            (ushort) ASCV_SCSIBUSY_B);
+                scsi_busy &= ~target_id;
+                AscWriteLramByte(iop_base,
+                                 (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+                asc_dvc->queue_full_or_busy &= ~target_id;
+            }
+        }
+        if (asc_dvc->cur_total_qng >= n_q_used) {
+            asc_dvc->cur_total_qng -= n_q_used;
+            if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
+                asc_dvc->cur_dvc_qng[tid_no]--;
+            }
+        } else {
+            AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
+            scsiq->d3.done_stat = QD_WITH_ERROR;
+            goto FATAL_ERR_QDONE;
+        }
+        if ((scsiq->d2.srb_ptr == 0UL) ||
+            ((scsiq->q_status & QS_ABORTED) != 0)) {
+            return (0x11);
+        } else if (scsiq->q_status == QS_DONE) {
+            false_overrun = FALSE;
+            if (scsiq->extra_bytes != 0) {
+                scsiq->remain_bytes += (ulong) scsiq->extra_bytes;
+            }
+            if (scsiq->d3.done_stat == QD_WITH_ERROR) {
+                if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) {
+                    if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) {
+                        scsiq->d3.done_stat = QD_NO_ERROR;
+                        scsiq->d3.host_stat = QHSTA_NO_ERROR;
+                    } else if (false_overrun) {
+                        scsiq->d3.done_stat = QD_NO_ERROR;
+                        scsiq->d3.host_stat = QHSTA_NO_ERROR;
+                    }
+                } else if (scsiq->d3.host_stat ==
+                           QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
+                    AscStopChip(iop_base);
+                    AscSetChipControl(iop_base,
+                        (uchar) (CC_SCSI_RESET | CC_HALT));
+                    DvcDelayNanoSecond(asc_dvc, 60000);
+                    AscSetChipControl(iop_base, CC_HALT);
+                    AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+                    AscSetChipStatus(iop_base, 0);
+                    AscSetChipControl(iop_base, 0);
+                }
+            }
+            if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+                (*asc_isr_callback) (asc_dvc, scsiq);
+            } else {
+                if ((AscReadLramByte(iop_base,
+                          (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) ==
+                     SCSICMD_StartStopUnit)) {
+                    asc_dvc->unit_not_ready &= ~target_id;
+                    if (scsiq->d3.done_stat != QD_NO_ERROR) {
+                        asc_dvc->start_motor &= ~target_id;
+                    }
+                }
+            }
+            return (1);
+        } else {
+            AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
+          FATAL_ERR_QDONE:
+            if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+                (*asc_isr_callback) (asc_dvc, scsiq);
+            }
+            return (0x80);
+        }
+    }
+    return (0);
 }
 
-#if CC_LINK_BUSY_Q
-#endif
-
-int
+STATIC int
 AscISR(
-		  REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+          REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	ASC_CS_TYPE         chipstat;
-	PortAddr            iop_base;
-	ushort              saved_ram_addr;
-	uchar               ctrl_reg;
-	uchar               saved_ctrl_reg;
-	int                 int_pending;
-	int                 status;
-	uchar               host_flag;
-	iop_base = asc_dvc->iop_base;
-	int_pending = FALSE;
-	if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
-		|| (asc_dvc->isr_callback == 0)
-	  ) {
-		return (ERR);
-	}
-	if (asc_dvc->in_critical_cnt != 0) {
-		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
-		return (ERR);
-	}
-	if (asc_dvc->is_in_int) {
-		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
-		return (ERR);
-	}
-	asc_dvc->is_in_int = TRUE;
-	ctrl_reg = AscGetChipControl(iop_base);
-	saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
-								   CC_SINGLE_STEP | CC_DIAG | CC_TEST));
-	chipstat = AscGetChipStatus(iop_base);
-	if (chipstat & CSW_SCSI_RESET_LATCH) {
-		if (
-			   !(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))
-		  ) {
-			int_pending = TRUE;
-			asc_dvc->sdtr_done = 0;
-			saved_ctrl_reg &= (uchar) (~CC_HALT);
-			while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
-			AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
-			AscSetChipControl(iop_base, CC_HALT);
-			AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-			AscSetChipStatus(iop_base, 0);
-			chipstat = AscGetChipStatus(iop_base);
-		}
-	}
-	saved_ram_addr = AscGetChipLramAddr(iop_base);
-	host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR);
-	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
-					 (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR));
-#if CC_ASCISR_CHECK_INT_PENDING
-	if ((chipstat & CSW_INT_PENDING)
-		|| (int_pending)
-	  ) {
-		AscAckInterrupt(iop_base);
-#endif
-		int_pending = TRUE;
-		if ((chipstat & CSW_HALTED) &&
-			(ctrl_reg & CC_SINGLE_STEP)) {
-			if (AscIsrChipHalted(asc_dvc) == ERR) {
-				goto ISR_REPORT_QDONE_FATAL_ERROR;
-			} else {
-				saved_ctrl_reg &= (uchar) (~CC_HALT);
-			}
-		} else {
-		  ISR_REPORT_QDONE_FATAL_ERROR:
-			if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
-				while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) {
-				}
-			} else {
-				do {
-					if ((status = AscIsrQDone(asc_dvc)) == 1) {
-						break;
-					}
-				} while (status == 0x11);
-			}
-			if ((status & 0x80) != 0)
-				int_pending = ERR;
-		}
-#if CC_ASCISR_CHECK_INT_PENDING
-	}
-#endif
-	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
-	AscSetChipLramAddr(iop_base, saved_ram_addr);
-	AscSetChipControl(iop_base, saved_ctrl_reg);
-	asc_dvc->is_in_int = FALSE;
-	return (int_pending);
+    ASC_CS_TYPE         chipstat;
+    PortAddr            iop_base;
+    ushort              saved_ram_addr;
+    uchar               ctrl_reg;
+    uchar               saved_ctrl_reg;
+    int                 int_pending;
+    int                 status;
+    uchar               host_flag;
+
+    iop_base = asc_dvc->iop_base;
+    int_pending = FALSE;
+    if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
+        || (asc_dvc->isr_callback == 0)
+) {
+        return (ERR);
+    }
+    if (asc_dvc->in_critical_cnt != 0) {
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
+        return (ERR);
+    }
+    if (asc_dvc->is_in_int) {
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
+        return (ERR);
+    }
+    asc_dvc->is_in_int = TRUE;
+    ctrl_reg = AscGetChipControl(iop_base);
+    saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
+                                   CC_SINGLE_STEP | CC_DIAG | CC_TEST));
+    chipstat = AscGetChipStatus(iop_base);
+    if (chipstat & CSW_SCSI_RESET_LATCH) {
+        if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+            int_pending = TRUE;
+            asc_dvc->sdtr_done = 0;
+            saved_ctrl_reg &= (uchar) (~CC_HALT);
+            while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+            AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
+            AscSetChipControl(iop_base, CC_HALT);
+            AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+            AscSetChipStatus(iop_base, 0);
+            chipstat = AscGetChipStatus(iop_base);
+        }
+    }
+    saved_ram_addr = AscGetChipLramAddr(iop_base);
+    host_flag = AscReadLramByte(iop_base,
+        ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR);
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+                     (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR));
+    if ((chipstat & CSW_INT_PENDING)
+        || (int_pending)
+) {
+        AscAckInterrupt(iop_base);
+        int_pending = TRUE;
+        if ((chipstat & CSW_HALTED) &&
+            (ctrl_reg & CC_SINGLE_STEP)) {
+            if (AscIsrChipHalted(asc_dvc) == ERR) {
+                goto ISR_REPORT_QDONE_FATAL_ERROR;
+            } else {
+                saved_ctrl_reg &= (uchar) (~CC_HALT);
+            }
+        } else {
+          ISR_REPORT_QDONE_FATAL_ERROR:
+            if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
+                while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) {
+                }
+            } else {
+                do {
+                    if ((status = AscIsrQDone(asc_dvc)) == 1) {
+                        break;
+                    }
+                } while (status == 0x11);
+            }
+            if ((status & 0x80) != 0)
+                int_pending = ERR;
+        }
+    }
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+    AscSetChipLramAddr(iop_base, saved_ram_addr);
+    AscSetChipControl(iop_base, saved_ctrl_reg);
+    asc_dvc->is_in_int = FALSE;
+    return (int_pending);
 }
 
-int
+STATIC int
 AscScsiSetupCmdQ(
-					REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					REG ASC_SCSI_REQ_Q dosfar * scsiq,
-					uchar dosfar * buf_addr,
-					ulong buf_len
-)
-{
-	ulong               phy_addr;
-	scsiq->r1.cntl = 0;
-	scsiq->r1.sg_queue_cnt = 0;
-	scsiq->r1.q_no = 0;
-	scsiq->r1.extra_bytes = 0;
-	scsiq->r3.scsi_stat = 0;
-	scsiq->r3.scsi_msg = 0;
-	scsiq->r3.host_stat = 0;
-	scsiq->r3.done_stat = 0;
-	scsiq->r2.vm_id = 0;
-	scsiq->r1.data_cnt = buf_len;
-	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
-	scsiq->sense_ptr = (uchar dosfar *) scsiq->sense ;
-	scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ;
-	scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE;
-	scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ;
-	scsiq->r2.srb_ptr = (ulong) scsiq;
-	scsiq->r1.status = (uchar) QS_READY;
-	scsiq->r1.data_addr = 0L;
-	if (buf_len != 0L) {
-		if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
-					(uchar dosfar *) buf_addr, scsiq->r1.data_cnt)) == 0L) {
-			return (ERR);
-		}
-		scsiq->r1.data_addr = phy_addr;
-	}
-	if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
-                       (uchar dosfar *) scsiq->sense_ptr,
-                       (ulong) scsiq->r1.sense_len )) == 0L) {
-		return (ERR);
-	}
-	scsiq->r1.sense_addr = phy_addr ;
-	return (0);
+                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                    REG ASC_SCSI_REQ_Q * scsiq,
+                    uchar * buf_addr,
+                    ulong buf_len
+)
+{
+    ulong               phy_addr;
+
+    scsiq->r1.cntl = 0;
+    scsiq->r1.sg_queue_cnt = 0;
+    scsiq->r1.q_no = 0;
+    scsiq->r1.extra_bytes = 0;
+    scsiq->r3.scsi_stat = 0;
+    scsiq->r3.scsi_msg = 0;
+    scsiq->r3.host_stat = 0;
+    scsiq->r3.done_stat = 0;
+    scsiq->r2.vm_id = 0;
+    scsiq->r1.data_cnt = buf_len;
+    scsiq->cdbptr = (uchar *) scsiq->cdb;
+    scsiq->sense_ptr = (uchar *) scsiq->sense ;
+    scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ;
+    scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE;
+    scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ;
+    scsiq->r2.srb_ptr = (ulong) scsiq;
+    scsiq->r1.status = (uchar) QS_READY;
+    scsiq->r1.data_addr = 0L;
+    if (buf_len != 0L) {
+        if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+                    (uchar *) buf_addr, scsiq->r1.data_cnt)) == 0L) {
+            return (ERR);
+        }
+        scsiq->r1.data_addr = phy_addr;
+    }
+    if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+                       (uchar *) scsiq->sense_ptr,
+                       (ulong) scsiq->r1.sense_len)) == 0L) {
+        return (ERR);
+    }
+    scsiq->r1.sense_addr = phy_addr ;
+    return (0);
 }
 
-uchar _mcode_buf[ ] = {
+STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
+{
   0x01,  0x03,  0x01,  0x19,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x10,  0x0D,  0x09,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xDB,  0x0C,  0x0A,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x23,  0x00,  0x21,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
-  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xDC,  0x88,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x23,  0x00,  0x23,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
+  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xD4,  0x88,  0x00,  0x00,  0x00,  0x00,
   0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
   0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
-  0x18,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
-  0x4F,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
+  0x10,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x3A,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
+  0x4F,  0x00,  0xF5,  0x00,  0x3A,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
   0x92,  0x80,  0x00,  0x46,  0x17,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
-  0x00,  0xA3,  0xD6,  0x00,  0xA0,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0xD2,  0xC1,
-  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xE2,  0x01,  0xA0,  0x97,  0xCE,  0x81,  0x00,  0x33,
-  0x02,  0x00,  0xBA,  0x88,  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0x02,  0x01,  0x4F,  0x00,
-  0x7E,  0x97,  0x07,  0xA6,  0x0C,  0x01,  0x00,  0x33,  0x03,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xDE,
-  0x00,  0x33,  0x05,  0x00,  0xBA,  0x88,  0xCE,  0x00,  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,
+  0x00,  0xA3,  0xD6,  0x00,  0x98,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xE0,  0x84,  0xD2,  0xC1,
+  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xE2,  0x01,  0x98,  0x97,  0xCE,  0x81,  0x00,  0x33,
+  0x02,  0x00,  0xB2,  0x88,  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0x02,  0x01,  0x4F,  0x00,
+  0x76,  0x97,  0x07,  0xA6,  0x0C,  0x01,  0x00,  0x33,  0x03,  0x00,  0xB2,  0x88,  0x03,  0x03,  0x03,  0xDE,
+  0x00,  0x33,  0x05,  0x00,  0xB2,  0x88,  0xCE,  0x00,  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,
   0x00,  0xA2,  0x80,  0x01,  0x80,  0x63,  0x07,  0xA6,  0x2C,  0x01,  0x80,  0x81,  0x03,  0x03,  0x80,  0x63,
-  0xE2,  0x00,  0x07,  0xA6,  0x3C,  0x01,  0x00,  0x33,  0x04,  0x00,  0xBA,  0x88,  0x03,  0x07,  0x02,  0x01,
-  0x04,  0xCA,  0x0D,  0x23,  0x62,  0x98,  0x4D,  0x04,  0xEA,  0x84,  0x05,  0xD8,  0x0D,  0x23,  0x62,  0x98,
-  0xCD,  0x04,  0x15,  0x23,  0xF0,  0x88,  0xFB,  0x23,  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,
-  0x06,  0xA3,  0x6A,  0x01,  0x00,  0x33,  0x0A,  0x00,  0xBA,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x76,  0x01,
-  0x00,  0x33,  0x0B,  0x00,  0xBA,  0x88,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xBA,  0x88,
+  0xE2,  0x00,  0x07,  0xA6,  0x3C,  0x01,  0x00,  0x33,  0x04,  0x00,  0xB2,  0x88,  0x03,  0x07,  0x02,  0x01,
+  0x04,  0xCA,  0x0D,  0x23,  0x5A,  0x98,  0x4D,  0x04,  0xFE,  0x84,  0x05,  0xD8,  0x0D,  0x23,  0x5A,  0x98,
+  0xCD,  0x04,  0x15,  0x23,  0xE8,  0x88,  0xFB,  0x23,  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,
+  0x06,  0xA3,  0x6A,  0x01,  0x00,  0x33,  0x0A,  0x00,  0xB2,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x76,  0x01,
+  0x00,  0x33,  0x0B,  0x00,  0xB2,  0x88,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xB2,  0x88,
   0x50,  0x04,  0x90,  0x81,  0x06,  0xAB,  0x8A,  0x01,  0x90,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x9A,  0x01,
-  0x50,  0x00,  0x00,  0xA3,  0x44,  0x01,  0x00,  0x05,  0x84,  0x81,  0x40,  0x97,  0x02,  0x01,  0x05,  0xC6,
+  0x50,  0x00,  0x00,  0xA3,  0x44,  0x01,  0x00,  0x05,  0x84,  0x81,  0x38,  0x97,  0x02,  0x01,  0x05,  0xC6,
   0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,  0xC6,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,
   0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xBC,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,
-  0x00,  0x33,  0x1B,  0x00,  0xBA,  0x88,  0x06,  0x23,  0x62,  0x98,  0xCD,  0x04,  0xCC,  0x84,  0x06,  0x01,
-  0x00,  0xA2,  0xDC,  0x01,  0x57,  0x60,  0x00,  0xA0,  0xE2,  0x01,  0xCC,  0x84,  0x80,  0x23,  0xA0,  0x01,
-  0xCC,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x08,  0x02,  0x04,  0x01,  0x0C,  0xDE,
-  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x7E,  0x97,  0x04,  0x82,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,
-  0x4F,  0x00,  0x5C,  0x97,  0x48,  0x04,  0x84,  0x80,  0xEA,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,
+  0x00,  0x33,  0x1B,  0x00,  0xB2,  0x88,  0x06,  0x23,  0x5A,  0x98,  0xCD,  0x04,  0xE0,  0x84,  0x06,  0x01,
+  0x00,  0xA2,  0xDC,  0x01,  0x57,  0x60,  0x00,  0xA0,  0xE2,  0x01,  0xE0,  0x84,  0x80,  0x23,  0xA0,  0x01,
+  0xE0,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x08,  0x02,  0x04,  0x01,  0x0C,  0xDE,
+  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x76,  0x97,  0x04,  0x82,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,
+  0x4F,  0x00,  0x54,  0x97,  0x48,  0x04,  0x84,  0x80,  0xE2,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,
   0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x67,  0xEB,
-  0x11,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0xF4,  0x80,  0x80,  0x73,  0x80,  0x77,  0x06,  0xA6,  0x36,  0x02,
-  0x00,  0x33,  0x31,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x03,  0xD8,  0xAC,  0x98,  0x36,  0x96,  0x48,  0x82,
-  0xC6,  0x95,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x72,  0x02,  0x07,  0xA6,
-  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x03,  0xA6,  0x68,  0x02,  0x00,  0x33,  0x10,  0x00,  0xBA,  0x88,
-  0x62,  0x95,  0x4A,  0x82,  0x2C,  0x96,  0x4A,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,
-  0x22,  0x84,  0x04,  0x01,  0x0C,  0xDC,  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,
+  0x11,  0x23,  0xE8,  0x88,  0xF6,  0x97,  0xF4,  0x80,  0x80,  0x73,  0x80,  0x77,  0x06,  0xA6,  0x36,  0x02,
+  0x00,  0x33,  0x31,  0x00,  0xB2,  0x88,  0x04,  0x01,  0x03,  0xD8,  0xA4,  0x98,  0x4C,  0x96,  0x48,  0x82,
+  0xDC,  0x95,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x72,  0x02,  0x07,  0xA6,
+  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x03,  0xA6,  0x68,  0x02,  0x00,  0x33,  0x10,  0x00,  0xB2,  0x88,
+  0x76,  0x95,  0x4A,  0x82,  0x42,  0x96,  0x4A,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,
+  0x36,  0x84,  0x04,  0x01,  0x0C,  0xDC,  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,
   0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,
-  0x1C,  0x01,  0x02,  0xA6,  0xA4,  0x02,  0x07,  0xA6,  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x00,  0x33,
-  0x12,  0x00,  0xBA,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x92,  0x02,  0x4D,  0x04,
-  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,
-  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xE4,  0x82,  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,
-  0xDC,  0x02,  0x04,  0x01,  0x98,  0xC8,  0x00,  0x33,  0x1F,  0x00,  0xBA,  0x88,  0x08,  0x31,  0x0A,  0x35,
-  0x0C,  0x39,  0x0E,  0x3D,  0x78,  0x98,  0xB6,  0x2D,  0x01,  0xA6,  0x0E,  0x03,  0x00,  0xA6,  0x0E,  0x03,
-  0x07,  0xA6,  0x06,  0x03,  0x06,  0xA6,  0x0A,  0x03,  0x03,  0xA6,  0x06,  0x04,  0x02,  0xA6,  0x72,  0x02,
-  0x00,  0x33,  0x33,  0x00,  0xBA,  0x88,  0x62,  0x95,  0xE8,  0x82,  0x2C,  0x96,  0xE8,  0x82,  0x7C,  0x98,
-  0x80,  0x42,  0x78,  0x98,  0x60,  0xE4,  0x04,  0x01,  0x29,  0xC8,  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,
-  0x4E,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x80,  0x98,  0x78,  0x98,  0x00,  0xA6,  0x10,  0x03,
-  0x07,  0xA6,  0x46,  0x03,  0x03,  0xA6,  0x22,  0x04,  0x06,  0xA6,  0x4A,  0x03,  0x01,  0xA6,  0x10,  0x03,
-  0x00,  0x33,  0x25,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x2C,  0x83,  0x2C,  0x96,  0x2C,  0x83,  0x04,  0x01,
-  0x0C,  0xCE,  0x03,  0xC8,  0x00,  0x33,  0x42,  0x00,  0xBA,  0x88,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,
-  0x6C,  0x03,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x28,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,
-  0x8C,  0x03,  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,
-  0x88,  0x03,  0x00,  0xA6,  0x88,  0x03,  0xFC,  0x83,  0x80,  0x42,  0x78,  0x98,  0x01,  0xA6,  0x96,  0x03,
-  0x00,  0xA6,  0xAE,  0x03,  0xFC,  0x83,  0xA0,  0x98,  0x80,  0x42,  0x01,  0xA6,  0x96,  0x03,  0x07,  0xA6,
-  0xA4,  0x03,  0xC6,  0x83,  0x62,  0x95,  0x9A,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xBA,  0x88,  0xA0,  0x98,
-  0x80,  0x42,  0x00,  0xA6,  0xAE,  0x03,  0x07,  0xA6,  0xBC,  0x03,  0xC6,  0x83,  0x62,  0x95,  0xB2,  0x83,
-  0x00,  0x33,  0x26,  0x00,  0xBA,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,
-  0x12,  0x23,  0xA1,  0x01,  0xFC,  0x83,  0x04,  0xF0,  0x80,  0x6B,  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,
-  0x03,  0xA6,  0xFA,  0x03,  0x07,  0xA6,  0xF2,  0x03,  0x06,  0xA6,  0xF6,  0x03,  0x00,  0x33,  0x17,  0x00,
-  0xBA,  0x88,  0x62,  0x95,  0xE0,  0x83,  0x2C,  0x96,  0xE0,  0x83,  0x06,  0x84,  0x04,  0xF0,  0x80,  0x6B,
-  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,  0xB6,  0x2D,  0x03,  0xA6,  0x22,  0x04,  0x07,  0xA6,  0x1A,  0x04,
-  0x06,  0xA6,  0x1E,  0x04,  0x00,  0x33,  0x30,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x06,  0x84,  0x2C,  0x96,
-  0x06,  0x84,  0x1D,  0x01,  0x06,  0xCC,  0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,
-  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,  0x07,  0xA6,  0x40,  0x04,  0x00,  0x33,  0x18,  0x00,  0xBA,  0x88,
-  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,  0x07,  0xA4,  0x4A,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x6C,  0x04,
-  0x0A,  0xA0,  0x5C,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1D,  0x00,  0xBA,  0x88,  0x0B,  0xA0,  0x68,  0x04,
-  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,  0xBA,  0x88,  0x42,  0x23,  0xF0,  0x88,  0x00,  0x23,  0x22,  0xA3,
-  0xCC,  0x04,  0x08,  0x23,  0x22,  0xA3,  0x88,  0x04,  0x28,  0x23,  0x22,  0xA3,  0x94,  0x04,  0x02,  0x23,
-  0x22,  0xA3,  0xAA,  0x04,  0x42,  0x23,  0xF0,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0x94,  0x04,
-  0x45,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0x00,  0xA2,  0xA6,  0x04,  0xAC,  0x98,  0x00,  0x33,  0x00,  0x82,
-  0xC0,  0x20,  0x81,  0x62,  0xF0,  0x81,  0x47,  0x23,  0xF0,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0xFE,  0x97,
-  0xAC,  0x98,  0x00,  0x33,  0x00,  0x81,  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x08,  0x02,
-  0x43,  0x23,  0xF0,  0x88,  0x04,  0x23,  0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,
-  0x03,  0xA3,  0xDA,  0x04,  0x00,  0x33,  0x27,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,
-  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xFE,  0x97,  0x0C,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,
-  0x4F,  0x00,  0x00,  0xA3,  0x08,  0x05,  0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x05,
-  0xF0,  0x84,  0x40,  0x97,  0xCD,  0x04,  0x0A,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,
-  0x80,  0x23,  0x82,  0x01,  0x1A,  0x85,  0x02,  0x23,  0xA0,  0x01,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
-  0x26,  0x05,  0x1D,  0x01,  0x04,  0xD6,  0xFF,  0x23,  0x86,  0x41,  0x4B,  0x60,  0xCB,  0x00,  0xFF,  0x23,
-  0x80,  0x01,  0x49,  0x00,  0x81,  0x01,  0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,
-  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,  0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x46,  0x05,
-  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,  0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,
-  0x00,  0x63,  0x07,  0xA4,  0xC4,  0x05,  0x03,  0x03,  0x02,  0xA0,  0x74,  0x05,  0xC0,  0x85,  0x00,  0x33,
-  0x2D,  0x00,  0xBA,  0x88,  0x04,  0xA0,  0x9A,  0x05,  0x80,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
-  0x86,  0x05,  0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x5C,  0x97,
-  0xEA,  0x84,  0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0xEA,  0x84,  0x08,  0xA0,  0xA0,  0x05,  0xC0,  0x85,
-  0x03,  0xA0,  0xA6,  0x05,  0xC0,  0x85,  0x01,  0xA0,  0xB2,  0x05,  0x88,  0x00,  0x80,  0x63,  0xB0,  0x96,
-  0x62,  0x85,  0x07,  0xA0,  0xBE,  0x05,  0x06,  0x23,  0x62,  0x98,  0x48,  0x23,  0xF0,  0x88,  0xC0,  0x86,
-  0x80,  0x63,  0x62,  0x85,  0x00,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x06,  0x1D,  0x01,
-  0x18,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0xE4,  0x05,  0x00,  0x33,
-  0x37,  0x00,  0xBA,  0x88,  0x1D,  0x01,  0x02,  0xD6,  0x46,  0x23,  0xF0,  0x88,  0x63,  0x60,  0x83,  0x03,
-  0x80,  0x63,  0x06,  0xA6,  0xFC,  0x05,  0x00,  0x33,  0x38,  0x00,  0xBA,  0x88,  0xEF,  0x04,  0x6F,  0x00,
-  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1A,  0x06,
-  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,  0x04,  0xCC,  0x00,  0x33,
-  0x00,  0x83,  0xC0,  0x20,  0x81,  0x62,  0x80,  0x23,  0x07,  0x41,  0x00,  0x63,  0x80,  0x67,  0x08,  0x23,
-  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x06,  0xA6,  0x48,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x02,  0xA6,
-  0xF4,  0x06,  0x00,  0x33,  0x39,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x01,  0xA0,  0x0E,  0x07,  0xC6,  0x95,
-  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x5C,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x00,  0x01,  0xA0,
-  0x0E,  0x07,  0x00,  0x2B,  0x40,  0x0E,  0x80,  0x63,  0x01,  0x00,  0x06,  0xA6,  0x78,  0x06,  0x07,  0xA6,
-  0x9C,  0x06,  0x00,  0x33,  0x3A,  0x00,  0xBA,  0x88,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,
-  0x6A,  0x06,  0x06,  0xA6,  0x90,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x33,  0x3B,  0x00,  0xBA,  0x88,
-  0x80,  0x67,  0x40,  0x0E,  0x80,  0x63,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x63,  0x03,  0x03,  0x80,  0x63,
-  0x88,  0x00,  0x01,  0xA2,  0xB0,  0x06,  0x07,  0xA2,  0xF4,  0x06,  0x00,  0x33,  0x35,  0x00,  0xBA,  0x88,
-  0x07,  0xA6,  0xBA,  0x06,  0x00,  0x33,  0x2A,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xA2,  0xC6,  0x06,
-  0x07,  0x23,  0x80,  0x00,  0x00,  0x87,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,  0xD6,  0x06,
-  0x00,  0x33,  0x29,  0x00,  0xBA,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xE2,  0x06,  0xC0,  0x0E,  0x80,  0x63,
-  0xCC,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,  0x08,  0xDA,
-  0x80,  0x63,  0x00,  0x63,  0x80,  0x67,  0x00,  0x33,  0x00,  0x40,  0xC0,  0x20,  0x81,  0x62,  0x00,  0x63,
-  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x54,  0x06,  0x00,  0x33,  0x2C,  0x00,  0xBA,  0x88,  0x0C,  0xA2,
-  0x28,  0x07,  0xC6,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x26,  0x07,  0x07,  0xA6,  0x9C,  0x06,
-  0x00,  0x33,  0x3D,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,
-  0x3E,  0x07,  0x07,  0xA6,  0x9C,  0x06,  0xBF,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0x00,  0x63,
-  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,  0x01,  0x05,  0x80,  0x01,  0x72,  0x04,
-  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,
-  0x72,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x71,  0x00,  0x81,  0x01,
-  0x72,  0x00,  0x80,  0x01,  0x71,  0x04,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x00,  0x63,  0xF0,  0x04,
-  0xF2,  0x00,  0x72,  0x04,  0x00,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x71,  0x00,
-  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x00,  0x63,
-  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,  0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,
-  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xBE,  0x07,  0x00,  0x33,  0x07,  0x00,  0xBA,  0x88,  0x80,  0x05,
-  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,
-  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xDE,  0x07,  0x00,  0x05,  0xD4,  0x87,  0x00,  0x01,
-  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,
-  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF7,  0x04,
-  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x00,  0xA0,  0x0E,  0x08,  0x10,  0x88,  0x00,  0x43,
-  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x00,  0x23,  0xF4,  0x00,  0x74,  0x00,
-  0x80,  0x43,  0xF4,  0x00,  0xCF,  0x40,  0x00,  0xA2,  0x3E,  0x08,  0x74,  0x04,  0x02,  0x01,  0xF7,  0xC9,
-  0xF6,  0xD9,  0x00,  0x01,  0x01,  0xA1,  0x1E,  0x08,  0xFE,  0x97,  0x0C,  0x95,  0x1E,  0x88,  0x73,  0x04,
-  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x54,  0x88,  0x02,  0x01,  0x04,  0xD8,  0x40,  0x97,  0xFE,  0x97,
-  0x0C,  0x95,  0x44,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x5E,  0x08,  0x00,  0x05,  0x48,  0x88,  0x73,  0x04,
-  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x70,  0x08,  0x00,  0x33,  0x3E,  0x00,  0xBA,  0x88,
-  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,  0x96,  0x88,  0x38,  0x2B,  0x8C,  0x88,
-  0x32,  0x09,  0x31,  0x05,  0x8C,  0x98,  0x05,  0x05,  0xB2,  0x09,  0x00,  0x63,  0x00,  0x32,  0x00,  0x36,
-  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,  0x80,  0x3A,  0x80,  0x3E,  0x00,  0x63,
-  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,
-  0x00,  0xA0,  0xAC,  0x08,  0x5D,  0x00,  0xFE,  0xC3,  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,
-  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,  0x13,  0x23,  0xF0,  0x88,  0x66,  0x20,  0xC0,  0x20,
-  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,  0x81,  0x62,  0xDA,  0x88,  0x80,  0x73,  0x80,  0x77,
-  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,  0xF1,  0xC7,  0x41,  0x23,  0xF0,  0x88,  0x11,  0x23,
-  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xCC,  0x84,
-} ;
+  0x1C,  0x01,  0x02,  0xA6,  0xB0,  0x02,  0x07,  0xA6,  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x03,  0xA6,
+  0x1A,  0x04,  0x01,  0xA6,  0xBA,  0x02,  0x00,  0xA6,  0xBA,  0x02,  0x00,  0x33,  0x12,  0x00,  0xB2,  0x88,
+  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x92,  0x02,  0x4D,  0x04,  0x04,  0x01,  0x0B,  0xDC,
+  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,  0xEC,  0x00,  0x6C,  0x38,
+  0x00,  0x3F,  0x00,  0x00,  0xF0,  0x82,  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,  0xE8,  0x02,  0x04,  0x01,
+  0x9C,  0xC8,  0x00,  0x33,  0x1F,  0x00,  0xB2,  0x88,  0x08,  0x31,  0x0A,  0x35,  0x0C,  0x39,  0x0E,  0x3D,
+  0x70,  0x98,  0xB6,  0x2D,  0x01,  0xA6,  0x1A,  0x03,  0x00,  0xA6,  0x1A,  0x03,  0x07,  0xA6,  0x12,  0x03,
+  0x06,  0xA6,  0x16,  0x03,  0x03,  0xA6,  0x1A,  0x04,  0x02,  0xA6,  0x72,  0x02,  0x00,  0x33,  0x33,  0x00,
+  0xB2,  0x88,  0x76,  0x95,  0xF4,  0x82,  0x42,  0x96,  0xF4,  0x82,  0x74,  0x98,  0x80,  0x42,  0x70,  0x98,
+  0x60,  0xE4,  0x04,  0x01,  0x29,  0xC8,  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,  0x5A,  0x03,  0x00,  0x43,
+  0x87,  0x01,  0x05,  0x05,  0x78,  0x98,  0x70,  0x98,  0x00,  0xA6,  0x1C,  0x03,  0x07,  0xA6,  0x52,  0x03,
+  0x03,  0xA6,  0x36,  0x04,  0x06,  0xA6,  0x56,  0x03,  0x01,  0xA6,  0x1C,  0x03,  0x00,  0x33,  0x25,  0x00,
+  0xB2,  0x88,  0x76,  0x95,  0x38,  0x83,  0x42,  0x96,  0x38,  0x83,  0x04,  0x01,  0x0C,  0xCE,  0x03,  0xC8,
+  0x00,  0x33,  0x42,  0x00,  0xB2,  0x88,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,  0x78,  0x03,  0xB1,  0x01,
+  0x08,  0x23,  0xB2,  0x01,  0x34,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,  0x98,  0x03,  0xEC,  0x00,
+  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,  0x94,  0x03,  0x00,  0xA6,
+  0x94,  0x03,  0x0C,  0x84,  0x80,  0x42,  0x70,  0x98,  0x01,  0xA6,  0xA2,  0x03,  0x00,  0xA6,  0xBA,  0x03,
+  0x0C,  0x84,  0x98,  0x98,  0x80,  0x42,  0x01,  0xA6,  0xA2,  0x03,  0x07,  0xA6,  0xB0,  0x03,  0xD2,  0x83,
+  0x76,  0x95,  0xA6,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xB2,  0x88,  0x98,  0x98,  0x80,  0x42,  0x00,  0xA6,
+  0xBA,  0x03,  0x07,  0xA6,  0xC8,  0x03,  0xD2,  0x83,  0x76,  0x95,  0xBE,  0x83,  0x00,  0x33,  0x26,  0x00,
+  0xB2,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,  0x12,  0x23,  0xA1,  0x01,
+  0x0C,  0x84,  0x06,  0xF0,  0x06,  0xA4,  0xF0,  0x03,  0x80,  0x6B,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,
+  0x03,  0xA6,  0x0A,  0x04,  0x07,  0xA6,  0x02,  0x04,  0x06,  0xA6,  0x06,  0x04,  0x00,  0x33,  0x17,  0x00,
+  0xB2,  0x88,  0x76,  0x95,  0xF0,  0x83,  0x42,  0x96,  0xF0,  0x83,  0x1A,  0x84,  0x06,  0xF0,  0x06,  0xA4,
+  0x1A,  0x04,  0x80,  0x6B,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x03,  0xA6,  0x36,  0x04,
+  0x07,  0xA6,  0x2E,  0x04,  0x06,  0xA6,  0x32,  0x04,  0x00,  0x33,  0x30,  0x00,  0xB2,  0x88,  0x76,  0x95,
+  0x1A,  0x84,  0x42,  0x96,  0x1A,  0x84,  0x1D,  0x01,  0x06,  0xCC,  0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,
+  0x00,  0x23,  0xEA,  0x00,  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,  0x07,  0xA6,  0x54,  0x04,  0x00,  0x33,
+  0x18,  0x00,  0xB2,  0x88,  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,  0x07,  0xA4,  0x5E,  0x04,  0x23,  0x01,
+  0x00,  0xA2,  0x80,  0x04,  0x0A,  0xA0,  0x70,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1D,  0x00,  0xB2,  0x88,
+  0x0B,  0xA0,  0x7C,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,  0xB2,  0x88,  0x42,  0x23,  0xE8,  0x88,
+  0x00,  0x23,  0x22,  0xA3,  0xE0,  0x04,  0x08,  0x23,  0x22,  0xA3,  0x9C,  0x04,  0x28,  0x23,  0x22,  0xA3,
+  0xA8,  0x04,  0x02,  0x23,  0x22,  0xA3,  0xBE,  0x04,  0x42,  0x23,  0xE8,  0x88,  0x4A,  0x00,  0x06,  0x61,
+  0x00,  0xA0,  0xA8,  0x04,  0x45,  0x23,  0xE8,  0x88,  0xF6,  0x97,  0x00,  0xA2,  0xBA,  0x04,  0xA4,  0x98,
+  0x00,  0x33,  0x00,  0x82,  0xC0,  0x20,  0x81,  0x62,  0xF0,  0x81,  0x47,  0x23,  0xE8,  0x88,  0x04,  0x01,
+  0x0B,  0xDE,  0xF6,  0x97,  0xA4,  0x98,  0x00,  0x33,  0x00,  0x81,  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,
+  0x00,  0xA0,  0x08,  0x02,  0x43,  0x23,  0xE8,  0x88,  0x04,  0x23,  0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,
+  0x80,  0x73,  0x4D,  0x00,  0x03,  0xA3,  0xEE,  0x04,  0x00,  0x33,  0x27,  0x00,  0xB2,  0x88,  0x04,  0x01,
+  0x04,  0xDC,  0x02,  0x23,  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xF6,  0x97,  0x20,  0x95,  0x4B,  0x00,
+  0xF6,  0x00,  0x4F,  0x04,  0x4F,  0x00,  0x00,  0xA3,  0x1C,  0x05,  0x00,  0x05,  0x76,  0x00,  0x06,  0x61,
+  0x00,  0xA2,  0x16,  0x05,  0x04,  0x85,  0x38,  0x97,  0xCD,  0x04,  0x1E,  0x85,  0x48,  0x04,  0x84,  0x80,
+  0x02,  0x01,  0x03,  0xDA,  0x80,  0x23,  0x82,  0x01,  0x2E,  0x85,  0x02,  0x23,  0xA0,  0x01,  0x4A,  0x00,
+  0x06,  0x61,  0x00,  0xA2,  0x3A,  0x05,  0x1D,  0x01,  0x04,  0xD6,  0xFF,  0x23,  0x86,  0x41,  0x4B,  0x60,
+  0xCB,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x49,  0x00,  0x81,  0x01,  0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,
+  0x80,  0x01,  0xF7,  0x04,  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,  0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,
+  0xFF,  0xA0,  0x5A,  0x05,  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,  0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,
+  0x00,  0x23,  0xEA,  0x00,  0x00,  0x63,  0x07,  0xA4,  0xDA,  0x05,  0x03,  0x03,  0x02,  0xA0,  0x88,  0x05,
+  0xD6,  0x85,  0x00,  0x33,  0x2D,  0x00,  0xB2,  0x88,  0x04,  0xA0,  0xAE,  0x05,  0x80,  0x63,  0x4A,  0x00,
+  0x06,  0x61,  0x00,  0xA2,  0x9A,  0x05,  0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,
+  0x50,  0x00,  0x54,  0x97,  0xFE,  0x84,  0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0xFE,  0x84,  0x08,  0xA0,
+  0xB4,  0x05,  0xD6,  0x85,  0x03,  0xA0,  0xBA,  0x05,  0xD6,  0x85,  0x01,  0xA0,  0xC4,  0x05,  0x88,  0x00,
+  0x80,  0x63,  0xB2,  0x86,  0x07,  0xA0,  0xD0,  0x05,  0x06,  0x23,  0x5A,  0x98,  0x48,  0x23,  0xE8,  0x88,
+  0x07,  0x23,  0x80,  0x00,  0xF8,  0x86,  0x80,  0x63,  0x76,  0x85,  0x00,  0x63,  0x4A,  0x00,  0x06,  0x61,
+  0x00,  0xA2,  0x18,  0x06,  0x1D,  0x01,  0x18,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,  0x80,  0x63,
+  0x06,  0xA6,  0xFA,  0x05,  0x00,  0x33,  0x37,  0x00,  0xB2,  0x88,  0x1D,  0x01,  0x02,  0xD6,  0x46,  0x23,
+  0xE8,  0x88,  0x63,  0x60,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x12,  0x06,  0x00,  0x33,  0x38,  0x00,
+  0xB2,  0x88,  0xEF,  0x04,  0x6F,  0x00,  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,
+  0x06,  0x61,  0x00,  0xA2,  0x30,  0x06,  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,
+  0x1D,  0x01,  0x04,  0xCC,  0x00,  0x33,  0x00,  0x83,  0xC0,  0x20,  0x81,  0x62,  0x80,  0x23,  0x07,  0x41,
+  0x00,  0x63,  0x80,  0x67,  0x08,  0x23,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x06,  0xA6,  0x5E,  0x06,
+  0x07,  0xA6,  0x76,  0x05,  0x02,  0xA6,  0xEC,  0x06,  0x00,  0x33,  0x39,  0x00,  0xB2,  0x88,  0x00,  0x00,
+  0x01,  0xA0,  0x06,  0x07,  0xDC,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x72,  0x06,  0x07,  0xA6,
+  0x76,  0x05,  0x00,  0x00,  0x01,  0xA0,  0x06,  0x07,  0x00,  0x2B,  0x40,  0x0E,  0x80,  0x63,  0x01,  0x00,
+  0x06,  0xA6,  0x8E,  0x06,  0x07,  0xA6,  0x76,  0x05,  0x00,  0x33,  0x3A,  0x00,  0xB2,  0x88,  0x40,  0x0E,
+  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x80,  0x06,  0x06,  0xA6,  0xA6,  0x06,  0x07,  0xA6,  0x76,  0x05,
+  0x00,  0x33,  0x3B,  0x00,  0xB2,  0x88,  0x80,  0x67,  0x40,  0x0E,  0x80,  0x63,  0x07,  0xA6,  0x76,  0x05,
+  0x00,  0x63,  0x07,  0xA6,  0xBC,  0x06,  0x00,  0x33,  0x2A,  0x00,  0xB2,  0x88,  0x03,  0x03,  0x80,  0x63,
+  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,  0xCE,  0x06,  0x00,  0x33,  0x29,  0x00,  0xB2,  0x88,  0x00,  0x43,
+  0x00,  0xA2,  0xDA,  0x06,  0xC0,  0x0E,  0x80,  0x63,  0xC4,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,
+  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,  0x08,  0xDA,  0x80,  0x63,  0x76,  0x85,  0x80,  0x67,  0x00,  0x33,
+  0x00,  0x40,  0xC0,  0x20,  0x81,  0x62,  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x6A,  0x06,
+  0x00,  0x33,  0x2C,  0x00,  0xB2,  0x88,  0x0C,  0xA2,  0x20,  0x07,  0xDC,  0x95,  0x83,  0x03,  0x80,  0x63,
+  0x06,  0xA6,  0x1E,  0x07,  0x07,  0xA6,  0x76,  0x05,  0x00,  0x33,  0x3D,  0x00,  0xB2,  0x88,  0x00,  0x00,
+  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,  0x36,  0x07,  0x07,  0xA6,  0x76,  0x05,  0xBF,  0x23,
+  0x04,  0x61,  0x84,  0x01,  0xE0,  0x84,  0x00,  0x63,  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,
+  0xF2,  0x00,  0x01,  0x05,  0x80,  0x01,  0x72,  0x04,  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,
+  0x81,  0x05,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,  0x72,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x70,  0x00,
+  0x81,  0x01,  0x70,  0x04,  0x71,  0x00,  0x81,  0x01,  0x72,  0x00,  0x80,  0x01,  0x71,  0x04,  0x70,  0x00,
+  0x80,  0x01,  0x70,  0x04,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,  0x72,  0x04,  0x00,  0x01,  0xF1,  0x00,
+  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x71,  0x00,  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,
+  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x00,  0x63,  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,
+  0xA2,  0x01,  0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xB6,  0x07,
+  0x00,  0x33,  0x07,  0x00,  0xB2,  0x88,  0x80,  0x05,  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,
+  0xB0,  0x01,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,
+  0xD6,  0x07,  0x00,  0x05,  0xCC,  0x87,  0x00,  0x01,  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,
+  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,
+  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,
+  0x00,  0xA0,  0x06,  0x08,  0x08,  0x88,  0x00,  0x43,  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,
+  0xF3,  0x04,  0x00,  0x23,  0xF4,  0x00,  0x74,  0x00,  0x80,  0x43,  0xF4,  0x00,  0xCF,  0x40,  0x00,  0xA2,
+  0x36,  0x08,  0x74,  0x04,  0x02,  0x01,  0xF7,  0xC9,  0xF6,  0xD9,  0x00,  0x01,  0x01,  0xA1,  0x16,  0x08,
+  0xF6,  0x97,  0x20,  0x95,  0x16,  0x88,  0x73,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x4C,  0x88,
+  0x02,  0x01,  0x04,  0xD8,  0x38,  0x97,  0xF6,  0x97,  0x20,  0x95,  0x3C,  0x88,  0x75,  0x00,  0x00,  0xA3,
+  0x56,  0x08,  0x00,  0x05,  0x40,  0x88,  0x73,  0x04,  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,
+  0x68,  0x08,  0x00,  0x33,  0x3E,  0x00,  0xB2,  0x88,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,
+  0x38,  0x2B,  0x8E,  0x88,  0x38,  0x2B,  0x84,  0x88,  0x32,  0x09,  0x31,  0x05,  0x84,  0x98,  0x05,  0x05,
+  0xB2,  0x09,  0x00,  0x63,  0x00,  0x32,  0x00,  0x36,  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,
+  0x80,  0x36,  0x80,  0x3A,  0x80,  0x3E,  0x00,  0x63,  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,
+  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,  0x00,  0xA0,  0xA4,  0x08,  0x5D,  0x00,  0xFE,  0xC3,
+  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,
+  0x13,  0x23,  0xE8,  0x88,  0x66,  0x20,  0xC0,  0x20,  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,
+  0x81,  0x62,  0xD2,  0x88,  0x80,  0x73,  0x80,  0x77,  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,
+  0xF1,  0xC7,  0x41,  0x23,  0xE8,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE0,  0x84,
+
+};
 
-ushort _mcode_size = sizeof(_mcode_buf);
-ulong  _mcode_chksum = 0x012BA2FAUL ;
+STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf);
+STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012A727FUL ;
 
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
-uchar               _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
+STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
 {
-	SCSICMD_Inquiry,
-	SCSICMD_RequestSense,
-	SCSICMD_ReadCapacity,
-	SCSICMD_ReadTOC,
-	SCSICMD_ModeSelect6,
-	SCSICMD_ModeSense6,
-	SCSICMD_ModeSelect10,
-	SCSICMD_ModeSense10,
-	0xFF,
-	0xFF,
-	0xFF,
-	0xFF,
-	0xFF,
-	0xFF,
-	0xFF,
-	0xFF
+    SCSICMD_Inquiry,
+    SCSICMD_RequestSense,
+    SCSICMD_ReadCapacity,
+    SCSICMD_ReadTOC,
+    SCSICMD_ModeSelect6,
+    SCSICMD_ModeSense6,
+    SCSICMD_ModeSelect10,
+    SCSICMD_ModeSense10,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF
 };
 
-int
+STATIC int
 AscExeScsiQueue(
-				   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				   REG ASC_SCSI_Q dosfar * scsiq
+                   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                   REG ASC_SCSI_Q * scsiq
 )
 {
-	PortAddr            iop_base;
-	int                 last_int_level;
-	int                 sta;
-	int                 n_q_required;
-	int                 disable_syn_offset_one_fix;
-	int                 i;
-	ulong               addr;
-	ASC_EXE_CALLBACK    asc_exe_callback;
-	ushort              sg_entry_cnt = 0;
-	ushort              sg_entry_cnt_minus_one = 0;
-	uchar               target_ix;
-	uchar               tid_no;
-	uchar               sdtr_data;
-	uchar               extra_bytes;
-	uchar               scsi_cmd;
-	uchar               disable_cmd;
-	ASC_SG_HEAD dosfar *sg_head;
-	ulong               data_cnt;
-#if CC_LINK_BUSY_Q
-	ASC_SCSI_Q dosfar  *scsiq_tail;
-	ASC_SCSI_Q dosfar  *scsiq_next;
-	ASC_SCSI_Q dosfar  *scsiq_prev;
-#endif
-	iop_base = asc_dvc->iop_base;
-	sg_head = scsiq->sg_head;
-	asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback;
-	if (asc_dvc->err_code != 0)
-		return (ERR);
-	if (scsiq == (ASC_SCSI_Q dosfar *) 0L) {
-		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
-		return (ERR);
-	}
-	scsiq->q1.q_no = 0;
-	if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
-		scsiq->q1.extra_bytes = 0;
-	}
-	sta = 0;
-	target_ix = scsiq->q2.target_ix;
-	tid_no = ASC_TIX_TO_TID(target_ix);
-	n_q_required = 1;
-	if (scsiq->cdbptr[0] == SCSICMD_RequestSense) {
-		if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
-			((asc_dvc->sdtr_done & scsiq->q1.target_id) != 0)) {
-			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-			AscMsgOutSDTR(asc_dvc,
-						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
-						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
-			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
-		}
-	}
-	last_int_level = DvcEnterCritical();
-	if (asc_dvc->in_critical_cnt != 0) {
-		DvcLeaveCritical(last_int_level);
-		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
-		return (ERR);
-	}
-	asc_dvc->in_critical_cnt++;
-	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
-		if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
-			asc_dvc->in_critical_cnt--;
-			DvcLeaveCritical(last_int_level);
-			return (ERR);
-		}
-		if (sg_entry_cnt > ASC_MAX_SG_LIST) {
-			return (ERR);
-		}
-		if (sg_entry_cnt == 1) {
-			scsiq->q1.data_addr = sg_head->sg_list[0].addr;
-			scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
-			scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
-		} else {
-#if CC_CHK_AND_COALESCE_SG_LIST
-			AscCoalesceSgList(scsiq);
-			sg_entry_cnt = sg_head->entry_cnt;
-#endif
-		}
-		sg_entry_cnt_minus_one = sg_entry_cnt - 1;
-#if CC_DEBUG_SG_LIST
-		if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
-			for (i = 0; i < sg_entry_cnt_minus_one; i++) {
-				addr = sg_head->sg_list[i].addr + sg_head->sg_list[i].bytes;
-				if (((ushort) addr & 0x0003) != 0) {
-					asc_dvc->in_critical_cnt--;
-					DvcLeaveCritical(last_int_level);
-					AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_LIST_ODD_ADDRESS);
-					return (ERR);
-				}
-			}
-		}
-#endif
-	}
-	scsi_cmd = scsiq->cdbptr[0];
-	disable_syn_offset_one_fix = FALSE;
-	if (
-		   (asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id)
-		   && !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)
-	  ) {
-		if (scsiq->q1.cntl & QC_SG_HEAD) {
-			data_cnt = 0;
-			for (i = 0; i < sg_entry_cnt; i++) {
-				data_cnt += sg_head->sg_list[i].bytes;
-			}
-		} else {
-			data_cnt = scsiq->q1.data_cnt;
-		}
-		if (data_cnt != 0UL) {
-			if (data_cnt < 512UL) {
-				disable_syn_offset_one_fix = TRUE;
-			} else {
-				for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) {
-					disable_cmd = _syn_offset_one_disable_cmd[i];
-					if (disable_cmd == 0xFF) {
-						break;
-					}
-					if (scsi_cmd == disable_cmd) {
-						disable_syn_offset_one_fix = TRUE;
-						break;
-					}
-				}
-			}
-		}
-	}
-	if (disable_syn_offset_one_fix) {
-		scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
-		scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
-							   ASC_TAG_FLAG_DISABLE_DISCONNECT);
-	} else {
-		scsiq->q2.tag_code &= 0x23;
-	}
-	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
-		if (asc_dvc->bug_fix_cntl) {
-			if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-				if (
-					   (scsi_cmd == SCSICMD_Read6)
-					   || (scsi_cmd == SCSICMD_Read10)
-				  ) {
-					addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
-					  sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
-					extra_bytes = (uchar) ((ushort) addr & 0x0003);
-					if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
-						scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
-						scsiq->q1.extra_bytes = extra_bytes;
-						sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= (ulong) extra_bytes;
-					}
-				}
-			}
-		}
-		sg_head->entry_to_copy = sg_head->entry_cnt;
-		n_q_required = AscSgListToQueue(sg_entry_cnt);
-#if CC_LINK_BUSY_Q
-		scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no];
-		if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) {
-			goto link_scisq_to_busy_list;
-		}
-#endif
-		if (
-			   (AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required)
-				>= (uint) n_q_required) ||
-			   ((scsiq->q1.cntl & QC_URGENT) != 0)
-		  ) {
-			if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
-										n_q_required)) == 1) {
-				asc_dvc->in_critical_cnt--;
-				if (asc_exe_callback != 0) {
-					(*asc_exe_callback) (asc_dvc, scsiq);
-				}
-				DvcLeaveCritical(last_int_level);
-				return (sta);
-			}
-		}
-	} else {
-		if (asc_dvc->bug_fix_cntl) {
-			if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-				if (
-					   (scsi_cmd == SCSICMD_Read6)
-					   || (scsi_cmd == SCSICMD_Read10)
-				  ) {
-					addr = scsiq->q1.data_addr + scsiq->q1.data_cnt;
-					extra_bytes = (uchar) ((ushort) addr & 0x0003);
-					if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
-						if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
-							scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
-							scsiq->q1.data_cnt -= (ulong) extra_bytes;
-							scsiq->q1.extra_bytes = extra_bytes;
-						}
-					}
-				}
-			}
-		}
-		n_q_required = 1;
-#if CC_LINK_BUSY_Q
-		scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no];
-		if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) {
-			goto link_scisq_to_busy_list;
-		}
-#endif
-		if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
-			((scsiq->q1.cntl & QC_URGENT) != 0)) {
-			if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
-										n_q_required)) == 1) {
-				asc_dvc->in_critical_cnt--;
-				if (asc_exe_callback != 0) {
-					(*asc_exe_callback) (asc_dvc, scsiq);
-				}
-				DvcLeaveCritical(last_int_level);
-				return (sta);
-			}
-		}
-	}
-#if CC_LINK_BUSY_Q
-	if (sta == 0) {
-	  link_scisq_to_busy_list:
-		scsiq->ext.q_required = n_q_required;
-		if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) {
-			asc_dvc->scsiq_busy_head[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
-			asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
-			scsiq->ext.next = (ASC_SCSI_Q dosfar *) 0L;
-			scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
-			scsiq->q1.status = QS_BUSY;
-			sta = 1;
-		} else {
-			scsiq_tail = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_tail[tid_no];
-			if (scsiq_tail->ext.next == (ASC_SCSI_Q dosfar *) 0L) {
-				if ((scsiq->q1.cntl & QC_URGENT) != 0) {
-					asc_dvc->scsiq_busy_head[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
-					scsiq->ext.next = scsiq_next;
-					scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
-				} else {
-					if (scsiq->ext.cntl & QCX_SORT) {
-						do {
-							scsiq_prev = scsiq_next;
-							scsiq_next = scsiq_next->ext.next;
-							if (scsiq->ext.lba < scsiq_prev->ext.lba)
-								break;
-						} while (scsiq_next != (ASC_SCSI_Q dosfar *) 0L);
-						scsiq_prev->ext.next = scsiq;
-						scsiq->ext.next = scsiq_next;
-						if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) {
-							asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
-						}
-						scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
-					} else {
-						scsiq_tail->ext.next = (ASC_SCSI_Q dosfar *) scsiq;
-						asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
-						scsiq->ext.next = (ASC_SCSI_Q dosfar *) 0L;
-						scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
-					}
-				}
-				scsiq->q1.status = QS_BUSY;
-				sta = 1;
-			} else {
-				AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_BAD_NEXT_PTR);
-				sta = ERR;
-			}
-		}
-	}
-#endif
-	asc_dvc->in_critical_cnt--;
-	DvcLeaveCritical(last_int_level);
-	return (sta);
+    PortAddr            iop_base;
+    int                 last_int_level;
+    int                 sta;
+    int                 n_q_required;
+    int                 disable_syn_offset_one_fix;
+    int                 i;
+    ulong               addr;
+    ASC_EXE_CALLBACK    asc_exe_callback;
+    ushort              sg_entry_cnt = 0;
+    ushort              sg_entry_cnt_minus_one = 0;
+    uchar               target_ix;
+    uchar               tid_no;
+    uchar               sdtr_data;
+    uchar               extra_bytes;
+    uchar               scsi_cmd;
+    uchar               disable_cmd;
+    ASC_SG_HEAD *sg_head;
+    ulong               data_cnt;
+
+    iop_base = asc_dvc->iop_base;
+    sg_head = scsiq->sg_head;
+    asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback;
+    if (asc_dvc->err_code != 0)
+        return (ERR);
+    if (scsiq == (ASC_SCSI_Q *) 0L) {
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
+        return (ERR);
+    }
+    scsiq->q1.q_no = 0;
+    if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+        scsiq->q1.extra_bytes = 0;
+    }
+    sta = 0;
+    target_ix = scsiq->q2.target_ix;
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    n_q_required = 1;
+    if (scsiq->cdbptr[0] == SCSICMD_RequestSense) {
+        if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
+            asc_dvc->sdtr_done &= ~scsiq->q1.target_id ;
+            sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+            AscMsgOutSDTR(asc_dvc,
+                          asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
+                          (uchar) (asc_dvc->max_sdtr_index - 1)],
+                          (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
+            scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+        }
+    }
+    last_int_level = DvcEnterCritical();
+    if (asc_dvc->in_critical_cnt != 0) {
+        DvcLeaveCritical(last_int_level);
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+        return (ERR);
+    }
+    asc_dvc->in_critical_cnt++;
+    if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+        if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
+            asc_dvc->in_critical_cnt--;
+            DvcLeaveCritical(last_int_level);
+            return (ERR);
+        }
+        if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+            return (ERR);
+        }
+        if (sg_entry_cnt == 1) {
+            scsiq->q1.data_addr = sg_head->sg_list[0].addr;
+            scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
+            scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+        }
+        sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+    }
+    scsi_cmd = scsiq->cdbptr[0];
+    disable_syn_offset_one_fix = FALSE;
+    if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
+        !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
+        if (scsiq->q1.cntl & QC_SG_HEAD) {
+            data_cnt = 0;
+            for (i = 0; i < sg_entry_cnt; i++) {
+                data_cnt += sg_head->sg_list[i].bytes;
+            }
+        } else {
+            data_cnt = scsiq->q1.data_cnt;
+        }
+        if (data_cnt != 0UL) {
+            if (data_cnt < 512UL) {
+                disable_syn_offset_one_fix = TRUE;
+            } else {
+                for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) {
+                    disable_cmd = _syn_offset_one_disable_cmd[i];
+                    if (disable_cmd == 0xFF) {
+                        break;
+                    }
+                    if (scsi_cmd == disable_cmd) {
+                        disable_syn_offset_one_fix = TRUE;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    if (disable_syn_offset_one_fix) {
+        scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
+        scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
+                               ASC_TAG_FLAG_DISABLE_DISCONNECT);
+    } else {
+        scsiq->q2.tag_code &= 0x23;
+    }
+    if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+        if (asc_dvc->bug_fix_cntl) {
+            if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+                if ((scsi_cmd == SCSICMD_Read6) ||
+                    (scsi_cmd == SCSICMD_Read10)) {
+                    addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
+                      sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+                    extra_bytes = (uchar) ((ushort) addr & 0x0003);
+                    if ((extra_bytes != 0) &&
+                        ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
+                         == 0)) {
+                        scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
+                        scsiq->q1.extra_bytes = extra_bytes;
+                        sg_head->sg_list[sg_entry_cnt_minus_one].bytes -=
+                            (ulong) extra_bytes;
+                    }
+                }
+            }
+        }
+        sg_head->entry_to_copy = sg_head->entry_cnt;
+        n_q_required = AscSgListToQueue(sg_entry_cnt);
+        if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
+            (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+            if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+                                        n_q_required)) == 1) {
+                asc_dvc->in_critical_cnt--;
+                if (asc_exe_callback != 0) {
+                    (*asc_exe_callback) (asc_dvc, scsiq);
+                }
+                DvcLeaveCritical(last_int_level);
+                return (sta);
+            }
+        }
+    } else {
+        if (asc_dvc->bug_fix_cntl) {
+            if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+                if ((scsi_cmd == SCSICMD_Read6) ||
+                    (scsi_cmd == SCSICMD_Read10)) {
+                    addr = scsiq->q1.data_addr + scsiq->q1.data_cnt;
+                    extra_bytes = (uchar) ((ushort) addr & 0x0003);
+                    if ((extra_bytes != 0) &&
+                        ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
+                          == 0)) {
+                        if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
+                            scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
+                            scsiq->q1.data_cnt -= (ulong) extra_bytes;
+                            scsiq->q1.extra_bytes = extra_bytes;
+                        }
+                    }
+                }
+            }
+        }
+        n_q_required = 1;
+        if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+            ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+            if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+                                        n_q_required)) == 1) {
+                asc_dvc->in_critical_cnt--;
+                if (asc_exe_callback != 0) {
+                    (*asc_exe_callback) (asc_dvc, scsiq);
+                }
+                DvcLeaveCritical(last_int_level);
+                return (sta);
+            }
+        }
+    }
+    asc_dvc->in_critical_cnt--;
+    DvcLeaveCritical(last_int_level);
+    return (sta);
 }
 
-int
+STATIC int
 AscSendScsiQueue(
-					REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					REG ASC_SCSI_Q dosfar * scsiq,
-					uchar n_q_required
-)
-{
-	PortAddr            iop_base;
-	uchar               free_q_head;
-	uchar               next_qp;
-	uchar               tid_no;
-	uchar               target_ix;
-	int                 sta;
-	iop_base = asc_dvc->iop_base;
-	target_ix = scsiq->q2.target_ix;
-	tid_no = ASC_TIX_TO_TID(target_ix);
-	sta = 0;
-	free_q_head = (uchar) AscGetVarFreeQHead(iop_base);
-	if (n_q_required > 1) {
-		if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
-									   free_q_head, (uchar) (n_q_required)))
-			!= (uchar) ASC_QLINK_END) {
-			asc_dvc->last_q_shortage = 0;
-			scsiq->sg_head->queue_cnt = n_q_required - 1;
-			scsiq->q1.q_no = free_q_head;
-			if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
-											  free_q_head)) == 1) {
-#if CC_WRITE_IO_COUNT
-				asc_dvc->req_count++;
-#endif
-				AscPutVarFreeQHead(iop_base, next_qp);
-				asc_dvc->cur_total_qng += (uchar) (n_q_required);
-				asc_dvc->cur_dvc_qng[tid_no]++;
-			}
-			return (sta);
-		}
-	} else if (n_q_required == 1) {
-		if ((next_qp = AscAllocFreeQueue(iop_base,
-										 free_q_head)) != ASC_QLINK_END) {
-			scsiq->q1.q_no = free_q_head;
-			if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
-										free_q_head)) == 1) {
-#if CC_WRITE_IO_COUNT
-				asc_dvc->req_count++;
-#endif
-				AscPutVarFreeQHead(iop_base, next_qp);
-				asc_dvc->cur_total_qng++;
-				asc_dvc->cur_dvc_qng[tid_no]++;
-			}
-			return (sta);
-		}
-	}
-	return (sta);
+                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                    REG ASC_SCSI_Q * scsiq,
+                    uchar n_q_required
+)
+{
+    PortAddr            iop_base;
+    uchar               free_q_head;
+    uchar               next_qp;
+    uchar               tid_no;
+    uchar               target_ix;
+    int                 sta;
+
+    iop_base = asc_dvc->iop_base;
+    target_ix = scsiq->q2.target_ix;
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    sta = 0;
+    free_q_head = (uchar) AscGetVarFreeQHead(iop_base);
+    if (n_q_required > 1) {
+        if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
+                                       free_q_head, (uchar) (n_q_required)))
+            != (uchar) ASC_QLINK_END) {
+            asc_dvc->last_q_shortage = 0;
+            scsiq->sg_head->queue_cnt = n_q_required - 1;
+            scsiq->q1.q_no = free_q_head;
+            if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+                                              free_q_head)) == 1) {
+                AscPutVarFreeQHead(iop_base, next_qp);
+                asc_dvc->cur_total_qng += (uchar) (n_q_required);
+                asc_dvc->cur_dvc_qng[tid_no]++;
+            }
+            return (sta);
+        }
+    } else if (n_q_required == 1) {
+        if ((next_qp = AscAllocFreeQueue(iop_base,
+                                         free_q_head)) != ASC_QLINK_END) {
+            scsiq->q1.q_no = free_q_head;
+            if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
+                                        free_q_head)) == 1) {
+                AscPutVarFreeQHead(iop_base, next_qp);
+                asc_dvc->cur_total_qng++;
+                asc_dvc->cur_dvc_qng[tid_no]++;
+            }
+            return (sta);
+        }
+    }
+    return (sta);
 }
 
-int
+STATIC int
 AscSgListToQueue(
-					int sg_list
+                    int sg_list
 )
 {
-	int                 n_sg_list_qs;
-	n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
-	if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
-		n_sg_list_qs++;
-	return (n_sg_list_qs + 1);
+    int                 n_sg_list_qs;
+
+    n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
+    if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
+        n_sg_list_qs++;
+    return (n_sg_list_qs + 1);
 }
 
 
-uint
+STATIC uint
 AscGetNumOfFreeQueue(
-						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						uchar target_ix,
-						uchar n_qs
-)
-{
-	uint                cur_used_qs;
-	uint                cur_free_qs;
-	ASC_SCSI_BIT_ID_TYPE target_id;
-	uchar               tid_no;
-	target_id = ASC_TIX_TO_TARGET_ID(target_ix);
-	tid_no = ASC_TIX_TO_TID(target_ix);
-	if ((asc_dvc->unit_not_ready & target_id) ||
-		(asc_dvc->queue_full_or_busy & target_id)) {
-		return (0);
-	}
-	if (n_qs == 1) {
-		cur_used_qs = (uint) asc_dvc->cur_total_qng +
-		  (uint) asc_dvc->last_q_shortage +
-		  (uint) ASC_MIN_FREE_Q;
-	} else {
-		cur_used_qs = (uint) asc_dvc->cur_total_qng +
-		  (uint) ASC_MIN_FREE_Q;
-	}
-	if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
-		cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
-		if (asc_dvc->cur_dvc_qng[tid_no] >=
-			asc_dvc->max_dvc_qng[tid_no]) {
-			return (0);
-		}
-		return (cur_free_qs);
-	}
-	if (n_qs > 1) {
-		if ((n_qs > asc_dvc->last_q_shortage) && ( n_qs <= ( asc_dvc->max_total_qng - ASC_MIN_FREE_Q ))) {
-			asc_dvc->last_q_shortage = n_qs;
-		}
-	}
-	return (0);
+                        REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                        uchar target_ix,
+                        uchar n_qs
+)
+{
+    uint                cur_used_qs;
+    uint                cur_free_qs;
+    ASC_SCSI_BIT_ID_TYPE target_id;
+    uchar               tid_no;
+
+    target_id = ASC_TIX_TO_TARGET_ID(target_ix);
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    if ((asc_dvc->unit_not_ready & target_id) ||
+        (asc_dvc->queue_full_or_busy & target_id)) {
+        return (0);
+    }
+    if (n_qs == 1) {
+        cur_used_qs = (uint) asc_dvc->cur_total_qng +
+          (uint) asc_dvc->last_q_shortage +
+          (uint) ASC_MIN_FREE_Q;
+    } else {
+        cur_used_qs = (uint) asc_dvc->cur_total_qng +
+          (uint) ASC_MIN_FREE_Q;
+    }
+    if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
+        cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
+        if (asc_dvc->cur_dvc_qng[tid_no] >=
+            asc_dvc->max_dvc_qng[tid_no]) {
+            return (0);
+        }
+        return (cur_free_qs);
+    }
+    if (n_qs > 1) {
+        if ((n_qs > asc_dvc->last_q_shortage) && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
+            asc_dvc->last_q_shortage = n_qs;
+        }
+    }
+    return (0);
 }
 
-int
+STATIC int
 AscPutReadyQueue(
-					REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					REG ASC_SCSI_Q dosfar * scsiq,
-					uchar q_no
-)
-{
-	ushort              q_addr;
-	uchar               tid_no;
-	uchar               sdtr_data;
-	uchar               syn_period_ix;
-	uchar               syn_offset;
-	PortAddr            iop_base;
-	iop_base = asc_dvc->iop_base;
-	if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
-		((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
-		tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
-		sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-		syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
-		syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
-		AscMsgOutSDTR(asc_dvc,
-					  asc_dvc->sdtr_period_tbl[syn_period_ix],
-					  syn_offset);
-		scsiq->q1.cntl |= QC_MSG_OUT;
-	}
-	q_addr = ASC_QNO_TO_QADDR(q_no);
-	if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
-		scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
-	}
-	scsiq->q1.status = QS_FREE;
-	AscMemWordCopyToLram(iop_base,
-						 (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
-						 (ushort dosfar *) scsiq->cdbptr,
-						 (ushort) ((ushort) scsiq->q2.cdb_len >> 1));
-#if !CC_LITTLE_ENDIAN_HOST
-	AscAdjEndianScsiQ(scsiq);
-#endif
-	DvcPutScsiQ(iop_base,
-				(ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
-				(ushort dosfar *) & scsiq->q1.cntl,
-	  (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)));
-#if CC_WRITE_IO_COUNT
-	AscWriteLramWord(iop_base,
-					 (ushort) (q_addr + (ushort) ASC_SCSIQ_W_REQ_COUNT),
-					 (ushort) asc_dvc->req_count);
-#endif
-#if CC_VERIFY_LRAM_COPY
-	if ((asc_dvc->dvc_cntl & ASC_CNTL_NO_VERIFY_COPY) == 0) {
-		if (AscMemWordCmpToLram(iop_base,
-							 (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
-								(ushort dosfar *) scsiq->cdbptr,
-								(ushort) (scsiq->q2.cdb_len >> 1)) != 0) {
-			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM);
-			return (ERR);
-		}
-		if (AscMemWordCmpToLram(iop_base,
-							 (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
-								(ushort dosfar *) & scsiq->q1.cntl,
-		 (ushort) (((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))
-			!= 0) {
-			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM);
-			return (ERR);
-		}
-	}
-#endif
-#if CC_CLEAR_DMA_REMAIN
-	AscWriteLramDWord(iop_base,
-		   (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_ADDR), 0UL);
-	AscWriteLramDWord(iop_base,
-			(ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT), 0UL);
-#endif
-	AscWriteLramWord(iop_base,
-					 (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-			 (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
-	return (1);
+                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                    REG ASC_SCSI_Q * scsiq,
+                    uchar q_no
+)
+{
+    ushort              q_addr;
+    uchar               tid_no;
+    uchar               sdtr_data;
+    uchar               syn_period_ix;
+    uchar               syn_offset;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
+        ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
+        tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
+        sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+        syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
+        syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
+        AscMsgOutSDTR(asc_dvc,
+                      asc_dvc->sdtr_period_tbl[syn_period_ix],
+                      syn_offset);
+        scsiq->q1.cntl |= QC_MSG_OUT;
+    }
+    q_addr = ASC_QNO_TO_QADDR(q_no);
+    if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
+        scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
+    }
+    scsiq->q1.status = QS_FREE;
+    AscMemWordCopyToLram(iop_base,
+                         (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
+                         (ushort *) scsiq->cdbptr,
+                         (ushort) ((ushort) scsiq->q2.cdb_len >> 1));
+    DvcPutScsiQ(iop_base,
+                (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
+                (ushort *) & scsiq->q1.cntl,
+      (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)));
+    AscWriteLramWord(iop_base,
+                     (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+             (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
+    return (1);
 }
 
-int
+STATIC int
 AscPutReadySgListQueue(
-						  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						  REG ASC_SCSI_Q dosfar * scsiq,
-						  uchar q_no
-)
-{
-	int                 sta;
-	int                 i;
-	ASC_SG_HEAD dosfar *sg_head;
-	ASC_SG_LIST_Q       scsi_sg_q;
-	ulong               saved_data_addr;
-	ulong               saved_data_cnt;
-	PortAddr            iop_base;
-	ushort              sg_list_dwords;
-	ushort              sg_index;
-	ushort              sg_entry_cnt;
-	ushort              q_addr;
-	uchar               next_qp;
-	iop_base = asc_dvc->iop_base;
-	sg_head = scsiq->sg_head;
-	saved_data_addr = scsiq->q1.data_addr;
-	saved_data_cnt = scsiq->q1.data_cnt;
-	scsiq->q1.data_addr = sg_head->sg_list[0].addr;
-	scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
-	sg_entry_cnt = sg_head->entry_cnt - 1;
-	if (sg_entry_cnt != 0) {
-		scsiq->q1.cntl |= QC_SG_HEAD;
-		q_addr = ASC_QNO_TO_QADDR(q_no);
-		sg_index = 1;
-		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
-		scsi_sg_q.sg_head_qp = q_no;
-		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
-		for (i = 0; i < sg_head->queue_cnt; i++) {
-			scsi_sg_q.seq_no = i + 1;
-			if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
-				sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
-				sg_entry_cnt -= ASC_SG_LIST_PER_Q;
-				if (i == 0) {
-					scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q;
-					scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q;
-				} else {
-					scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
-					scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
-				}
-			} else {
-				scsi_sg_q.cntl |= QCSG_SG_XFER_END;
-				sg_list_dwords = sg_entry_cnt << 1;
-				if (i == 0) {
-					scsi_sg_q.sg_list_cnt = sg_entry_cnt;
-					scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt;
-				} else {
-					scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
-					scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
-				}
-				sg_entry_cnt = 0;
-			}
-			next_qp = AscReadLramByte(iop_base,
-									  (ushort) (q_addr + ASC_SCSIQ_B_FWD));
-			scsi_sg_q.q_no = next_qp;
-			q_addr = ASC_QNO_TO_QADDR(next_qp);
-			AscMemWordCopyToLram(iop_base,
-								 (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG),
-								 (ushort dosfar *) & scsi_sg_q,
-								 (ushort) (sizeof (ASC_SG_LIST_Q) >> 1));
-			AscMemDWordCopyToLram(iop_base,
-								  (ushort) (q_addr + ASC_SGQ_LIST_BEG),
-							  (ulong dosfar *) & sg_head->sg_list[sg_index],
-								  (ushort) sg_list_dwords);
-			sg_index += ASC_SG_LIST_PER_Q;
-		}
-	} else {
-		scsiq->q1.cntl &= ~QC_SG_HEAD;
-	}
-	sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
-	scsiq->q1.data_addr = saved_data_addr;
-	scsiq->q1.data_cnt = saved_data_cnt;
-	return (sta);
+                          REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                          REG ASC_SCSI_Q * scsiq,
+                          uchar q_no
+)
+{
+    int                 sta;
+    int                 i;
+    ASC_SG_HEAD *sg_head;
+    ASC_SG_LIST_Q       scsi_sg_q;
+    ulong               saved_data_addr;
+    ulong               saved_data_cnt;
+    PortAddr            iop_base;
+    ushort              sg_list_dwords;
+    ushort              sg_index;
+    ushort              sg_entry_cnt;
+    ushort              q_addr;
+    uchar               next_qp;
+
+    iop_base = asc_dvc->iop_base;
+    sg_head = scsiq->sg_head;
+    saved_data_addr = scsiq->q1.data_addr;
+    saved_data_cnt = scsiq->q1.data_cnt;
+    scsiq->q1.data_addr = sg_head->sg_list[0].addr;
+    scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
+    sg_entry_cnt = sg_head->entry_cnt - 1;
+    if (sg_entry_cnt != 0) {
+        scsiq->q1.cntl |= QC_SG_HEAD;
+        q_addr = ASC_QNO_TO_QADDR(q_no);
+        sg_index = 1;
+        scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
+        scsi_sg_q.sg_head_qp = q_no;
+        scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+        for (i = 0; i < sg_head->queue_cnt; i++) {
+            scsi_sg_q.seq_no = i + 1;
+            if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+                sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+                sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                if (i == 0) {
+                    scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q;
+                    scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q;
+                } else {
+                    scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                    scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                }
+            } else {
+                scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                sg_list_dwords = sg_entry_cnt << 1;
+                if (i == 0) {
+                    scsi_sg_q.sg_list_cnt = sg_entry_cnt;
+                    scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt;
+                } else {
+                    scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+                    scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+                }
+                sg_entry_cnt = 0;
+            }
+            next_qp = AscReadLramByte(iop_base,
+                                      (ushort) (q_addr + ASC_SCSIQ_B_FWD));
+            scsi_sg_q.q_no = next_qp;
+            q_addr = ASC_QNO_TO_QADDR(next_qp);
+            AscMemWordCopyToLram(iop_base,
+                                 (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG),
+                                 (ushort *) & scsi_sg_q,
+                                 (ushort) (sizeof (ASC_SG_LIST_Q) >> 1));
+            AscMemDWordCopyToLram(iop_base,
+                                  (ushort) (q_addr + ASC_SGQ_LIST_BEG),
+                              (ulong *) & sg_head->sg_list[sg_index],
+                                  (ushort) sg_list_dwords);
+            sg_index += ASC_SG_LIST_PER_Q;
+        }
+    } else {
+        scsiq->q1.cntl &= ~QC_SG_HEAD;
+    }
+    sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
+    scsiq->q1.data_addr = saved_data_addr;
+    scsiq->q1.data_cnt = saved_data_cnt;
+    return (sta);
 }
 
-int
+STATIC int
 AscAbortSRB(
-			   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-			   ulong srb_ptr
+               REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+               ulong srb_ptr
 )
 {
-	int                 sta;
-	ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
-	PortAddr            iop_base;
-	iop_base = asc_dvc->iop_base;
-	sta = ERR;
-	saved_unit_not_ready = asc_dvc->unit_not_ready;
-	asc_dvc->unit_not_ready = 0xFF;
-	AscWaitISRDone(asc_dvc);
-	if (AscStopQueueExe(iop_base) == 1) {
-		if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) {
-			sta = 1;
-			AscCleanUpBusyQueue(iop_base);
-			AscStartQueueExe(iop_base);
-		} else {
-			sta = 0;
-			AscStartQueueExe(iop_base);
-		}
-	}
-	asc_dvc->unit_not_ready = saved_unit_not_ready;
-	return (sta);
+    int                 sta;
+    ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    sta = ERR;
+    saved_unit_not_ready = asc_dvc->unit_not_ready;
+    asc_dvc->unit_not_ready = 0xFF;
+    AscWaitISRDone(asc_dvc);
+    if (AscStopQueueExe(iop_base) == 1) {
+        if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) {
+            sta = 1;
+            AscCleanUpBusyQueue(iop_base);
+            AscStartQueueExe(iop_base);
+        } else {
+            sta = 0;
+            AscStartQueueExe(iop_base);
+        }
+    }
+    asc_dvc->unit_not_ready = saved_unit_not_ready;
+    return (sta);
 }
 
-int
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int
 AscResetDevice(
-				  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				  uchar target_ix
+                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                  uchar target_ix
 )
 {
-	PortAddr            iop_base;
-	int                 sta;
-	uchar               tid_no;
-	ASC_SCSI_BIT_ID_TYPE target_id;
-	int                 i;
-	ASC_SCSI_REQ_Q      scsiq_buf;
-	ASC_SCSI_REQ_Q dosfar *scsiq;
-	uchar dosfar       *buf;
-	ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
-	iop_base = asc_dvc->iop_base;
-	tid_no = ASC_TIX_TO_TID(target_ix);
-	target_id = ASC_TID_TO_TARGET_ID(tid_no);
-	saved_unit_not_ready = asc_dvc->unit_not_ready;
-	asc_dvc->unit_not_ready = target_id;
-	sta = ERR;
-	AscWaitTixISRDone(asc_dvc, target_ix);
-	if (AscStopQueueExe(iop_base) == 1) {
-		if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) {
-			AscCleanUpBusyQueue(iop_base);
-			AscStartQueueExe(iop_base);
-			AscWaitTixISRDone(asc_dvc, target_ix);
-			sta = TRUE;
-			scsiq = (ASC_SCSI_REQ_Q dosfar *) & scsiq_buf;
-			buf = (uchar dosfar *) & scsiq_buf;
-			for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) {
-				*buf++ = 0x00;
-			}
-			scsiq->r1.status = (uchar) QS_READY;
-			scsiq->r2.cdb_len = 6;
-			scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE;
-			scsiq->r1.target_id = target_id;
-			scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0);
-			scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
-			scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT;
-			AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG,
-							 M1_BUS_DVC_RESET);
-			asc_dvc->unit_not_ready &= ~target_id;
-			asc_dvc->sdtr_done |= target_id;
-			if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q dosfar *) scsiq)
-				== 1) {
-				asc_dvc->unit_not_ready = target_id;
-				DvcSleepMilliSecond(1000);
-				_AscWaitQDone(iop_base, (ASC_SCSI_Q dosfar *) scsiq);
-				if (AscStopQueueExe(iop_base) == 1) {
-					AscCleanUpDiscQueue(iop_base);
-					AscStartQueueExe(iop_base);
-					if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-						AscSetRunChipSynRegAtID(iop_base, tid_no,
-											 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
-					}
-					AscWaitTixISRDone(asc_dvc, target_ix);
-				}
-			} else {
-				sta = 0;
-			}
-			asc_dvc->sdtr_done &= ~target_id;
-		} else {
-			sta = ERR;
-			AscStartQueueExe(iop_base);
-		}
-	}
-	asc_dvc->unit_not_ready = saved_unit_not_ready;
-	return (sta);
+    PortAddr            iop_base;
+    int                 sta;
+    uchar               tid_no;
+
+    ASC_SCSI_BIT_ID_TYPE target_id;
+    int                 i;
+    ASC_SCSI_REQ_Q      scsiq_buf;
+    ASC_SCSI_REQ_Q *scsiq;
+    uchar       *buf;
+    ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
+    iop_base = asc_dvc->iop_base;
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    target_id = ASC_TID_TO_TARGET_ID(tid_no);
+    saved_unit_not_ready = asc_dvc->unit_not_ready;
+    asc_dvc->unit_not_ready = target_id;
+    sta = ERR;
+    AscWaitTixISRDone(asc_dvc, target_ix);
+    if (AscStopQueueExe(iop_base) == 1) {
+        if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) {
+            AscCleanUpBusyQueue(iop_base);
+            AscStartQueueExe(iop_base);
+            AscWaitTixISRDone(asc_dvc, target_ix);
+            sta = TRUE;
+            scsiq = (ASC_SCSI_REQ_Q *) & scsiq_buf;
+            buf = (uchar *) & scsiq_buf;
+            for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) {
+                *buf++ = 0x00;
+            }
+            scsiq->r1.status = (uchar) QS_READY;
+            scsiq->r2.cdb_len = 6;
+            scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE;
+            scsiq->r1.target_id = target_id;
+            scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0);
+            scsiq->cdbptr = (uchar *) scsiq->cdb;
+            scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT;
+            AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG,
+                             M1_BUS_DVC_RESET);
+            asc_dvc->unit_not_ready &= ~target_id;
+            asc_dvc->sdtr_done |= target_id;
+            if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q *) scsiq)
+                == 1) {
+                asc_dvc->unit_not_ready = target_id;
+                DvcSleepMilliSecond(1000);
+                _AscWaitQDone(iop_base, (ASC_SCSI_Q *) scsiq);
+                if (AscStopQueueExe(iop_base) == 1) {
+                    AscCleanUpDiscQueue(iop_base);
+                    AscStartQueueExe(iop_base);
+                    if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+                        AscSetRunChipSynRegAtID(iop_base, tid_no,
+                                             ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+                    }
+                    AscWaitTixISRDone(asc_dvc, target_ix);
+                }
+            } else {
+                sta = 0;
+            }
+            asc_dvc->sdtr_done &= ~target_id;
+        } else {
+            sta = ERR;
+            AscStartQueueExe(iop_base);
+        }
+    }
+    asc_dvc->unit_not_ready = saved_unit_not_ready;
+    return (sta);
 }
+#endif /* version >= v1.3.89 */
 
-int
+STATIC int
 AscResetSB(
-			  REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+              REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	int                 sta;
-	int                 i;
-	PortAddr            iop_base;
-	iop_base = asc_dvc->iop_base;
-	asc_dvc->unit_not_ready = 0xFF;
-	sta = TRUE;
-	AscWaitISRDone(asc_dvc);
-	AscStopQueueExe(iop_base);
-	asc_dvc->sdtr_done = 0;
-	AscResetChipAndScsiBus(iop_base);
-	DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
-	AscReInitLram(asc_dvc);
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		asc_dvc->cur_dvc_qng[i] = 0;
-		if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) {
-			AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB);
-		}
-	}
-	asc_dvc->err_code = 0;
-	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-		sta = ERR;
-	}
-	if (AscStartChip(iop_base) == 0) {
-		sta = ERR;
-	}
-	AscStartQueueExe(iop_base);
-	asc_dvc->unit_not_ready = 0;
-	asc_dvc->queue_full_or_busy = 0;
-	return (sta);
+    int                 sta;
+    int                 i;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    asc_dvc->unit_not_ready = 0xFF;
+    sta = TRUE;
+    AscWaitISRDone(asc_dvc);
+    AscStopQueueExe(iop_base);
+    asc_dvc->sdtr_done = 0;
+    AscResetChipAndScsiBus(asc_dvc);
+    DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+    AscReInitLram(asc_dvc);
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        asc_dvc->cur_dvc_qng[i] = 0;
+        if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) {
+            AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+        }
+    }
+    asc_dvc->err_code = 0;
+    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+        sta = ERR;
+    }
+    if (AscStartChip(iop_base) == 0) {
+        sta = ERR;
+    }
+    AscStartQueueExe(iop_base);
+    asc_dvc->unit_not_ready = 0;
+    asc_dvc->queue_full_or_busy = 0;
+    return (sta);
 }
 
-int
+STATIC int
 AscSetRunChipSynRegAtID(
-						   PortAddr iop_base,
-						   uchar tid_no,
-						   uchar sdtr_data
+                           PortAddr iop_base,
+                           uchar tid_no,
+                           uchar sdtr_data
 )
 {
-	int                 sta = FALSE;
-	if (AscHostReqRiscHalt(iop_base)) {
-		sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
-		AscStartChip(iop_base);
-		return (sta);
-	}
-	return (sta);
+    int                 sta = FALSE;
+
+    if (AscHostReqRiscHalt(iop_base)) {
+        sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+        AscStartChip(iop_base);
+        return (sta);
+    }
+    return (sta);
 }
 
-int
+STATIC int
 AscSetChipSynRegAtID(
-						PortAddr iop_base,
-						uchar id,
-						uchar sdtr_data
-)
-{
-	ASC_SCSI_BIT_ID_TYPE org_id;
-	int                 i;
-	int                 sta;
-	sta = TRUE;
-	AscSetBank(iop_base, 1);
-	org_id = AscReadChipDvcID(iop_base);
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		if (org_id == (0x01 << i))
-			break;
-	}
-	org_id = i;
-	AscWriteChipDvcID(iop_base, id);
-	if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
-		AscSetBank(iop_base, 0);
-		AscSetChipSyn(iop_base, sdtr_data);
-		if (AscGetChipSyn(iop_base) != sdtr_data) {
-			sta = FALSE;
-		}
-	} else {
-		sta = FALSE;
-	}
-	AscSetBank(iop_base, 1);
-	AscWriteChipDvcID(iop_base, org_id);
-	AscSetBank(iop_base, 0);
-	return (sta);
+                        PortAddr iop_base,
+                        uchar id,
+                        uchar sdtr_data
+)
+{
+    ASC_SCSI_BIT_ID_TYPE org_id;
+    int                 i;
+    int                 sta = TRUE;
+
+    AscSetBank(iop_base, 1);
+    org_id = AscReadChipDvcID(iop_base);
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if (org_id == (0x01 << i))
+            break;
+    }
+    org_id = i;
+    AscWriteChipDvcID(iop_base, id);
+    if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
+        AscSetBank(iop_base, 0);
+        AscSetChipSyn(iop_base, sdtr_data);
+        if (AscGetChipSyn(iop_base) != sdtr_data) {
+            sta = FALSE;
+        }
+    } else {
+        sta = FALSE;
+    }
+    AscSetBank(iop_base, 1);
+    AscWriteChipDvcID(iop_base, org_id);
+    AscSetBank(iop_base, 0);
+    return (sta);
 }
 
-int
+STATIC int
 AscReInitLram(
-				 REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                 REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	AscInitLram(asc_dvc);
-	AscInitQLinkVar(asc_dvc);
-	return (0);
+    AscInitLram(asc_dvc);
+    AscInitQLinkVar(asc_dvc);
+    return (0);
 }
 
-ushort
+STATIC ushort
 AscInitLram(
-			   REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+               REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	uchar               i;
-	ushort              s_addr;
-	PortAddr            iop_base;
-	ushort              warn_code;
-	iop_base = asc_dvc->iop_base;
-	warn_code = 0;
-	AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
-			   (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1)
-	  );
-	i = ASC_MIN_ACTIVE_QNO;
-	s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
-	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
-					 (uchar) (i + 1));
-	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
-					 (uchar) (asc_dvc->max_total_qng));
-	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
-					 (uchar) i);
-	i++;
-	s_addr += ASC_QBLK_SIZE;
-	for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
-		AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
-						 (uchar) (i + 1));
-		AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
-						 (uchar) (i - 1));
-		AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
-						 (uchar) i);
-	}
-	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
-					 (uchar) ASC_QLINK_END);
-	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
-					 (uchar) (asc_dvc->max_total_qng - 1));
-	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
-					 (uchar) asc_dvc->max_total_qng);
-	i++;
-	s_addr += ASC_QBLK_SIZE;
-	for (; i <= (uchar) (asc_dvc->max_total_qng + 3);
-		 i++, s_addr += ASC_QBLK_SIZE) {
-		AscWriteLramByte(iop_base,
-						 (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i);
-		AscWriteLramByte(iop_base,
-						 (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i);
-		AscWriteLramByte(iop_base,
-						 (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i);
-	}
-	return (warn_code);
+    uchar               i;
+    ushort              s_addr;
+    PortAddr            iop_base;
+    ushort              warn_code;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+               (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1)
+);
+    i = ASC_MIN_ACTIVE_QNO;
+    s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+                     (uchar) (i + 1));
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+                     (uchar) (asc_dvc->max_total_qng));
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+                     (uchar) i);
+    i++;
+    s_addr += ASC_QBLK_SIZE;
+    for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+                         (uchar) (i + 1));
+        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+                         (uchar) (i - 1));
+        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+                         (uchar) i);
+    }
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+                     (uchar) ASC_QLINK_END);
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+                     (uchar) (asc_dvc->max_total_qng - 1));
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+                     (uchar) asc_dvc->max_total_qng);
+    i++;
+    s_addr += ASC_QBLK_SIZE;
+    for (; i <= (uchar) (asc_dvc->max_total_qng + 3);
+         i++, s_addr += ASC_QBLK_SIZE) {
+        AscWriteLramByte(iop_base,
+                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i);
+        AscWriteLramByte(iop_base,
+                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i);
+        AscWriteLramByte(iop_base,
+                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i);
+    }
+    return (warn_code);
 }
 
-ushort
+STATIC ushort
 AscInitQLinkVar(
-				   REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                   REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	PortAddr            iop_base;
-	int                 i;
-	ushort              lram_addr;
-	iop_base = asc_dvc->iop_base;
-	AscPutRiscVarFreeQHead(iop_base, 1);
-	AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
-	AscPutVarFreeQHead(iop_base, 1);
-	AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
-	AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
-					 (uchar) ((int) asc_dvc->max_total_qng + 1));
-	AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
-					 (uchar) ((int) asc_dvc->max_total_qng + 2));
-	AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B,
-					 asc_dvc->max_total_qng);
-	AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
-	AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
-	AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
-	AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
-	AscPutQDoneInProgress(iop_base, 0);
-	lram_addr = ASC_QADR_BEG;
-	for (i = 0; i < 32; i++, lram_addr += 2) {
-		AscWriteLramWord(iop_base, lram_addr, 0);
-	}
-	return (0);
+    PortAddr            iop_base;
+    int                 i;
+    ushort              lram_addr;
+
+    iop_base = asc_dvc->iop_base;
+    AscPutRiscVarFreeQHead(iop_base, 1);
+    AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+    AscPutVarFreeQHead(iop_base, 1);
+    AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+    AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+                     (uchar) ((int) asc_dvc->max_total_qng + 1));
+    AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+                     (uchar) ((int) asc_dvc->max_total_qng + 2));
+    AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B,
+                     asc_dvc->max_total_qng);
+    AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+    AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+    AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+    AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+    AscPutQDoneInProgress(iop_base, 0);
+    lram_addr = ASC_QADR_BEG;
+    for (i = 0; i < 32; i++, lram_addr += 2) {
+        AscWriteLramWord(iop_base, lram_addr, 0);
+    }
+    return (0);
 }
 
-int
+STATIC int
 AscSetLibErrorCode(
-					  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					  ushort err_code
+                      REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                      ushort err_code
 )
 {
-	if (asc_dvc->err_code == 0) {
-		asc_dvc->err_code = err_code;
-		AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
-						 err_code);
-	}
-	return (err_code);
+    if (asc_dvc->err_code == 0) {
+        asc_dvc->err_code = err_code;
+        AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+                         err_code);
+    }
+    return (err_code);
 }
 
 
-int
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int
 _AscWaitQDone(
-				 PortAddr iop_base,
-				 REG ASC_SCSI_Q dosfar * scsiq
+                 PortAddr iop_base,
+                 REG ASC_SCSI_Q * scsiq
 )
 {
-	ushort              q_addr;
-	uchar               q_status;
-	int                 count = 0;
-	while (scsiq->q1.q_no == 0) ;
-	q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
-	do {
-		q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS);
-		DvcSleepMilliSecond(100L);
-		if (count++ > 30) {
-			return (0);
-		}
-	} while ((q_status & QS_READY) != 0);
-	return (1);
+    ushort              q_addr;
+    uchar               q_status;
+    int                 count = 0;
+
+    while (scsiq->q1.q_no == 0) ;
+    q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
+    do {
+        q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS);
+        DvcSleepMilliSecond(100L);
+        if (count++ > 30) {
+            return (0);
+        }
+    } while ((q_status & QS_READY) != 0);
+    return (1);
 }
+#endif /* version >= v1.3.89 */
 
-uchar
+STATIC uchar 
 AscMsgOutSDTR(
-				 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				 uchar sdtr_period,
-				 uchar sdtr_offset
-)
-{
-	SDTR_XMSG           sdtr_buf;
-	uchar               sdtr_period_index;
-	PortAddr            iop_base;
-	iop_base = asc_dvc->iop_base;
-	sdtr_buf.msg_type = MS_EXTEND;
-	sdtr_buf.msg_len = MS_SDTR_LEN;
-	sdtr_buf.msg_req = MS_SDTR_CODE;
-	sdtr_buf.xfer_period = sdtr_period;
-	sdtr_offset &= ASC_SYN_MAX_OFFSET;
-	sdtr_buf.req_ack_offset = sdtr_offset;
-	if ((sdtr_period_index =
-		 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
-		asc_dvc->max_sdtr_index) {
-		AscMemWordCopyToLram(iop_base,
-							 ASCV_MSGOUT_BEG,
-							 (ushort dosfar *) & sdtr_buf, SYN_XMSG_WLEN);
-		return ((sdtr_period_index << 4) | sdtr_offset);
-	} else {
-		sdtr_buf.req_ack_offset = 0;
-		AscMemWordCopyToLram(iop_base,
-							 ASCV_MSGOUT_BEG,
-							 (ushort dosfar *) & sdtr_buf, SYN_XMSG_WLEN);
-		return (0);
-	}
+                 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                 uchar sdtr_period,
+                 uchar sdtr_offset
+)
+{
+    EXT_MSG             sdtr_buf;
+    uchar               sdtr_period_index;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    sdtr_buf.msg_type = MS_EXTEND;
+    sdtr_buf.msg_len = MS_SDTR_LEN;
+    sdtr_buf.msg_req = MS_SDTR_CODE;
+    sdtr_buf.xfer_period = sdtr_period;
+    sdtr_offset &= ASC_SYN_MAX_OFFSET;
+    sdtr_buf.req_ack_offset = sdtr_offset;
+    if ((sdtr_period_index =
+         AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
+        asc_dvc->max_sdtr_index) {
+        AscMemWordCopyToLram(iop_base,
+                             ASCV_MSGOUT_BEG,
+                             (ushort *) & sdtr_buf,
+                             (ushort) (sizeof (EXT_MSG) >> 1));
+        return ((sdtr_period_index << 4) | sdtr_offset);
+    } else {
+
+        sdtr_buf.req_ack_offset = 0;
+        AscMemWordCopyToLram(iop_base,
+                             ASCV_MSGOUT_BEG,
+                             (ushort *) & sdtr_buf,
+                             (ushort) (sizeof (EXT_MSG) >> 1));
+        return (0);
+    }
 }
 
-uchar
+STATIC uchar
 AscCalSDTRData(
-				  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				  uchar sdtr_period,
-				  uchar syn_offset
+                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                  uchar sdtr_period,
+                  uchar syn_offset
 )
 {
-	uchar               byte;
-	uchar               sdtr_period_ix;
-	sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
-	if (
-		   (sdtr_period_ix > asc_dvc->max_sdtr_index)
-	  ) {
-		return (0xFF);
-	}
-	byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
-	return (byte);
+    uchar               byte;
+    uchar               sdtr_period_ix;
+
+    sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+    if (
+           (sdtr_period_ix > asc_dvc->max_sdtr_index)
+) {
+        return (0xFF);
+    }
+    byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+    return (byte);
 }
 
-void
+STATIC void
 AscSetChipSDTR(
-				  PortAddr iop_base,
-				  uchar sdtr_data,
-				  uchar tid_no
+                  PortAddr iop_base,
+                  uchar sdtr_data,
+                  uchar tid_no
 )
 {
-	AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
-	AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
-	return;
+    AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+    AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
+    return;
 }
 
-uchar
+STATIC uchar
 AscGetSynPeriodIndex(
-						ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						ruchar syn_time
+                        ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                        ruchar syn_time
 )
 {
-	ruchar             *period_table;
-	int                 max_index;
-	int                 min_index;
-	int                 i;
-	period_table = asc_dvc->sdtr_period_tbl;
-	max_index = (int) asc_dvc->max_sdtr_index;
-	min_index = ( int )asc_dvc->host_init_sdtr_index ;
-	if (
-		   (syn_time <= period_table[max_index])
-	  ) {
-		for (i = min_index; i < (max_index - 1); i++) {
-			if (syn_time <= period_table[i]) {
-				return ((uchar) i);
-			}
-		}
-		return ((uchar) max_index);
-	} else {
-		return ((uchar) (max_index + 1));
-	}
+    ruchar             *period_table;
+    int                 max_index;
+    int                 min_index;
+    int                 i;
+
+    period_table = asc_dvc->sdtr_period_tbl;
+    max_index = (int) asc_dvc->max_sdtr_index;
+    min_index = (int)asc_dvc->host_init_sdtr_index ;
+    if ((syn_time <= period_table[max_index])) {
+        for (i = min_index; i < (max_index - 1); i++) {
+            if (syn_time <= period_table[i]) {
+                return ((uchar) i);
+            }
+        }
+        return ((uchar) max_index);
+    } else {
+        return ((uchar) (max_index + 1));
+    }
 }
 
-uchar
+STATIC uchar
 AscAllocFreeQueue(
-					 PortAddr iop_base,
-					 uchar free_q_head
+                     PortAddr iop_base,
+                     uchar free_q_head
 )
 {
-	ushort              q_addr;
-	uchar               next_qp;
-	uchar               q_status;
-	q_addr = ASC_QNO_TO_QADDR(free_q_head);
-	q_status = (uchar) AscReadLramByte(iop_base,
-									(ushort) (q_addr + ASC_SCSIQ_B_STATUS));
-	next_qp = AscReadLramByte(iop_base,
-							  (ushort) (q_addr + ASC_SCSIQ_B_FWD));
-	if (
-		   ((q_status & QS_READY) == 0)
-		   && (next_qp != ASC_QLINK_END)
-	  ) {
-		return (next_qp);
-	}
-	return (ASC_QLINK_END);
+    ushort              q_addr;
+    uchar               next_qp;
+    uchar               q_status;
+
+    q_addr = ASC_QNO_TO_QADDR(free_q_head);
+    q_status = (uchar) AscReadLramByte(iop_base,
+                                    (ushort) (q_addr + ASC_SCSIQ_B_STATUS));
+    next_qp = AscReadLramByte(iop_base,
+                              (ushort) (q_addr + ASC_SCSIQ_B_FWD));
+    if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
+        return (next_qp);
+    }
+    return (ASC_QLINK_END);
 }
 
-uchar
+STATIC uchar
 AscAllocMultipleFreeQueue(
-							 PortAddr iop_base,
-							 uchar free_q_head,
-							 uchar n_free_q
+                             PortAddr iop_base,
+                             uchar free_q_head,
+                             uchar n_free_q
 )
 {
-	uchar               i;
-	for (i = 0; i < n_free_q; i++) {
-		if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
-			== ASC_QLINK_END) {
-			return (ASC_QLINK_END);
-		}
-	}
-	return (free_q_head);
+    uchar               i;
+
+    for (i = 0; i < n_free_q; i++) {
+        if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
+            == ASC_QLINK_END) {
+            return (ASC_QLINK_END);
+        }
+    }
+    return (free_q_head);
 }
 
-int
+STATIC int
 AscRiscHaltedAbortSRB(
-						 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						 ulong srb_ptr
+                         REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                         ulong srb_ptr
 )
 {
-	PortAddr            iop_base;
-	ushort              q_addr;
-	uchar               q_no;
-	ASC_QDONE_INFO      scsiq_buf;
-	ASC_QDONE_INFO dosfar *scsiq;
-	ASC_ISR_CALLBACK    asc_isr_callback;
-	int                 last_int_level;
-	iop_base = asc_dvc->iop_base;
-	asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
-	last_int_level = DvcEnterCritical();
-	scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf;
-#if CC_LINK_BUSY_Q
-	_AscAbortSrbBusyQueue(asc_dvc, scsiq, srb_ptr);
-#endif
-	for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
-		 q_no++) {
-		q_addr = ASC_QNO_TO_QADDR(q_no);
-		scsiq->d2.srb_ptr = AscReadLramDWord(iop_base,
-						   (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR));
-		if (scsiq->d2.srb_ptr == srb_ptr) {
-			_AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
-			if (
-				   ((scsiq->q_status & QS_READY) != 0)
-				   && ((scsiq->q_status & QS_ABORTED) == 0)
-				   && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
-			  ) {
-				scsiq->q_status |= QS_ABORTED;
-				scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
-				AscWriteLramDWord(iop_base,
-							(ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
-								  0L);
-				AscWriteLramByte(iop_base,
-							(ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-								 scsiq->q_status);
-				(*asc_isr_callback) (asc_dvc, scsiq);
-				return (1);
-			}
-		}
-	}
-	DvcLeaveCritical(last_int_level);
-	return (0);
+    PortAddr            iop_base;
+    ushort              q_addr;
+    uchar               q_no;
+    ASC_QDONE_INFO      scsiq_buf;
+    ASC_QDONE_INFO *scsiq;
+    ASC_ISR_CALLBACK    asc_isr_callback;
+    int                 last_int_level;
+
+    iop_base = asc_dvc->iop_base;
+    asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+    last_int_level = DvcEnterCritical();
+    scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
+    for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
+         q_no++) {
+        q_addr = ASC_QNO_TO_QADDR(q_no);
+        scsiq->d2.srb_ptr = AscReadLramDWord(iop_base,
+                           (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR));
+        if (scsiq->d2.srb_ptr == srb_ptr) {
+            _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
+            if (((scsiq->q_status & QS_READY) != 0)
+                 && ((scsiq->q_status & QS_ABORTED) == 0)
+                 && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) {
+                scsiq->q_status |= QS_ABORTED;
+                scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
+                AscWriteLramDWord(iop_base,
+                            (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
+                                  0L);
+                AscWriteLramByte(iop_base,
+                            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+                                 scsiq->q_status);
+                (*asc_isr_callback) (asc_dvc, scsiq);
+                return (1);
+            }
+        }
+    }
+    DvcLeaveCritical(last_int_level);
+    return (0);
 }
 
-int
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int
 AscRiscHaltedAbortTIX(
-						 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						 uchar target_ix
+                         REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                         uchar target_ix
 )
 {
-	PortAddr            iop_base;
-	ushort              q_addr;
-	uchar               q_no;
-	ASC_QDONE_INFO      scsiq_buf;
-	ASC_QDONE_INFO dosfar *scsiq;
-	ASC_ISR_CALLBACK    asc_isr_callback;
-	int                 last_int_level;
-#if CC_LINK_BUSY_Q
-	uchar               tid_no;
-#endif
-	iop_base = asc_dvc->iop_base;
-	asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
-	last_int_level = DvcEnterCritical();
-	scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf;
-#if CC_LINK_BUSY_Q
-	tid_no = ASC_TIX_TO_TID(target_ix);
-	_AscAbortTidBusyQueue(asc_dvc, scsiq, tid_no);
-#endif
-	for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
-		 q_no++) {
-		q_addr = ASC_QNO_TO_QADDR(q_no);
-		_AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
-		if (
-			   ((scsiq->q_status & QS_READY) != 0)
-			   && ((scsiq->q_status & QS_ABORTED) == 0)
-			   && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
-		  ) {
-			if (scsiq->d2.target_ix == target_ix) {
-				scsiq->q_status |= QS_ABORTED;
-				scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
-				AscWriteLramDWord(iop_base,
-							(ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
-								  0L);
-				AscWriteLramByte(iop_base,
-							(ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-								 scsiq->q_status);
-				(*asc_isr_callback) (asc_dvc, scsiq);
-			}
-		}
-	}
-	DvcLeaveCritical(last_int_level);
-	return (1);
+    PortAddr            iop_base;
+    ushort              q_addr;
+    uchar               q_no;
+    ASC_QDONE_INFO      scsiq_buf;
+    ASC_QDONE_INFO *scsiq;
+    ASC_ISR_CALLBACK    asc_isr_callback;
+    int                 last_int_level;
+
+    iop_base = asc_dvc->iop_base;
+    asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+    last_int_level = DvcEnterCritical();
+    scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
+    for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
+         q_no++) {
+        q_addr = ASC_QNO_TO_QADDR(q_no);
+        _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
+        if (((scsiq->q_status & QS_READY) != 0) &&
+            ((scsiq->q_status & QS_ABORTED) == 0) &&
+            ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) {
+            if (scsiq->d2.target_ix == target_ix) {
+                scsiq->q_status |= QS_ABORTED;
+                scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
+                AscWriteLramDWord(iop_base,
+                            (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
+                                  0L);
+                AscWriteLramByte(iop_base,
+                            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+                                 scsiq->q_status);
+                (*asc_isr_callback) (asc_dvc, scsiq);
+            }
+        }
+    }
+    DvcLeaveCritical(last_int_level);
+    return (1);
 }
+#endif /* version >= v1.3.89 */
 
-#if CC_LINK_BUSY_Q
-
-#endif
-
-int
+STATIC int
 AscHostReqRiscHalt(
-					  PortAddr iop_base
+                      PortAddr iop_base
 )
 {
-	int                 count = 0;
-	int                 sta = 0;
-	uchar               saved_stop_code;
-	if (AscIsChipHalted(iop_base))
-		return (1);
-	saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
-	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-					 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP
-	  );
-	do {
-		if (AscIsChipHalted(iop_base)) {
-			sta = 1;
-			break;
-		}
-		DvcSleepMilliSecond(100);
-	} while (count++ < 20);
-	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
-	return (sta);
+    int                 count = 0;
+    int                 sta = 0;
+    uchar               saved_stop_code;
+
+    if (AscIsChipHalted(iop_base))
+        return (1);
+    saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                     ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP
+);
+    do {
+        if (AscIsChipHalted(iop_base)) {
+            sta = 1;
+            break;
+        }
+        DvcSleepMilliSecond(100);
+    } while (count++ < 20);
+    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+    return (sta);
 }
 
-int
+STATIC int
 AscStopQueueExe(
-				   PortAddr iop_base
+                   PortAddr iop_base
 )
 {
-	int                 count;
-	count = 0;
-	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
-		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-						 ASC_STOP_REQ_RISC_STOP);
-		do {
-			if (
-				   AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
-				   ASC_STOP_ACK_RISC_STOP) {
-				return (1);
-			}
-			DvcSleepMilliSecond(100);
-		} while (count++ < 20);
-	}
-	return (0);
+    int                 count = 0;
+
+    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                         ASC_STOP_REQ_RISC_STOP);
+        do {
+            if (
+                   AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+                   ASC_STOP_ACK_RISC_STOP) {
+                return (1);
+            }
+            DvcSleepMilliSecond(100);
+        } while (count++ < 20);
+    }
+    return (0);
 }
 
-int
+STATIC int
 AscStartQueueExe(
-					PortAddr iop_base
+                    PortAddr iop_base
 )
 {
-	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
-		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
-	}
-	return (1);
+    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
+        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+    }
+    return (1);
 }
 
-int
+STATIC int
 AscCleanUpBusyQueue(
-					   PortAddr iop_base
+                       PortAddr iop_base
 )
 {
-	int                 count;
-	uchar               stop_code;
-	count = 0;
-	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
-		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-						 ASC_STOP_CLEAN_UP_BUSY_Q);
-		do {
-			stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
-			if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0)
-				break;
-			DvcSleepMilliSecond(100);
-		} while (count++ < 20);
-	}
-	return (1);
+    int                 count;
+    uchar               stop_code;
+
+    count = 0;
+    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
+        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                         ASC_STOP_CLEAN_UP_BUSY_Q);
+        do {
+            stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+            if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0)
+                break;
+            DvcSleepMilliSecond(100);
+        } while (count++ < 20);
+    }
+    return (1);
 }
 
-int
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+STATIC int
 AscCleanUpDiscQueue(
-					   PortAddr iop_base
+                       PortAddr iop_base
 )
 {
-	int                 count;
-	uchar               stop_code;
-	count = 0;
-	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
-		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-						 ASC_STOP_CLEAN_UP_DISC_Q);
-		do {
-			stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
-			if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0)
-				break;
-			DvcSleepMilliSecond(100);
-		} while (count++ < 20);
-	}
-	return (1);
+    int                 count;
+    uchar               stop_code;
+
+    count = 0;
+    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
+        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                         ASC_STOP_CLEAN_UP_DISC_Q);
+        do {
+            stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+            if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0)
+                break;
+            DvcSleepMilliSecond(100);
+        } while (count++ < 20);
+    }
+    return (1);
 }
+#endif /* version >= v1.3.89 */
 
-int
+STATIC int
 AscWaitTixISRDone(
-					 ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					 uchar target_ix
+                     ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                     uchar target_ix
 )
 {
-	uchar               cur_req;
-	uchar               tid_no;
-	tid_no = ASC_TIX_TO_TID(target_ix);
-	while (TRUE) {
-		if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) {
-			break;
-		}
-		DvcSleepMilliSecond(1000L);
-		if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) {
-			break;
-		}
-	}
-	return (1);
+    uchar               cur_req;
+    uchar               tid_no;
+    int                 i = 0;
+
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    while (i++ < 10) {
+        if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) {
+            break;
+        }
+        DvcSleepMilliSecond(100L);
+        if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) {
+            break;
+        }
+    }
+    return (1);
 }
 
-int
+STATIC int
 AscWaitISRDone(
-				  REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	int                 tid;
-	for (tid = 0; tid <= ASC_MAX_TID; tid++) {
-		AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid));
-	}
-	return (1);
+    int                 tid;
+
+    for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+        AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid));
+    }
+    return (1);
 }
 
-ulong
+STATIC ulong
 AscGetOnePhyAddr(
-					REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					uchar dosfar * buf_addr,
-					ulong buf_size
+                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                    uchar * buf_addr,
+                    ulong buf_size
 )
 {
-	ASC_MIN_SG_HEAD     sg_head;
-	sg_head.entry_cnt = ASC_MIN_SG_LIST;
-	if (DvcGetSGList(asc_dvc, (uchar dosfar *) buf_addr,
-				  buf_size, (ASC_SG_HEAD dosfar *) & sg_head) != buf_size) {
-		return (0L);
-	}
-	if (sg_head.entry_cnt > 1) {
-		return (0L);
-	}
-	return (sg_head.sg_list[0].addr);
+    ASC_MIN_SG_HEAD     sg_head;
+
+    sg_head.entry_cnt = ASC_MIN_SG_LIST;
+    if (DvcGetSGList(asc_dvc, (uchar *) buf_addr,
+                  buf_size, (ASC_SG_HEAD *) & sg_head) != buf_size) {
+        return (0L);
+    }
+    if (sg_head.entry_cnt > 1) {
+        return (0L);
+    }
+    return (sg_head.sg_list[0].addr);
 }
 
-void
-DvcDelayNanoSecond(
-					  ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					  ulong nano_sec
-)
+STATIC void
+DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
 {
-	ulong               loop;
-	PortAddr            iop_base;
-	iop_base = asc_dvc->iop_base;
-	loop = nano_sec / 90;
-	loop++;
-	while (loop-- != 0) {
-		inp(iop_base);
-	}
-	return;
+    udelay(micro_sec);
 }
 
-ulong
+STATIC void
+DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong nano_sec)
+{
+    udelay((nano_sec + 999)/1000);
+}
+
+ASC_INITFUNC(
+STATIC ulong
 AscGetEisaProductID(
-					   PortAddr iop_base
+                       PortAddr iop_base
+)
 )
 {
-	PortAddr            eisa_iop;
-	ushort              product_id_high, product_id_low;
-	ulong               product_id;
-	eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
-	product_id_low = inpw(eisa_iop);
-	product_id_high = inpw(eisa_iop + 2);
-	product_id = ((ulong) product_id_high << 16) | (ulong) product_id_low;
-	return (product_id);
+    PortAddr            eisa_iop;
+    ushort              product_id_high, product_id_low;
+    ulong               product_id;
+
+    eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
+    product_id_low = inpw(eisa_iop);
+    product_id_high = inpw(eisa_iop + 2);
+    product_id = ((ulong) product_id_high << 16) | (ulong) product_id_low;
+    return (product_id);
 }
 
-PortAddr
+ASC_INITFUNC(
+STATIC PortAddr
 AscSearchIOPortAddrEISA(
-						   PortAddr iop_base
+                           PortAddr iop_base
+)
 )
 {
-	ulong               eisa_product_id;
-	if (iop_base == 0) {
-		iop_base = ASC_EISA_MIN_IOP_ADDR;
-	} else {
-		if (iop_base == ASC_EISA_MAX_IOP_ADDR)
-			return (0);
-		if ((iop_base & 0x0050) == 0x0050) {
-			iop_base += ASC_EISA_BIG_IOP_GAP;
-		} else {
-			iop_base += ASC_EISA_SMALL_IOP_GAP;
-		}
-	}
-	while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
-		eisa_product_id = AscGetEisaProductID(iop_base);
-		if (
-			   (eisa_product_id == ASC_EISA_ID_740)
-			   || (eisa_product_id == ASC_EISA_ID_750)
-		  ) {
-			if (AscFindSignature(iop_base)) {
-				inpw(iop_base + 4);
-				return (iop_base);
-			}
-		}
-		if (iop_base == ASC_EISA_MAX_IOP_ADDR)
-			return (0);
-		if ((iop_base & 0x0050) == 0x0050) {
-			iop_base += ASC_EISA_BIG_IOP_GAP;
-		} else {
-			iop_base += ASC_EISA_SMALL_IOP_GAP;
-		}
-	}
-	return (0);
+    ulong               eisa_product_id;
+
+    if (iop_base == 0) {
+        iop_base = ASC_EISA_MIN_IOP_ADDR;
+    } else {
+        if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+            return (0);
+        if ((iop_base & 0x0050) == 0x0050) {
+            iop_base += ASC_EISA_BIG_IOP_GAP;
+        } else {
+            iop_base += ASC_EISA_SMALL_IOP_GAP;
+        }
+    }
+    while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
+        eisa_product_id = AscGetEisaProductID(iop_base);
+        if ((eisa_product_id == ASC_EISA_ID_740) ||
+            (eisa_product_id == ASC_EISA_ID_750)) {
+            if (AscFindSignature(iop_base)) {
+                inpw(iop_base + 4);
+                return (iop_base);
+            }
+        }
+        if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+            return (0);
+        if ((iop_base & 0x0050) == 0x0050) {
+            iop_base += ASC_EISA_BIG_IOP_GAP;
+        } else {
+            iop_base += ASC_EISA_SMALL_IOP_GAP;
+        }
+    }
+    return (0);
 }
 
-int
+STATIC int
 AscStartChip(
-				PortAddr iop_base
+                PortAddr iop_base
 )
 {
-	AscSetChipControl(iop_base, 0);
-	if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
-		return (0);
-	}
-	return (1);
+    AscSetChipControl(iop_base, 0);
+    if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+        return (0);
+    }
+    return (1);
 }
 
-int
+STATIC int
 AscStopChip(
-			   PortAddr iop_base
+               PortAddr iop_base
 )
 {
-	uchar               cc_val;
-	cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
-	AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT));
-	AscSetChipIH(iop_base, INS_HALT);
-	AscSetChipIH(iop_base, INS_RFLAG_WTM);
-	if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
-		return (0);
-	}
-	return (1);
+    uchar               cc_val;
+
+    cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+    AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT));
+    AscSetChipIH(iop_base, INS_HALT);
+    AscSetChipIH(iop_base, INS_RFLAG_WTM);
+    if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+        return (0);
+    }
+    return (1);
 }
 
-int
+STATIC int
 AscIsChipHalted(
-				   PortAddr iop_base
+                   PortAddr iop_base
 )
 {
-	if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
-		if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
-			return (1);
-		}
-	}
-	return (0);
+    if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+        if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+            return (1);
+        }
+    }
+    return (0);
 }
 
-void
+STATIC void
 AscSetChipIH(
-				PortAddr iop_base,
-				ushort ins_code
+                PortAddr iop_base,
+                ushort ins_code
 )
 {
-	AscSetBank(iop_base, 1);
-	AscWriteChipIH(iop_base, ins_code);
-	AscSetBank(iop_base, 0);
-	return;
+    AscSetBank(iop_base, 1);
+    AscWriteChipIH(iop_base, ins_code);
+    AscSetBank(iop_base, 0);
+    return;
 }
 
-void
+STATIC void
 AscAckInterrupt(
-				   PortAddr iop_base
+                   PortAddr iop_base
 )
 {
-	uchar               host_flag;
-	uchar               risc_flag;
-	ushort              loop;
-	loop = 0;
-	do {
-		risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
-		if (loop++ > 0x7FFF) {
-			break;
-		}
-	} while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
-	host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
-	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
-					 (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT));
-	AscSetChipStatus(iop_base, CIW_INT_ACK);
-	loop = 0;
-	while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
-		AscSetChipStatus(iop_base, CIW_INT_ACK);
-		if (loop++ > 3) {
-			break;
-		}
-	}
-	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
-	return;
+    uchar               host_flag;
+    uchar               risc_flag;
+    ushort              loop;
+
+    loop = 0;
+    do {
+        risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+        if (loop++ > 0x7FFF) {
+            break;
+        }
+    } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+    host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+                     (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT));
+    AscSetChipStatus(iop_base, CIW_INT_ACK);
+    loop = 0;
+    while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+        AscSetChipStatus(iop_base, CIW_INT_ACK);
+        if (loop++ > 3) {
+            break;
+        }
+    }
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+    return;
 }
 
-void
+STATIC void
 AscDisableInterrupt(
-					   PortAddr iop_base
+                       PortAddr iop_base
 )
 {
-	ushort              cfg;
-	cfg = AscGetChipCfgLsw(iop_base);
-	AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
-	return;
+    ushort              cfg;
+
+    cfg = AscGetChipCfgLsw(iop_base);
+    AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+    return;
 }
 
-void
+STATIC void
 AscEnableInterrupt(
-					  PortAddr iop_base
+                      PortAddr iop_base
 )
 {
-	ushort              cfg;
-	cfg = AscGetChipCfgLsw(iop_base);
-	AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
-	return;
+    ushort              cfg;
+
+    cfg = AscGetChipCfgLsw(iop_base);
+    AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
+    return;
 }
 
 
 
-void
+STATIC void
 AscSetBank(
-			  PortAddr iop_base,
-			  uchar bank
+              PortAddr iop_base,
+              uchar bank
 )
 {
-	uchar               val;
-	val = AscGetChipControl(iop_base) &
-	  (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET));
-	if (bank == 1) {
-		val |= CC_BANK_ONE;
-	} else if (bank == 2) {
-		val |= CC_DIAG | CC_BANK_ONE;
-	} else {
-		val &= ~CC_BANK_ONE;
-	}
-	AscSetChipControl(iop_base, val);
-	return;
-}
-
+    uchar               val;
 
+    val = AscGetChipControl(iop_base) &
+      (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET));
+    if (bank == 1) {
+        val |= CC_BANK_ONE;
+    } else if (bank == 2) {
+        val |= CC_DIAG | CC_BANK_ONE;
+    } else {
+        val &= ~CC_BANK_ONE;
+    }
+    AscSetChipControl(iop_base, val);
+    return;
+}
 
-int
+STATIC int
 AscResetChipAndScsiBus(
-						  PortAddr iop_base
+                          ASC_DVC_VAR *asc_dvc
 )
 {
-	while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
-	AscStopChip(iop_base);
-	AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
-	DvcSleepMilliSecond(200);
-	AscSetChipIH(iop_base, INS_RFLAG_WTM);
-	AscSetChipIH(iop_base, INS_HALT);
-	AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
-	AscSetChipControl(iop_base, CC_HALT);
-	DvcSleepMilliSecond(200);
-	AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-	AscSetChipStatus(iop_base, 0);
-	return (AscIsChipHalted(iop_base));
-}
-
+    PortAddr    iop_base;
 
+    iop_base = asc_dvc->iop_base;
+    while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+    AscStopChip(iop_base);
+    AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+    DvcDelayNanoSecond(asc_dvc, 60000);
+    AscSetChipIH(iop_base, INS_RFLAG_WTM);
+    AscSetChipIH(iop_base, INS_HALT);
+    AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+    AscSetChipControl(iop_base, CC_HALT);
+    DvcSleepMilliSecond(200);
+    AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+    AscSetChipStatus(iop_base, 0);
+    return (AscIsChipHalted(iop_base));
+}
 
-ulong
+ASC_INITFUNC(
+STATIC ulong
 AscGetMaxDmaCount(
-					 ushort bus_type
+                     ushort bus_type
+)
 )
 {
-	if (bus_type & ASC_IS_ISA)
-		return (ASC_MAX_ISA_DMA_COUNT);
-	else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
-		return (ASC_MAX_VL_DMA_COUNT);
-	return (ASC_MAX_PCI_DMA_COUNT);
+    if (bus_type & ASC_IS_ISA)
+        return (ASC_MAX_ISA_DMA_COUNT);
+    else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
+        return (ASC_MAX_VL_DMA_COUNT);
+    return (ASC_MAX_PCI_DMA_COUNT);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscGetIsaDmaChannel(
-					   PortAddr iop_base
+                       PortAddr iop_base
+)
 )
 {
-	ushort              channel;
-	channel = AscGetChipCfgLsw(iop_base) & 0x0003;
-	if (channel == 0x03)
-		return (0);
-	else if (channel == 0x00)
-		return (7);
-	return (channel + 4);
+    ushort              channel;
+
+    channel = AscGetChipCfgLsw(iop_base) & 0x0003;
+    if (channel == 0x03)
+        return (0);
+    else if (channel == 0x00)
+        return (7);
+    return (channel + 4);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscSetIsaDmaChannel(
-					   PortAddr iop_base,
-					   ushort dma_channel
+                       PortAddr iop_base,
+                       ushort dma_channel
+)
 )
 {
-	ushort              cfg_lsw;
-	uchar               value;
-	if ((dma_channel >= 5) && (dma_channel <= 7)) {
-		if (dma_channel == 7)
-			value = 0x00;
-		else
-			value = dma_channel - 4;
-		cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
-		cfg_lsw |= value;
-		AscSetChipCfgLsw(iop_base, cfg_lsw);
-		return (AscGetIsaDmaChannel(iop_base));
-	}
-	return (0);
+    ushort              cfg_lsw;
+    uchar               value;
+
+    if ((dma_channel >= 5) && (dma_channel <= 7)) {
+        if (dma_channel == 7)
+            value = 0x00;
+        else
+            value = dma_channel - 4;
+        cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
+        cfg_lsw |= value;
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        return (AscGetIsaDmaChannel(iop_base));
+    }
+    return (0);
 }
 
-uchar
+ASC_INITFUNC(
+STATIC uchar
 AscSetIsaDmaSpeed(
-					 PortAddr iop_base,
-					 uchar speed_value
+                     PortAddr iop_base,
+                     uchar speed_value
+)
 )
 {
-	speed_value &= 0x07;
-	AscSetBank(iop_base, 1);
-	AscWriteChipDmaSpeed(iop_base, speed_value);
-	AscSetBank(iop_base, 0);
-	return (AscGetIsaDmaSpeed(iop_base));
+    speed_value &= 0x07;
+    AscSetBank(iop_base, 1);
+    AscWriteChipDmaSpeed(iop_base, speed_value);
+    AscSetBank(iop_base, 0);
+    return (AscGetIsaDmaSpeed(iop_base));
 }
 
-uchar
+ASC_INITFUNC(
+STATIC uchar
 AscGetIsaDmaSpeed(
-					 PortAddr iop_base
+                     PortAddr iop_base
+)
+)
+{
+    uchar               speed_value;
+
+    AscSetBank(iop_base, 1);
+    speed_value = AscReadChipDmaSpeed(iop_base);
+    speed_value &= 0x07;
+    AscSetBank(iop_base, 0);
+    return (speed_value);
+}
+
+ASC_INITFUNC(
+STATIC ushort
+AscReadPCIConfigWord(
+    ASC_DVC_VAR asc_ptr_type *asc_dvc,
+    ushort pci_config_offset)
 )
 {
-	uchar               speed_value;
-	AscSetBank(iop_base, 1);
-	speed_value = AscReadChipDmaSpeed(iop_base);
-	speed_value &= 0x07;
-	AscSetBank(iop_base, 0);
-	return (speed_value);
+    uchar       lsb, msb;
+
+    lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
+    msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
+    return ((ushort) ((msb << 8) | lsb));
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort 
 AscInitGetConfig(
-					ASC_DVC_VAR asc_ptr_type * asc_dvc
+        ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	ushort              warn_code;
-	warn_code = 0;
-	asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
-	if (asc_dvc->err_code != 0)
-		return (UW_ERR);
-	if (AscFindSignature(asc_dvc->iop_base)) {
-		warn_code |= AscInitAscDvcVar(asc_dvc);
-#if CC_INCLUDE_EEP_CONFIG
-		if (asc_dvc->init_state & ASC_INIT_STATE_WITHOUT_EEP) {
-			warn_code |= AscInitWithoutEEP(asc_dvc);
-		} else {
-			warn_code |= AscInitFromEEP(asc_dvc);
-		}
-#else
-		warn_code |= AscInitWithoutEEP(asc_dvc);
-#endif
-		asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
-		if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
-			asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
-		}
-	} else {
-		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-	}
-	return (warn_code);
+    ushort              warn_code;
+    PortAddr            iop_base;
+    ushort              PCIDeviceID;
+    ushort              PCIVendorID;
+    uchar               PCIRevisionID;
+    uchar               prevCmdRegBits;
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+    asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+    if (asc_dvc->err_code != 0) {
+        return (UW_ERR);
+    }
+    if (asc_dvc->bus_type == ASC_IS_PCI) {
+        PCIVendorID = AscReadPCIConfigWord(asc_dvc,
+                                    AscPCIConfigVendorIDRegister);
+
+        PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
+                                    AscPCIConfigDeviceIDRegister);
+
+        PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
+                                    AscPCIConfigRevisionIDRegister);
+
+        if (PCIVendorID != ASC_PCI_VENDORID) {
+            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+        }
+        prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
+                                    AscPCIConfigCommandRegister);
+
+        if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
+            AscPCICmdRegBits_IOMemBusMaster) {
+            DvcWritePCIConfigByte(asc_dvc,
+                            AscPCIConfigCommandRegister,
+                            (prevCmdRegBits |
+                             AscPCICmdRegBits_IOMemBusMaster));
+
+            if ((DvcReadPCIConfigByte(asc_dvc,
+                                AscPCIConfigCommandRegister)
+                 & AscPCICmdRegBits_IOMemBusMaster)
+                != AscPCICmdRegBits_IOMemBusMaster) {
+                warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+            }
+        }
+        if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) ||
+            (PCIDeviceID == ASC_PCI_DEVICEID_1200B)) {
+            DvcWritePCIConfigByte(asc_dvc,
+                            AscPCIConfigLatencyTimer, 0x00);
+            if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
+                != 0x00) {
+                warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+            }
+        } else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) {
+            if (DvcReadPCIConfigByte(asc_dvc,
+                                AscPCIConfigLatencyTimer) < 0x20) {
+                DvcWritePCIConfigByte(asc_dvc,
+                                    AscPCIConfigLatencyTimer, 0x20);
+
+                if (DvcReadPCIConfigByte(asc_dvc,
+                                    AscPCIConfigLatencyTimer) < 0x20) {
+                    warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+                }
+            }
+        }
+    }
+
+    if (AscFindSignature(iop_base)) {
+        warn_code |= AscInitAscDvcVar(asc_dvc);
+        warn_code |= AscInitFromEEP(asc_dvc);
+        asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+        if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
+            asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
+        }
+    } else {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+    }
+    return(warn_code);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscInitSetConfig(
-					ASC_DVC_VAR asc_ptr_type * asc_dvc
+                    ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	ushort              warn_code;
-	warn_code = 0;
-	asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
-	if (asc_dvc->err_code != 0)
-		return (UW_ERR);
-	if (AscFindSignature(asc_dvc->iop_base)) {
-		warn_code |= AscInitFromAscDvcVar(asc_dvc);
-		asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
-	} else {
-		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-	}
-	return (warn_code);
+    ushort              warn_code = 0;
+
+    asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+    if (asc_dvc->err_code != 0)
+        return (UW_ERR);
+    if (AscFindSignature(asc_dvc->iop_base)) {
+        warn_code |= AscInitFromAscDvcVar(asc_dvc);
+        asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
+    } else {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+    }
+    return (warn_code);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscInitFromAscDvcVar(
-						ASC_DVC_VAR asc_ptr_type * asc_dvc
+                        ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	PortAddr            iop_base;
-	ushort              cfg_msw;
-	ushort              warn_code;
-	ushort              pci_device_id;
-	iop_base = asc_dvc->iop_base;
-	pci_device_id = asc_dvc->cfg->pci_device_id;
-	warn_code = 0;
-	cfg_msw = AscGetChipCfgMsw(iop_base);
-	if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
-		cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-		warn_code |= ASC_WARN_CFG_MSW_RECOVER;
-		AscSetChipCfgMsw(iop_base, cfg_msw);
-	}
-	if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
-		asc_dvc->cfg->cmd_qng_enabled) {
-		asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
-		warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
-	}
-	if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
-		warn_code |= ASC_WARN_AUTO_CONFIG;
-	}
-	if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
-		if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
-			!= asc_dvc->irq_no) {
-			asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
-		}
-	}
-	if (asc_dvc->bus_type & ASC_IS_PCI) {
-#if CC_DISABLE_PCI_PARITY_INT
-		cfg_msw &= 0xFFC0;
-		AscSetChipCfgMsw(iop_base, cfg_msw);
-#endif
-		if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
-		} else {
-			if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
-				(pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
-				asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
-				asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
-#if CC_SET_PCI_LATENCY_TIMER_ZERO
-				DvcWritePCIConfigByte(asc_dvc,
-									  AscPCIConfigCommandRegister,
-									  AscPCICmdRegBits_BusMastering
-				  );
-				if ((DvcReadPCIConfigByte(asc_dvc,
-										  AscPCIConfigCommandRegister
-					 )
-					 & AscPCICmdRegBits_BusMastering)
-					!= AscPCICmdRegBits_BusMastering) {
-					warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-				}
-				DvcWritePCIConfigByte(asc_dvc,
-									  AscPCIConfigLatencyTimer,
-									  0x00
-				  );
-				if (DvcReadPCIConfigByte(asc_dvc,
-										 AscPCIConfigLatencyTimer
-					) != 0x00) {
-					warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-				}
-#endif
-			}
-		}
-	} else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
-		if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
-			== ASC_CHIP_VER_ASYN_BUG) {
-			asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
-		}
-	}
-	if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
-		asc_dvc->cfg->chip_scsi_id) {
-		asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
-	}
-	if (asc_dvc->bus_type & ASC_IS_ISA) {
-		AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
-		AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
-	}
-	return (warn_code);
+    PortAddr            iop_base;
+    ushort              cfg_msw;
+    ushort              warn_code;
+    ushort              pci_device_id;
+
+    iop_base = asc_dvc->iop_base;
+    pci_device_id = asc_dvc->cfg->pci_device_id;
+    warn_code = 0;
+    cfg_msw = AscGetChipCfgMsw(iop_base);
+    if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+        cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+        warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+        AscSetChipCfgMsw(iop_base, cfg_msw);
+    }
+    if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+        asc_dvc->cfg->cmd_qng_enabled) {
+        asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+        warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+    }
+    if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+        warn_code |= ASC_WARN_AUTO_CONFIG;
+    }
+    if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
+        if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
+            != asc_dvc->irq_no) {
+            asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
+        }
+    }
+    if (asc_dvc->bus_type & ASC_IS_PCI) {
+        cfg_msw &= 0xFFC0;
+        AscSetChipCfgMsw(iop_base, cfg_msw);
+        if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
+        } else {
+            if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
+                (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
+                asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+                asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+            }
+        }
+    } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
+        if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+            == ASC_CHIP_VER_ASYN_BUG) {
+            asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+        }
+    }
+    if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+        asc_dvc->cfg->chip_scsi_id) {
+        asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+    }
+    if (asc_dvc->bus_type & ASC_IS_ISA) {
+        AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+        AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+    }
+    return (warn_code);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscInitAsc1000Driver(
-						ASC_DVC_VAR asc_ptr_type * asc_dvc
+                        ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	ushort              warn_code;
-	PortAddr            iop_base;
-	extern ushort       _mcode_size;
-	extern ulong        _mcode_chksum;
-	extern uchar        _mcode_buf[];
-	iop_base = asc_dvc->iop_base;
-	warn_code = 0;
-	if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
-		!(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
-		AscResetChipAndScsiBus(iop_base);
-		DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
-	}
-	asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
-	if (asc_dvc->err_code != 0)
-		return (UW_ERR);
-	if (!AscFindSignature(asc_dvc->iop_base)) {
-		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-		return (warn_code);
-	}
-	AscDisableInterrupt(iop_base);
-	warn_code |= AscInitLram(asc_dvc);
-	if (asc_dvc->err_code != 0)
-		return (UW_ERR);
-	if (AscLoadMicroCode(iop_base, 0, (ushort dosfar *) _mcode_buf,
-						 _mcode_size) != _mcode_chksum) {
-		asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-		return (warn_code);
-	}
-	warn_code |= AscInitMicroCodeVar(asc_dvc);
-	asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
-	AscEnableInterrupt(iop_base);
-	return (warn_code);
+    ushort              warn_code;
+    PortAddr            iop_base;
+    extern ushort       _asc_mcode_size;
+    extern ulong        _asc_mcode_chksum;
+    extern uchar        _asc_mcode_buf[];
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+        !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+        AscResetChipAndScsiBus(asc_dvc);
+        DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+    }
+    asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+    if (asc_dvc->err_code != 0)
+        return (UW_ERR);
+    if (!AscFindSignature(asc_dvc->iop_base)) {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+        return (warn_code);
+    }
+    AscDisableInterrupt(iop_base);
+    warn_code |= AscInitLram(asc_dvc);
+    if (asc_dvc->err_code != 0)
+        return (UW_ERR);
+    if (AscLoadMicroCode(iop_base, 0, (ushort *) _asc_mcode_buf,
+                         _asc_mcode_size) != _asc_mcode_chksum) {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return (warn_code);
+    }
+    warn_code |= AscInitMicroCodeVar(asc_dvc);
+    asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+    AscEnableInterrupt(iop_base);
+    return (warn_code);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscInitAscDvcVar(
-					ASC_DVC_VAR asc_ptr_type * asc_dvc
+                    ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	int                 i;
-	PortAddr            iop_base;
-	ushort              warn_code;
-	uchar               chip_version;
-	iop_base = asc_dvc->iop_base;
-	warn_code = 0;
-	asc_dvc->err_code = 0;
-	if (
-		   (asc_dvc->bus_type &
-			(ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0
-	  ) {
-		asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
-	}
-	AscSetChipControl(iop_base, CC_HALT);
-	AscSetChipStatus(iop_base, 0);
-#if CC_LINK_BUSY_Q
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L;
-		asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L;
-	}
-#endif
-	asc_dvc->bug_fix_cntl = 0;
-	asc_dvc->pci_fix_asyn_xfer = 0;
-	asc_dvc->pci_fix_asyn_xfer_always = 0;
-	asc_dvc->init_state = 0;
-	asc_dvc->sdtr_done = 0;
-	asc_dvc->cur_total_qng = 0;
-	asc_dvc->is_in_int = 0;
-	asc_dvc->in_critical_cnt = 0;
-	asc_dvc->last_q_shortage = 0;
-	asc_dvc->use_tagged_qng = 0;
-	asc_dvc->no_scam = 0;
-	asc_dvc->unit_not_ready = 0;
-	asc_dvc->queue_full_or_busy = 0;
-	asc_dvc->redo_scam = 0 ;
-	asc_dvc->res2 = 0 ;
-	asc_dvc->host_init_sdtr_index = 0 ;
-	asc_dvc->res7 = 0 ;
-	asc_dvc->res8 = 0 ;
-	asc_dvc->cfg->can_tagged_qng = 0 ;
-	asc_dvc->cfg->cmd_qng_enabled = 0;
-	asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
-	asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET;
-	asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
-	asc_dvc->scsi_reset_wait = 3;
-	asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
-	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
-	asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
-	asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
-	asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
-	asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
-	  ASC_LIB_VERSION_MINOR;
-	chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
-	asc_dvc->cfg->chip_version = chip_version;
-	asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
-	asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
-	asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
-	asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
-	asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
-	asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
-	asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
-	asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
-	asc_dvc->max_sdtr_index = 7;
-	if (
-		   (asc_dvc->bus_type & ASC_IS_PCI) &&
-		   (chip_version >= ASC_CHIP_VER_1ST_PCI_ULTRA)
-	  ) {
-		asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
-		asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
-		asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
-		asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
-		asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
-		asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
-		asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
-		asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
-		asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
-		asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
-		asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
-		asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
-		asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
-		asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
-		asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
-		asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
-		asc_dvc->max_sdtr_index = 15;
-		AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
-		asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
-	}
-	asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
-	if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
-		AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
-		asc_dvc->bus_type = ASC_IS_ISAPNP;
-	}
-	if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
-		asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base);
-	}
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		asc_dvc->cur_dvc_qng[i] = 0;
-		asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
-		asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L;
-		asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L;
-		asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
-	}
-	return (warn_code);
+    int                 i;
+    PortAddr            iop_base;
+    ushort              warn_code;
+    uchar               chip_version;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    asc_dvc->err_code = 0;
+    if ((asc_dvc->bus_type &
+         (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
+        asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
+    }
+    AscSetChipControl(iop_base, CC_HALT);
+    AscSetChipStatus(iop_base, 0);
+    asc_dvc->bug_fix_cntl = 0;
+    asc_dvc->pci_fix_asyn_xfer = 0;
+    asc_dvc->pci_fix_asyn_xfer_always = 0;
+    asc_dvc->init_state = 0;
+    asc_dvc->sdtr_done = 0;
+    asc_dvc->cur_total_qng = 0;
+    asc_dvc->is_in_int = 0;
+    asc_dvc->in_critical_cnt = 0;
+    asc_dvc->last_q_shortage = 0;
+    asc_dvc->use_tagged_qng = 0;
+    asc_dvc->no_scam = 0;
+    asc_dvc->unit_not_ready = 0;
+    asc_dvc->queue_full_or_busy = 0;
+    asc_dvc->redo_scam = 0 ;
+    asc_dvc->res2 = 0 ;
+    asc_dvc->host_init_sdtr_index = 0 ;
+    asc_dvc->res7 = 0 ;
+    asc_dvc->res8 = 0 ;
+    asc_dvc->cfg->can_tagged_qng = 0 ;
+    asc_dvc->cfg->cmd_qng_enabled = 0;
+    asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
+    asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET;
+    asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
+    asc_dvc->scsi_reset_wait = 3;
+    asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
+    asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
+    asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
+    asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
+    asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
+    asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
+      ASC_LIB_VERSION_MINOR;
+    chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
+    asc_dvc->cfg->chip_version = chip_version;
+    asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
+    asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
+    asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
+    asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
+    asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
+    asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
+    asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
+    asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
+    asc_dvc->max_sdtr_index = 7;
+    if ((asc_dvc->bus_type & ASC_IS_PCI) &&
+        (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
+        asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
+        asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
+        asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
+        asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
+        asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
+        asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
+        asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
+        asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
+        asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
+        asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
+        asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
+        asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
+        asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
+        asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
+        asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
+        asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
+        asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
+        asc_dvc->max_sdtr_index = 15;
+        if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150)
+        {
+            AscSetExtraControl(iop_base,
+                (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+        } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
+            AscSetExtraControl(iop_base,
+                (SEC_ACTIVE_NEGATE | SEC_ENABLE_FILTER));
+        }
+    }
+    if (asc_dvc->bus_type == ASC_IS_PCI) {
+           AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+    }
+
+    asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
+    if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
+        AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
+        asc_dvc->bus_type = ASC_IS_ISAPNP;
+    }
+    if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+        asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base);
+    }
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        asc_dvc->cur_dvc_qng[i] = 0;
+        asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
+        asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *) 0L;
+        asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *) 0L;
+        asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
+    }
+    return (warn_code);
 }
 
-#if CC_INCLUDE_EEP_CONFIG
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscInitFromEEP(
-				  ASC_DVC_VAR asc_ptr_type * asc_dvc
+                  ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	ASCEEP_CONFIG       eep_config_buf;
-	ASCEEP_CONFIG dosfar *eep_config;
-	PortAddr            iop_base;
-	ushort              chksum;
-	ushort              warn_code;
-	ushort              cfg_msw, cfg_lsw;
-	int                 i;
-	iop_base = asc_dvc->iop_base;
-	warn_code = 0;
-	AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
-	AscStopQueueExe(iop_base);
-	if ((AscStopChip(iop_base) == FALSE) ||
-		(AscGetChipScsiCtrl(iop_base) != 0)) {
-		asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
-		AscResetChipAndScsiBus(iop_base);
-		DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
-	}
-	if (AscIsChipHalted(iop_base) == FALSE) {
-		asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
-		return (warn_code);
-	}
-	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-		asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
-		return (warn_code);
-	}
-	eep_config = (ASCEEP_CONFIG dosfar *) & eep_config_buf;
-	cfg_msw = AscGetChipCfgMsw(iop_base);
-	cfg_lsw = AscGetChipCfgLsw(iop_base);
-	if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
-		cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-		warn_code |= ASC_WARN_CFG_MSW_RECOVER;
-		AscSetChipCfgMsw(iop_base, cfg_msw);
-	}
-	chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
-	eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-	if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
-		warn_code |= ASC_WARN_AUTO_CONFIG;
-		if (asc_dvc->cfg->chip_version == 3) {
-			if (eep_config->cfg_lsw != cfg_lsw) {
-				warn_code |= ASC_WARN_EEPROM_RECOVER;
-				eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base);
-			}
-			if (eep_config->cfg_msw != cfg_msw) {
-				warn_code |= ASC_WARN_EEPROM_RECOVER;
-				eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
-			}
-		}
-	}
-	eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
-	if (chksum != eep_config->chksum) {
-		warn_code |= ASC_WARN_EEPROM_CHKSUM;
-	}
-	asc_dvc->init_sdtr = eep_config->init_sdtr;
-	asc_dvc->cfg->disc_enable = eep_config->disc_enable;
-	asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
-	asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed;
-	asc_dvc->start_motor = eep_config->start_motor;
-	asc_dvc->dvc_cntl = eep_config->cntl;
-	asc_dvc->no_scam = eep_config->no_scam;
-	if (!AscTestExternalLram(asc_dvc)) {
-		if (
-			   ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)
-		  ) {
-			eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
-			eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
-		} else {
-			eep_config->cfg_msw |= 0x0800;
-			cfg_msw |= 0x0800;
-			AscSetChipCfgMsw(iop_base, cfg_msw);
-			eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
-			eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
-		}
-	} else {
-	}
-	if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
-		eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
-	}
-	if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
-		eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
-	}
-	if (eep_config->max_tag_qng > eep_config->max_total_qng) {
-		eep_config->max_tag_qng = eep_config->max_total_qng;
-	}
-	if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
-		eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
-	}
-	asc_dvc->max_total_qng = eep_config->max_total_qng;
-	if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
-		eep_config->use_cmd_qng) {
-		eep_config->disc_enable = eep_config->use_cmd_qng;
-		warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
-	}
-	if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
-		asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
-	}
-	eep_config->chip_scsi_id &= ASC_MAX_TID;
-	asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id;
-	if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA ) == ASC_IS_PCI_ULTRA ) &&
-	    !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
-		asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
-	}
-
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-#if CC_TMP_USE_EEP_SDTR
-		asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i];
-#endif
-		asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
-		asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
-		asc_dvc->cfg->sdtr_period_offset[i] =
-			(uchar) (ASC_DEF_SDTR_OFFSET |
-					 (asc_dvc->host_init_sdtr_index << 4));
-	}
-	eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
-#if CC_CHK_FIX_EEP_CONTENT
-	if (AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type) != 0) {
-		asc_dvc->err_code |= ASC_IERR_WRITE_EEPROM;
-	}
-#endif
-	return (warn_code);
-}
-#endif
+    ASCEEP_CONFIG       eep_config_buf;
+    ASCEEP_CONFIG       *eep_config;
+    PortAddr            iop_base;
+    ushort              chksum;
+    ushort              warn_code;
+    ushort              cfg_msw, cfg_lsw;
+    int                 i;
+    int                 write_eep = 0;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+    AscStopQueueExe(iop_base);
+    if ((AscStopChip(iop_base) == FALSE) ||
+        (AscGetChipScsiCtrl(iop_base) != 0)) {
+        asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+        AscResetChipAndScsiBus(asc_dvc);
+        DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+    }
+    if (AscIsChipHalted(iop_base) == FALSE) {
+        asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+        return (warn_code);
+    }
+    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+        asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+        return (warn_code);
+    }
+    eep_config = (ASCEEP_CONFIG *) & eep_config_buf;
+    cfg_msw = AscGetChipCfgMsw(iop_base);
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
+    if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+        cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+        warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+        AscSetChipCfgMsw(iop_base, cfg_msw);
+    }
+    chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+    if (chksum == 0) {
+        chksum = 0xaa55;
+    }
+    if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+        warn_code |= ASC_WARN_AUTO_CONFIG;
+        if (asc_dvc->cfg->chip_version == 3) {
+            if (eep_config->cfg_lsw != cfg_lsw) {
+                warn_code |= ASC_WARN_EEPROM_RECOVER;
+                eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base);
+            }
+            if (eep_config->cfg_msw != cfg_msw) {
+                warn_code |= ASC_WARN_EEPROM_RECOVER;
+                eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+            }
+        }
+    }
+    eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+    eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+    if (chksum != eep_config->chksum) {
+            if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+                    ASC_CHIP_VER_PCI_ULTRA_3050 )
+            {
+                eep_config->init_sdtr = 0xFF;
+                eep_config->disc_enable = 0xFF;
+                eep_config->start_motor = 0xFF;
+                eep_config->use_cmd_qng = 0;
+                eep_config->max_total_qng = 0xF0;
+                eep_config->max_tag_qng = 0x20;
+                eep_config->cntl = 0xBFFF;
+                eep_config->chip_scsi_id = 7;
+                eep_config->no_scam = 0;
+                eep_config->adapter_info[0] = 0;
+                eep_config->adapter_info[1] = 0;
+                eep_config->adapter_info[2] = 0;
+                eep_config->adapter_info[3] = 0;
+                eep_config->adapter_info[4] = 0;
+                /* Indicate EEPROM-less board. */
+                eep_config->adapter_info[5] = 0xBB;
+            } else {
+                write_eep = 1 ;
+                warn_code |= ASC_WARN_EEPROM_CHKSUM ;
+            }
+    }
+    asc_dvc->init_sdtr = eep_config->init_sdtr;
+    asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+    asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+    asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed;
+    asc_dvc->start_motor = eep_config->start_motor;
+    asc_dvc->dvc_cntl = eep_config->cntl;
+    asc_dvc->no_scam = eep_config->no_scam;
+    asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+    asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+    asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+    asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+    asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+    asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
+    if (!AscTestExternalLram(asc_dvc)) {
+        if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
+            eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+            eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+        } else {
+            eep_config->cfg_msw |= 0x0800;
+            cfg_msw |= 0x0800;
+            AscSetChipCfgMsw(iop_base, cfg_msw);
+            eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+            eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
+        }
+    } else {
+    }
+    if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+        eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
+    }
+    if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+        eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
+    }
+    if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+        eep_config->max_tag_qng = eep_config->max_total_qng;
+    }
+    if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+        eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+    }
+    asc_dvc->max_total_qng = eep_config->max_total_qng;
+    if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+        eep_config->use_cmd_qng) {
+        eep_config->disc_enable = eep_config->use_cmd_qng;
+        warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+    }
+    if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
+        asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
+    }
+    eep_config->chip_scsi_id &= ASC_MAX_TID;
+    asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id;
+    if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
+        !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+        asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+    }
 
-ushort
-AscInitWithoutEEP(
-					 ASC_DVC_VAR asc_ptr_type * asc_dvc
-)
-{
-	PortAddr            iop_base;
-	ushort              warn_code;
-	ushort              cfg_msw;
-	int					i;
-	iop_base = asc_dvc->iop_base;
-	warn_code = 0;
-	cfg_msw = AscGetChipCfgMsw(iop_base);
-	if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
-		cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-		warn_code |= ASC_WARN_CFG_MSW_RECOVER;
-		AscSetChipCfgMsw(iop_base, cfg_msw);
-	}
-	if (!AscTestExternalLram(asc_dvc)) {
-		if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
-			asc_dvc->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG ;
-			for( i = 0 ; i <= ASC_MAX_TID ; i++ ) {
-				asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG ;
-			}
-		} else {
-			cfg_msw |= 0x0800;
-			AscSetChipCfgMsw(iop_base, cfg_msw);
-			asc_dvc->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
-			for (i = 0 ; i <= ASC_MAX_TID ; i++) {
-				asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_INRAM_TAG_QNG;
-			}
-		}
-	}
-	if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
-		asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
-	}
-	return (warn_code);
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
+        asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+        asc_dvc->cfg->sdtr_period_offset[i] =
+            (uchar) (ASC_DEF_SDTR_OFFSET |
+                     (asc_dvc->host_init_sdtr_index << 4));
+    }
+    eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+    if (write_eep) {
+        (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+    }
+    return (warn_code);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscInitMicroCodeVar(
-					   ASC_DVC_VAR asc_ptr_type * asc_dvc
+                       ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	int                 i;
-	ushort              warn_code;
-	PortAddr            iop_base;
-	ulong               phy_addr;
-	iop_base = asc_dvc->iop_base;
-	warn_code = 0;
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		AscPutMCodeInitSDTRAtID(iop_base, i,
-								asc_dvc->cfg->sdtr_period_offset[i]
-		  );
-	}
-	AscInitQLinkVar(asc_dvc);
-	AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
-					 asc_dvc->cfg->disc_enable);
-	AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
-					 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
-	if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
-								 (uchar dosfar *) asc_dvc->cfg->overrun_buf,
-									 ASC_OVERRUN_BSIZE)) == 0L) {
-		asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR;
-	} else {
-		phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8;
-		AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr);
-		AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D,
-						  ASC_OVERRUN_BSIZE - 8);
-	}
-	asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base,
-											   (ushort) ASCV_MC_DATE_W);
-	asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base,
-												  (ushort) ASCV_MC_VER_W);
-	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-		asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
-		return (warn_code);
-	}
-	if (AscStartChip(iop_base) != 1) {
-		asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
-		return (warn_code);
-	}
-	return (warn_code);
+    int                 i;
+    ushort              warn_code;
+    PortAddr            iop_base;
+    ulong               phy_addr;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        AscPutMCodeInitSDTRAtID(iop_base, i,
+                                asc_dvc->cfg->sdtr_period_offset[i]
+);
+    }
+    AscInitQLinkVar(asc_dvc);
+    AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+                     asc_dvc->cfg->disc_enable);
+    AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+                     ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+    if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+                                 (uchar *) asc_dvc->cfg->overrun_buf,
+                                     ASC_OVERRUN_BSIZE)) == 0L) {
+        asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR;
+    } else {
+        phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8;
+        AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr);
+        AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D,
+                          ASC_OVERRUN_BSIZE - 8);
+    }
+    asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base,
+                                               (ushort) ASCV_MC_DATE_W);
+    asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base,
+                                                  (ushort) ASCV_MC_VER_W);
+    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+        asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+        return (warn_code);
+    }
+    if (AscStartChip(iop_base) != 1) {
+        asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+        return (warn_code);
+    }
+    return (warn_code);
 }
 
-void                dosfar
+STATIC void
 AscInitPollIsrCallBack(
-						  ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						  ASC_QDONE_INFO dosfar * scsi_done_q
+                          ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                          ASC_QDONE_INFO * scsi_done_q
 )
 {
-	ASC_SCSI_REQ_Q dosfar *scsiq_req;
-	ASC_ISR_CALLBACK    asc_isr_callback;
-	uchar               cp_sen_len;
-	uchar               i;
-	ASC_DBG(1, "AscInitPollIsrCallBack: begin\n");
-	if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) {
-		scsiq_req = (ASC_SCSI_REQ_Q dosfar *) scsi_done_q->d2.srb_ptr;
-		scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat;
-		scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat;
-		scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat;
-		scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg;
-		ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n",
-			scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat,
-			scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg);
-		if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) &&
-			(scsi_done_q->d3.host_stat == 0)) {
-			cp_sen_len = (uchar) ASC_MIN_SENSE_LEN;
-			if (scsiq_req->r1.sense_len < ASC_MIN_SENSE_LEN) {
-				cp_sen_len = (uchar) scsiq_req->r1.sense_len;
-			}
-			for (i = 0; i < cp_sen_len; i++) {
-				scsiq_req->sense[i] = scsiq_req->sense_ptr[i];
-			}
-		}
-	} else {
-		if (asc_dvc->isr_callback != 0) {
-			asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
-			(*asc_isr_callback) (asc_dvc, scsi_done_q);
-		}
-	}
-	ASC_DBG(1, "AscInitPollIsrCallBack: end\n");
-	return;
+    ASC_SCSI_REQ_Q *scsiq_req;
+    ASC_ISR_CALLBACK    asc_isr_callback;
+    uchar               cp_sen_len;
+    uchar               i;
+
+    ASC_DBG(1, "AscInitPollIsrCallBack: begin\n");
+    if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) {
+        scsiq_req = (ASC_SCSI_REQ_Q *) scsi_done_q->d2.srb_ptr;
+        scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat;
+        scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat;
+        scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat;
+        scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg;
+        ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n",
+            scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat,
+            scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg);
+        if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) &&
+            (scsi_done_q->d3.host_stat == 0)) {
+            cp_sen_len = (uchar) ASC_MIN_SENSE_LEN;
+            if (scsiq_req->r1.sense_len < ASC_MIN_SENSE_LEN) {
+                cp_sen_len = (uchar) scsiq_req->r1.sense_len;
+            }
+            for (i = 0; i < cp_sen_len; i++) {
+                scsiq_req->sense[i] = scsiq_req->sense_ptr[i];
+            }
+        }
+    } else {
+        if (asc_dvc->isr_callback != 0) {
+            asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+            (*asc_isr_callback) (asc_dvc, scsi_done_q);
+        }
+    }
+    ASC_DBG(1, "AscInitPollIsrCallBack: end\n");
+    return;
 }
 
-int
+ASC_INITFUNC(
+STATIC int
 AscTestExternalLram(
-					   ASC_DVC_VAR asc_ptr_type * asc_dvc
+                       ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
 )
 {
-	PortAddr            iop_base;
-	ushort              q_addr;
-	ushort              saved_word;
-	int                 sta;
-	iop_base = asc_dvc->iop_base;
-	sta = 0;
-	q_addr = ASC_QNO_TO_QADDR(241);
-	saved_word = AscReadLramWord(iop_base, q_addr);
-	AscSetChipLramAddr(iop_base, q_addr);
-	AscSetChipLramData(iop_base, 0x55AA);
-	DvcSleepMilliSecond(10);
-	AscSetChipLramAddr(iop_base, q_addr);
-	if (AscGetChipLramData(iop_base) == 0x55AA) {
-		sta = 1;
-		AscWriteLramWord(iop_base, q_addr, saved_word);
-	}
-	return (sta);
+    PortAddr            iop_base;
+    ushort              q_addr;
+    ushort              saved_word;
+    int                 sta;
+
+    iop_base = asc_dvc->iop_base;
+    sta = 0;
+    q_addr = ASC_QNO_TO_QADDR(241);
+    saved_word = AscReadLramWord(iop_base, q_addr);
+    AscSetChipLramAddr(iop_base, q_addr);
+    AscSetChipLramData(iop_base, 0x55AA);
+    DvcSleepMilliSecond(10);
+    AscSetChipLramAddr(iop_base, q_addr);
+    if (AscGetChipLramData(iop_base) == 0x55AA) {
+        sta = 1;
+        AscWriteLramWord(iop_base, q_addr, saved_word);
+    }
+    return (sta);
 }
 
-#if CC_INCLUDE_EEP_CONFIG
-int
+ASC_INITFUNC(
+STATIC int
 AscWriteEEPCmdReg(
-					 PortAddr iop_base,
-					 uchar cmd_reg
+                     PortAddr iop_base,
+                     uchar cmd_reg
+)
 )
 {
-	uchar               read_back;
-	int                 retry;
-	retry = 0;
-	while (TRUE) {
-		AscSetChipEEPCmd(iop_base, cmd_reg);
-		DvcSleepMilliSecond(1);
-		read_back = AscGetChipEEPCmd(iop_base);
-		if (read_back == cmd_reg) {
-			return (1);
-		}
-		if (retry++ > ASC_EEP_MAX_RETRY) {
-			return (0);
-		}
-	}
+    uchar               read_back;
+    int                 retry;
+
+    retry = 0;
+    while (TRUE) {
+        AscSetChipEEPCmd(iop_base, cmd_reg);
+        DvcSleepMilliSecond(1);
+        read_back = AscGetChipEEPCmd(iop_base);
+        if (read_back == cmd_reg) {
+            return (1);
+        }
+        if (retry++ > ASC_EEP_MAX_RETRY) {
+            return (0);
+        }
+    }
 }
 
-int
+ASC_INITFUNC(
+STATIC int
 AscWriteEEPDataReg(
-					  PortAddr iop_base,
-					  ushort data_reg
+                      PortAddr iop_base,
+                      ushort data_reg
+)
 )
 {
-	ushort              read_back;
-	int                 retry;
-	retry = 0;
-	while (TRUE) {
-		AscSetChipEEPData(iop_base, data_reg);
-		DvcSleepMilliSecond(1);
-		read_back = AscGetChipEEPData(iop_base);
-		if (read_back == data_reg) {
-			return (1);
-		}
-		if (retry++ > ASC_EEP_MAX_RETRY) {
-			return (0);
-		}
-	}
+    ushort              read_back;
+    int                 retry;
+
+    retry = 0;
+    while (TRUE) {
+        AscSetChipEEPData(iop_base, data_reg);
+        DvcSleepMilliSecond(1);
+        read_back = AscGetChipEEPData(iop_base);
+        if (read_back == data_reg) {
+            return (1);
+        }
+        if (retry++ > ASC_EEP_MAX_RETRY) {
+            return (0);
+        }
+    }
 }
 
-void
+ASC_INITFUNC(
+STATIC void
 AscWaitEEPRead(
-				  void
+                  void
+)
 )
 {
-	DvcSleepMilliSecond(1);
-	return;
+    DvcSleepMilliSecond(1);
+    return;
 }
 
-void
+ASC_INITFUNC(
+STATIC void
 AscWaitEEPWrite(
-				   void
+                   void
+)
 )
 {
-	DvcSleepMilliSecond(20);
-	return;
+    DvcSleepMilliSecond(20);
+    return;
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscReadEEPWord(
-				  PortAddr iop_base,
-				  uchar addr
+                  PortAddr iop_base,
+                  uchar addr
+)
 )
 {
-	ushort              read_wval;
-	uchar               cmd_reg;
-	AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
-	AscWaitEEPRead();
-	cmd_reg = addr | ASC_EEP_CMD_READ;
-	AscWriteEEPCmdReg(iop_base, cmd_reg);
-	AscWaitEEPRead();
-	read_wval = AscGetChipEEPData(iop_base);
-	AscWaitEEPRead();
-	return (read_wval);
+    ushort              read_wval;
+    uchar               cmd_reg;
+
+    AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+    AscWaitEEPRead();
+    cmd_reg = addr | ASC_EEP_CMD_READ;
+    AscWriteEEPCmdReg(iop_base, cmd_reg);
+    AscWaitEEPRead();
+    read_wval = AscGetChipEEPData(iop_base);
+    AscWaitEEPRead();
+    return (read_wval);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscWriteEEPWord(
-				   PortAddr iop_base,
-				   uchar addr,
-				   ushort word_val
-)
-{
-	ushort              read_wval;
-	read_wval = AscReadEEPWord(iop_base, addr);
-	if (read_wval != word_val) {
-		AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
-		AscWaitEEPRead();
-		AscWriteEEPDataReg(iop_base, word_val);
-		AscWaitEEPRead();
-		AscWriteEEPCmdReg(iop_base,
-						  (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr));
-		AscWaitEEPWrite();
-		AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
-		AscWaitEEPRead();
-		return (AscReadEEPWord(iop_base, addr));
-	}
-	return (read_wval);
+                   PortAddr iop_base,
+                   uchar addr,
+                   ushort word_val
+)
+)
+{
+    ushort              read_wval;
+
+    read_wval = AscReadEEPWord(iop_base, addr);
+    if (read_wval != word_val) {
+        AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
+        AscWaitEEPRead();
+        AscWriteEEPDataReg(iop_base, word_val);
+        AscWaitEEPRead();
+        AscWriteEEPCmdReg(iop_base,
+                          (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr));
+        AscWaitEEPWrite();
+        AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+        AscWaitEEPRead();
+        return (AscReadEEPWord(iop_base, addr));
+    }
+    return (read_wval);
 }
 
-ushort
+ASC_INITFUNC(
+STATIC ushort
 AscGetEEPConfig(
-				   PortAddr iop_base,
-				   ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type
+                   PortAddr iop_base,
+                   ASCEEP_CONFIG * cfg_buf, ushort bus_type
+)
 )
 {
-	ushort              wval;
-	ushort              sum;
-	ushort dosfar      *wbuf;
-	int                 cfg_beg;
-	int                 cfg_end;
-	int                 s_addr;
-	int                 isa_pnp_wsize;
-	wbuf = (ushort dosfar *) cfg_buf;
-	sum = 0;
-	isa_pnp_wsize = 0;
-	for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) {
-		wval = AscReadEEPWord(iop_base, (uchar) s_addr);
-		sum += wval;
-		*wbuf = wval;
-	}
-	if (bus_type & ASC_IS_VL) {
-		cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-		cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-	} else {
-		cfg_beg = ASC_EEP_DVC_CFG_BEG;
-		cfg_end = ASC_EEP_MAX_DVC_ADDR;
-	}
-	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
-		 s_addr++, wbuf++) {
-		wval = AscReadEEPWord(iop_base, (uchar) s_addr);
-		sum += wval;
-		*wbuf = wval;
-	}
-	*wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
-	return (sum);
+    ushort              wval;
+    ushort              sum;
+    ushort      *wbuf;
+    int                 cfg_beg;
+    int                 cfg_end;
+    int                 s_addr;
+    int                 isa_pnp_wsize;
+
+    wbuf = (ushort *) cfg_buf;
+    sum = 0;
+    isa_pnp_wsize = 0;
+    for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) {
+        wval = AscReadEEPWord(iop_base, (uchar) s_addr);
+        sum += wval;
+        *wbuf = wval;
+    }
+    if (bus_type & ASC_IS_VL) {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+    } else {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR;
+    }
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
+         s_addr++, wbuf++) {
+        wval = AscReadEEPWord(iop_base, (uchar) s_addr);
+        sum += wval;
+        *wbuf = wval;
+    }
+    *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
+    return (sum);
 }
 
-#if CC_CHK_FIX_EEP_CONTENT
-int
+ASC_INITFUNC(
+STATIC int
 AscSetEEPConfigOnce(
-					   PortAddr iop_base,
-					   ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type
+                       PortAddr iop_base,
+                       ASCEEP_CONFIG * cfg_buf, ushort bus_type
+)
 )
 {
-	int                 n_error;
-	ushort dosfar      *wbuf;
-	ushort              sum;
-	int                 s_addr;
-	int                 cfg_beg;
-	int                 cfg_end;
-	wbuf = (ushort dosfar *) cfg_buf;
-	n_error = 0;
-	sum = 0;
-	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-		sum += *wbuf;
-		if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
-			n_error++;
-		}
-	}
-	if (bus_type & ASC_IS_VL) {
-		cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-		cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-	} else {
-		cfg_beg = ASC_EEP_DVC_CFG_BEG;
-		cfg_end = ASC_EEP_MAX_DVC_ADDR;
-	}
-	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
-		 s_addr++, wbuf++) {
-		sum += *wbuf;
-		if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
-			n_error++;
-		}
-	}
-	*wbuf = sum;
-	if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) {
-		n_error++;
-	}
-	wbuf = (ushort dosfar *) cfg_buf;
-	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-		if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
-			n_error++;
-		}
-	}
-	for (s_addr = cfg_beg; s_addr <= cfg_end;
-		 s_addr++, wbuf++) {
-		if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
-			n_error++;
-		}
-	}
-	return (n_error);
+    int                 n_error;
+    ushort      *wbuf;
+    ushort              sum;
+    int                 s_addr;
+    int                 cfg_beg;
+    int                 cfg_end;
+
+    wbuf = (ushort *) cfg_buf;
+    n_error = 0;
+    sum = 0;
+    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+        sum += *wbuf;
+        if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
+            n_error++;
+        }
+    }
+    if (bus_type & ASC_IS_VL) {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+    } else {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR;
+    }
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
+         s_addr++, wbuf++) {
+        sum += *wbuf;
+        if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
+            n_error++;
+        }
+    }
+    *wbuf = sum;
+    if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) {
+        n_error++;
+    }
+    wbuf = (ushort *) cfg_buf;
+    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+        if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
+            n_error++;
+        }
+    }
+    for (s_addr = cfg_beg; s_addr <= cfg_end;
+         s_addr++, wbuf++) {
+        if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
+            n_error++;
+        }
+    }
+    return (n_error);
 }
 
-int
+ASC_INITFUNC(
+STATIC int
 AscSetEEPConfig(
-				   PortAddr iop_base,
-				   ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type
+                   PortAddr iop_base,
+                   ASCEEP_CONFIG * cfg_buf, ushort bus_type
+)
 )
 {
-	int                 retry;
-	int                 n_error;
-	retry = 0;
-	while (TRUE) {
-		if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
-										   bus_type)) == 0) {
-			break;
-		}
-		if (++retry > ASC_EEP_MAX_RETRY) {
-			break;
-		}
-	}
-	return (n_error);
+    int            retry;
+    int            n_error;
+
+    retry = 0;
+    while (TRUE) {
+        if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
+                                           bus_type)) == 0) {
+            break;
+        }
+        if (++retry > ASC_EEP_MAX_RETRY) {
+            break;
+        }
+    }
+    return (n_error);
 }
-#endif
-#endif
 
-int
+STATIC int
 AscInitPollBegin(
-					REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	PortAddr            iop_base;
-	iop_base = asc_dvc->iop_base;
-#if CC_INIT_INQ_DISPLAY
-	DvcDisplayString((uchar dosfar *) "\r\n");
-#endif
-	AscDisableInterrupt(iop_base);
-	asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY;
-	AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, 0x00);
-	asc_dvc->use_tagged_qng = 0;
-	asc_dvc->cfg->can_tagged_qng = 0;
-	asc_dvc->saved_ptr2func = (ulong) asc_dvc->isr_callback;
-	asc_dvc->isr_callback = ASC_GET_PTR2FUNC(AscInitPollIsrCallBack);
-	return (0);
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    AscDisableInterrupt(iop_base);
+    asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY;
+    AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, 0x00);
+    asc_dvc->use_tagged_qng = 0;
+    asc_dvc->cfg->can_tagged_qng = 0;
+    asc_dvc->saved_ptr2func = (ulong) asc_dvc->isr_callback;
+    asc_dvc->isr_callback = ASC_GET_PTR2FUNC(AscInitPollIsrCallBack);
+    return (0);
 }
 
-int
+STATIC int
 AscInitPollEnd(
-				  REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
 {
-	PortAddr            iop_base;
-	rint                i;
-	iop_base = asc_dvc->iop_base;
-	asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func;
-	AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
-					 asc_dvc->cfg->disc_enable);
-	AscWriteLramByte(iop_base, ASCV_USE_TAGGED_QNG_B,
-					 asc_dvc->use_tagged_qng);
-	AscWriteLramByte(iop_base, ASCV_CAN_TAGGED_QNG_B,
-					 asc_dvc->cfg->can_tagged_qng);
-	for (i = 0; i <= ASC_MAX_TID; i++) {
-		AscWriteLramByte(iop_base,
-					  (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) i),
-						 asc_dvc->max_dvc_qng[i]);
-	}
-	AscAckInterrupt(iop_base);
-	AscEnableInterrupt(iop_base);
-#if CC_INIT_INQ_DISPLAY
-	DvcDisplayString((uchar dosfar *) "\r\n");
-#endif
-	asc_dvc->init_state |= ASC_INIT_STATE_END_INQUIRY;
-	return (0);
-}
+    PortAddr            iop_base;
+    rint                i;
 
-int                 _asc_wait_slow_device_ = FALSE;
+    iop_base = asc_dvc->iop_base;
+    asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func;
+    AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+                     asc_dvc->cfg->disc_enable);
+    AscWriteLramByte(iop_base, ASCV_USE_TAGGED_QNG_B,
+                     asc_dvc->use_tagged_qng);
+    AscWriteLramByte(iop_base, ASCV_CAN_TAGGED_QNG_B,
+                     asc_dvc->cfg->can_tagged_qng);
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        AscWriteLramByte(iop_base,
+                      (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) i),
+                         asc_dvc->max_dvc_qng[i]);
+    }
+    AscAckInterrupt(iop_base);
+    AscEnableInterrupt(iop_base);
+    asc_dvc->init_state |= ASC_INIT_STATE_END_INQUIRY;
+    return (0);
+}
 
-int
+STATIC int
 AscInitPollTarget(
-					 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					 REG ASC_SCSI_REQ_Q dosfar * scsiq,
-					 REG ASC_SCSI_INQUIRY dosfar * inq,
-					 REG ASC_CAP_INFO dosfar * cap_info
-)
-{
-	uchar               tid_no, lun;
-	uchar               dvc_type;
-	ASC_SCSI_BIT_ID_TYPE tid_bits;
-	int                 dvc_found;
-	int                 support_read_cap;
-	int                 tmp_disable_init_sdtr;
-	int                 sta;
-	dvc_found = 0;
-	tmp_disable_init_sdtr = FALSE;
-	tid_bits = scsiq->r1.target_id;
-	lun = scsiq->r1.target_lun;
-	tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix);
-	if (
-		   ((asc_dvc->init_sdtr & tid_bits) != 0)
-		   && ((asc_dvc->sdtr_done & tid_bits) == 0)
-	  ) {
-		asc_dvc->init_sdtr &= ~tid_bits;
-		tmp_disable_init_sdtr = TRUE;
-	}
-	ASC_DBG(1, "AscInitPollTarget: before PollScsiInquiry\n");
-	if (
-		   PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq,
-						   sizeof (ASC_SCSI_INQUIRY)) == 1
-	  ) {
-		dvc_found = 1;
-		support_read_cap = TRUE;
-		dvc_type = inq->byte0.peri_dvc_type;
-		if (dvc_type != SCSI_TYPE_UNKNOWN) {
-			if (
-				   (dvc_type != SCSI_TYPE_DASD)
-				   && (dvc_type != SCSI_TYPE_WORM)
-				   && (dvc_type != SCSI_TYPE_CDROM)
-				   && (dvc_type != SCSI_TYPE_OPTMEM)
-			  ) {
-				asc_dvc->start_motor &= ~tid_bits;
-				support_read_cap = FALSE;
-			}
-			if (
-				   (dvc_type != SCSI_TYPE_DASD)
-				   || inq->byte1.rmb
-			  ) {
-				if (!_asc_wait_slow_device_) {
-					DvcSleepMilliSecond(3000 - ((int) tid_no * 250));
-					_asc_wait_slow_device_ = TRUE;
-				}
-			}
-#if CC_INIT_INQ_DISPLAY
-			AscDispInquiry(tid_no, lun, inq);
-#endif
-			if (lun == 0) {
-				if (
-					   (inq->byte3.rsp_data_fmt >= 2)
-					   || (inq->byte2.ansi_apr_ver >= 2)
-				  ) {
-					if (inq->byte7.CmdQue) {
-						asc_dvc->cfg->can_tagged_qng |= tid_bits;
-						if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) {
-								asc_dvc->use_tagged_qng |= tid_bits;
-								asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no];
-						}
-					}
-					if (!inq->byte7.Sync) {
-						asc_dvc->init_sdtr &= ~tid_bits;
-						asc_dvc->sdtr_done &= ~tid_bits;
-					} else if (tmp_disable_init_sdtr) {
-						asc_dvc->init_sdtr |= tid_bits;
-					}
-				} else {
-					asc_dvc->init_sdtr &= ~tid_bits;
-					asc_dvc->sdtr_done &= ~tid_bits;
-					asc_dvc->use_tagged_qng &= ~tid_bits;
-				}
-			}
-			if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
-				if (!(asc_dvc->init_sdtr & tid_bits)) {
-					if (
-						   (dvc_type == SCSI_TYPE_CDROM)
-						   && (AscCompareString((uchar *) inq->vendor_id, (uchar *) "HP ", 3) == 0)
-					  ) {
-						asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
-					}
-					asc_dvc->pci_fix_asyn_xfer |= tid_bits;
-#if CC_DISABLE_ASYN_FIX_WANGTEK_TAPE
-					if (
-						   (dvc_type == SCSI_TYPE_SASD)
-						   && (AscCompareString((uchar *) inq->vendor_id, (uchar *) "WANGTEK ", 8) == 0)
-					  ) {
-						asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-					}
-#endif
-					if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
-						AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
-											 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
-					}
-				}
-			}
-			sta = 1;
-			ASC_DBG(1, "AscInitPollTarget: before InitTestUnitReady\n");
-			sta = InitTestUnitReady(asc_dvc, scsiq);
-			if (sta == 1) {
-				if ((cap_info != 0L) && support_read_cap) {
-					ASC_DBG(1,
-						"AscInitPollTarget: before PollScsiReadCapacity\n");
-					if (PollScsiReadCapacity(asc_dvc, scsiq,
-											 cap_info) != 1) {
-						cap_info->lba = 0L;
-						cap_info->blk_size = 0x0000;
-					} else {
-					}
-				}
-			}
-		} else {
-			asc_dvc->start_motor &= ~tid_bits;
-		}
-	}
-	ASC_DBG1(1, "AscInitPollTarget: dvc_found %d\n", dvc_found);
-	return (dvc_found);
+                     REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                     REG ASC_SCSI_REQ_Q * scsiq,
+                     REG ASC_SCSI_INQUIRY * inq,
+                     REG ASC_CAP_INFO * cap_info
+)
+{
+    uchar               tid_no, lun;
+    uchar               dvc_type;
+    ASC_SCSI_BIT_ID_TYPE tid_bits;
+    int                 dvc_found;
+    int                 support_read_cap;
+    int                 tmp_disable_init_sdtr;
+    int                 sta;
+
+    dvc_found = 0;
+    tmp_disable_init_sdtr = FALSE;
+    tid_bits = scsiq->r1.target_id;
+    lun = scsiq->r1.target_lun;
+    tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix);
+    if (((asc_dvc->init_sdtr & tid_bits) != 0) &&
+        ((asc_dvc->sdtr_done & tid_bits) == 0)) {
+        asc_dvc->init_sdtr &= ~tid_bits;
+        tmp_disable_init_sdtr = TRUE;
+    }
+    ASC_DBG(1, "AscInitPollTarget: before PollScsiInquiry\n");
+    if (PollScsiInquiry(asc_dvc, scsiq, (uchar *) inq,
+        sizeof (ASC_SCSI_INQUIRY)) == 1) {
+        dvc_found = 1;
+        dvc_type = inq->byte0.peri_dvc_type;
+        if (dvc_type != SCSI_TYPE_UNKNOWN) {
+            support_read_cap = TRUE;
+            if ((dvc_type != SCSI_TYPE_DASD)
+                && (dvc_type != SCSI_TYPE_WORM)
+                && (dvc_type != SCSI_TYPE_CDROM)
+                && (dvc_type != SCSI_TYPE_OPTMEM)) {
+                asc_dvc->start_motor &= ~tid_bits;
+                support_read_cap = FALSE;
+            }
+            if (lun == 0) {
+                if ((inq->byte3.rsp_data_fmt >= 2) ||
+                    (inq->byte2.ansi_apr_ver >= 2)) {
+                    if (inq->byte7.CmdQue) {
+                        asc_dvc->cfg->can_tagged_qng |= tid_bits;
+                        if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) {
+                                asc_dvc->use_tagged_qng |= tid_bits;
+                                asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no];
+                        }
+                    }
+                    if (!inq->byte7.Sync) {
+                        asc_dvc->init_sdtr &= ~tid_bits;
+                        asc_dvc->sdtr_done &= ~tid_bits;
+                    } else if (tmp_disable_init_sdtr) {
+                        asc_dvc->init_sdtr |= tid_bits;
+                    }
+                } else {
+                    asc_dvc->init_sdtr &= ~tid_bits;
+                    asc_dvc->sdtr_done &= ~tid_bits;
+                    asc_dvc->use_tagged_qng &= ~tid_bits;
+                }
+            }
+            if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
+                if (!(asc_dvc->init_sdtr & tid_bits)) {
+                    if ((dvc_type == SCSI_TYPE_CDROM) &&
+                        (AscCompareString((uchar *) inq->vendor_id,
+                            (uchar *) "HP ", 3) == 0)) {
+                        asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
+                    }
+                    asc_dvc->pci_fix_asyn_xfer |= tid_bits;
+                    if ((dvc_type == SCSI_TYPE_PROC) || (dvc_type == SCSI_TYPE_SCANNER)) {
+                        asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+                    }
+                    if ((dvc_type == SCSI_TYPE_SASD) &&
+                        (AscCompareString((uchar *) inq->vendor_id,
+                            (uchar *) "TANDBERG", 8) == 0) &&
+                        (AscCompareString((uchar *) inq->product_id,
+                         (uchar *) " TDC 36", 7) == 0)) {
+                        asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+                    }
+                    if ((dvc_type == SCSI_TYPE_SASD) &&
+                        (AscCompareString((uchar *) inq->vendor_id,
+                         (uchar *) "WANGTEK ", 8) == 0)) {
+                        asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+                    }
+
+                    if ((dvc_type == SCSI_TYPE_CDROM) &&
+                       (AscCompareString((uchar *)inq->vendor_id,
+                        (uchar *)"NEC     ", 8) == 0) &&
+                        (AscCompareString((uchar *)inq->product_id,
+                         (uchar *)"CD-ROM DRIVE    ", 16) == 0)) {
+                        asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ;
+                    }
+                    if ((dvc_type == SCSI_TYPE_CDROM) &&
+                        (AscCompareString((uchar *) inq->vendor_id,
+                         (uchar *) "YAMAHA", 6) == 0)  &&
+                        (AscCompareString((uchar *) inq->product_id,
+                         (uchar *) "CDR400", 6) == 0))
+                    {
+                        asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ;
+                    }
+ 
+                    if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
+                        AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
+                                                ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+                    }
+                }
+            }
+            sta = 1;
+            ASC_DBG(1, "AscInitPollTarget: before InitTestUnitReady\n");
+            sta = InitTestUnitReady(asc_dvc, scsiq);
+            if (sta == 1) {
+                if ((cap_info != 0L) && support_read_cap) {
+                    ASC_DBG(1,
+                        "AscInitPollTarget: before PollScsiReadCapacity\n");
+                    if (PollScsiReadCapacity(asc_dvc, scsiq,
+                                             cap_info) != 1) {
+                        cap_info->lba = 0L;
+                        cap_info->blk_size = 0x0000;
+                    } else {
+                    }
+                }
+            }
+        } else {
+            asc_dvc->start_motor &= ~tid_bits;
+        }
+    } else if (tmp_disable_init_sdtr) {
+        asc_dvc->init_sdtr |= tid_bits;
+    }
+    ASC_DBG1(1, "AscInitPollTarget: dvc_found %d\n", dvc_found);
+    return (dvc_found);
 }
 
-int
+STATIC int
 PollQueueDone(
-				 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				 REG ASC_SCSI_REQ_Q dosfar * scsiq,
-				 int timeout_sec
-)
-{
-	int                 status;
-	int                 retry = 0;
-
-	ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec);
-	do {
-		ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
-		if ((status = AscExeScsiQueue(asc_dvc,
-				(ASC_SCSI_Q dosfar *) scsiq)) == 1) {
-			ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
-			if ((status = AscPollQDone(asc_dvc, scsiq,
-									   timeout_sec)) != 1) {
-				ASC_DBG1(1, "PollQueueDone: status %x\n", status);
-				if (status == 0x80) {
-					if (retry++ > ASC_MAX_INIT_BUSY_RETRY) {
-						break;
-					}
-					scsiq->r3.done_stat = 0;
-					scsiq->r3.host_stat = 0;
-					scsiq->r3.scsi_stat = 0;
-					scsiq->r3.scsi_msg = 0;
-					DvcSleepMilliSecond(2000);
-					continue;
-				}
-				scsiq->r3.done_stat = 0;
-				scsiq->r3.host_stat = 0;
-				scsiq->r3.scsi_stat = 0;
-				scsiq->r3.scsi_msg = 0;
-				ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n");
-				AscAbortSRB(asc_dvc, (ulong) scsiq);
-			}
-			ASC_DBG1(1, "PollQueueDone: status %x\n", status);
-			ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
-			return (scsiq->r3.done_stat);
-		}
-		ASC_DBG1(1, "PollQueueDone: status %x\n", status);
-		DvcSleepMilliSecond(5);
-	} while (((status == 0) || (status == 0x80)) &&
-			  retry++ < ASC_MAX_INIT_BUSY_RETRY);
-	ASC_DBG1(1, "PollQueueDone: status %x\n", status);
-	ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
-	return (scsiq->r3.done_stat = QD_WITH_ERROR);
+                 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                 REG ASC_SCSI_REQ_Q * scsiq,
+                 int timeout_sec
+)
+{
+    int                 status;
+    int                 retry = 0;
+
+    ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec);
+    do {
+        ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
+        if ((status = AscExeScsiQueue(asc_dvc,
+                (ASC_SCSI_Q *) scsiq)) == 1) {
+            ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
+            if ((status = AscPollQDone(asc_dvc, scsiq,
+                                       timeout_sec)) != 1) {
+                ASC_DBG1(1, "PollQueueDone: status %x\n", status);
+                if (status == 0x80) {
+                    if (retry++ > ASC_MAX_INIT_BUSY_RETRY) {
+                        break;
+                    }
+                    scsiq->r3.done_stat = 0;
+                    scsiq->r3.host_stat = 0;
+                    scsiq->r3.scsi_stat = 0;
+                    scsiq->r3.scsi_msg = 0;
+                    DvcSleepMilliSecond(1000);
+                    continue;
+                }
+                scsiq->r3.done_stat = 0;
+                scsiq->r3.host_stat = 0;
+                scsiq->r3.scsi_stat = 0;
+                scsiq->r3.scsi_msg = 0;
+                ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n");
+                AscAbortSRB(asc_dvc, (ulong) scsiq);
+            }
+            ASC_DBG1(1, "PollQueueDone: status %x\n", status);
+            ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
+            return (scsiq->r3.done_stat);
+        }
+        ASC_DBG1(1, "PollQueueDone: status %x\n", status);
+        DvcSleepMilliSecond(5);
+    } while (((status == 0) || (status == 0x80)) &&
+              retry++ < ASC_MAX_INIT_BUSY_RETRY);
+    ASC_DBG1(1, "PollQueueDone: status %x\n", status);
+    ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
+    return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
 
-int
+STATIC int
 PollScsiInquiry(
-				   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				   REG ASC_SCSI_REQ_Q dosfar * scsiq,
-				   uchar dosfar * buf,
-				   int buf_len
+                   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                   REG ASC_SCSI_REQ_Q * scsiq,
+                   uchar * buf,
+                   int buf_len
 )
 {
-	if (AscScsiInquiry(asc_dvc, scsiq, buf, buf_len) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 4));
+    if (AscScsiInquiry(asc_dvc, scsiq, buf, buf_len) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 4));
 }
 
-int
+STATIC int
 PollScsiStartUnit(
-					 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					 REG ASC_SCSI_REQ_Q dosfar * scsiq
+                     REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                     REG ASC_SCSI_REQ_Q * scsiq
 )
 {
-	if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40));
+    if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 40));
 }
 
-int
+STATIC int
 PollScsiReadCapacity(
-						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						REG ASC_SCSI_REQ_Q dosfar * scsiq,
-						REG ASC_CAP_INFO dosfar * cap_info
-)
-{
-	ASC_CAP_INFO        scsi_cap_info;
-	int                 status;
-	if (AscScsiReadCapacity(asc_dvc, scsiq,
-							(uchar dosfar *) & scsi_cap_info) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 8);
-	if (status == 1) {
-#if CC_LITTLE_ENDIAN_HOST
-		cap_info->lba = (ulong) * swapfarbuf4((uchar dosfar *) & scsi_cap_info.lba);
-		cap_info->blk_size = (ulong) * swapfarbuf4((uchar dosfar *) & scsi_cap_info.blk_size);
-#else
-		cap_info->lba = scsi_cap_info.lba;
-		cap_info->blk_size = scsi_cap_info.blk_size;
-#endif
-		return (scsiq->r3.done_stat);
-	}
-	return (scsiq->r3.done_stat = QD_WITH_ERROR);
+                        REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                        REG ASC_SCSI_REQ_Q * scsiq,
+                        REG ASC_CAP_INFO * cap_info
+)
+{
+    ASC_CAP_INFO        scsi_cap_info;
+    int                 status;
+
+    if (AscScsiReadCapacity(asc_dvc, scsiq,
+                            (uchar *) & scsi_cap_info) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 8);
+    if (status == 1) {
+        cap_info->lba = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.lba);
+        cap_info->blk_size = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.blk_size);
+        return (scsiq->r3.done_stat);
+    }
+    return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
 
-ulong dosfar       *
+STATIC ulong *
 swapfarbuf4(
-			   uchar dosfar * buf
+    uchar *buf
 )
 {
-	uchar               tmp;
+    uchar      tmp;
 
-	tmp = buf[3];
-	buf[3] = buf[0];
-	buf[0] = tmp;
+    tmp = buf[3];
+    buf[3] = buf[0];
+    buf[0] = tmp;
 
-	tmp = buf[1];
-	buf[1] = buf[2];
-	buf[2] = tmp;
+    tmp = buf[1];
+    buf[1] = buf[2];
+    buf[2] = tmp;
 
-	return ((ulong dosfar *) buf);
+    return ((ulong *) buf);
 }
 
-int
+STATIC int
 PollScsiTestUnitReady(
-						 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						 REG ASC_SCSI_REQ_Q dosfar * scsiq
+                         REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                         REG ASC_SCSI_REQ_Q * scsiq
 )
 {
-	if (AscScsiTestUnitReady(asc_dvc, scsiq) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 12));
+    if (AscScsiTestUnitReady(asc_dvc, scsiq) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 12));
 }
 
-int
+STATIC int
 InitTestUnitReady(
-					 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					 REG ASC_SCSI_REQ_Q dosfar * scsiq
+                     REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                     REG ASC_SCSI_REQ_Q * scsiq
 )
 {
-	ASC_SCSI_BIT_ID_TYPE tid_bits;
-	int                 retry;
-	ASC_REQ_SENSE dosfar *sen;
-	retry = 0;
-	tid_bits = scsiq->r1.target_id;
-	while (retry++ < 4) {
-		PollScsiTestUnitReady(asc_dvc, scsiq);
-		if (scsiq->r3.done_stat == 0x01) {
-			return (1);
-		} else if (scsiq->r3.done_stat == QD_WITH_ERROR) {
-			DvcSleepMilliSecond(200);
-			sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr;
-			if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) &&
-				((sen->err_code & 0x70) != 0)) {
-				if (sen->sense_key == SCSI_SENKEY_NOT_READY) {
-					if (asc_dvc->start_motor & tid_bits) {
-						if (PollScsiStartUnit(asc_dvc, scsiq) == 1) {
-							retry = 0;
-							continue;
-						} else {
-							asc_dvc->start_motor &= ~tid_bits;
-							break;
-						}
-					} else {
-						DvcSleepMilliSecond(5000);
-					}
-				} else if (sen->sense_key == SCSI_SENKEY_ATTENTION) {
-					DvcSleepMilliSecond( ( ulong )( 500L*retry ) ) ;
-				} else {
-					DvcSleepMilliSecond( 500 ) ;
-					break;
-				}
-			} else {
-				break;
-			}
-		} else if (scsiq->r3.done_stat == QD_ABORTED_BY_HOST) {
-			break;
-		} else {
-			break;
-		}
-	}
-	return (0);
+    ASC_SCSI_BIT_ID_TYPE tid_bits;
+    int                 retry;
+    ASC_REQ_SENSE *sen;
+
+    retry = 0;
+    tid_bits = scsiq->r1.target_id;
+    while (retry++ < 4) {
+        PollScsiTestUnitReady(asc_dvc, scsiq);
+        if (scsiq->r3.done_stat == 0x01) {
+            return (1);
+        } else if (scsiq->r3.done_stat == QD_WITH_ERROR) {
+            sen = (ASC_REQ_SENSE *) scsiq->sense_ptr;
+            if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) &&
+                ((sen->err_code & 0x70) != 0)) {
+                if (sen->sense_key == SCSI_SENKEY_NOT_READY) {
+                    if (sen->asc == SCSI_ASC_NOMEDIA)
+                    {
+                        break;
+                    }
+                    if (asc_dvc->start_motor & tid_bits) {
+                        if (PollScsiStartUnit(asc_dvc, scsiq) == 1) {
+                            DvcSleepMilliSecond(250);
+                            continue;
+                        } else {
+                            asc_dvc->start_motor &= ~tid_bits;
+                            break;
+                        }
+                    } else {
+                        DvcSleepMilliSecond(250);
+                    }
+                } else if (sen->sense_key == SCSI_SENKEY_ATTENTION) {
+                    DvcSleepMilliSecond(250);
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        } else if (scsiq->r3.done_stat == QD_ABORTED_BY_HOST) {
+            break;
+        } else {
+            break;
+        }
+    }
+    return (0);
 }
 
-int
+STATIC int
 AscPollQDone(
-				REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				REG ASC_SCSI_REQ_Q dosfar * scsiq,
-				int timeout_sec
-)
-{
-	int                 loop, loop_end;
-	int                 sta;
-	PortAddr            iop_base;
-	iop_base = asc_dvc->iop_base;
-	loop = 0;
-	loop_end = timeout_sec * 100;
-	sta = 1;
-	while (TRUE) {
-		if (asc_dvc->err_code != 0) {
-			scsiq->r3.done_stat = QD_WITH_ERROR;
-			ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code);
-			sta = ERR;
-			break;
-		}
-		if (scsiq->r3.done_stat != QD_IN_PROGRESS) {
-			if ((scsiq->r3.done_stat == QD_WITH_ERROR) &&
-				(scsiq->r3.scsi_stat == SS_TARGET_BUSY)) {
-				sta = 0x80;
-			}
-			break;
-		}
-		DvcSleepMilliSecond(10);
-		if (loop++ > loop_end) {
-			ASC_DBG(1, "AscPollQDone: loop finished\n");
-			sta = 0;
-			break;
-		}
-		if (AscIsChipHalted(iop_base)) {
-			ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n");
-#if !CC_ASCISR_CHECK_INT_PENDING
-			AscAckInterrupt(iop_base);
-#endif
-			AscISR(asc_dvc);
-			loop = 0;
-		} else {
-			if (AscIsIntPending(iop_base)) {
-				ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n");
-#if !CC_ASCISR_CHECK_INT_PENDING
-				AscAckInterrupt(iop_base);
-#endif
-				AscISR(asc_dvc);
-			}
-		}
-	}
-	return (sta);
+                REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                REG ASC_SCSI_REQ_Q * scsiq,
+                int timeout_sec
+)
+{
+    int                 loop, loop_end;
+    int                 sta;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    loop = 0;
+    loop_end = timeout_sec * 100;
+    sta = 1;
+    while (TRUE) {
+        if (asc_dvc->err_code != 0) {
+            scsiq->r3.done_stat = QD_WITH_ERROR;
+            ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code);
+            sta = ERR;
+            break;
+        }
+        if (scsiq->r3.done_stat != QD_IN_PROGRESS) {
+            if ((scsiq->r3.done_stat == QD_WITH_ERROR) &&
+                (scsiq->r3.scsi_stat == SS_TARGET_BUSY)) {
+                sta = 0x80;
+            }
+            break;
+        }
+        DvcSleepMilliSecond(10);
+        if (loop++ > loop_end) {
+            ASC_DBG(1, "AscPollQDone: loop finished\n");
+            sta = 0;
+            break;
+        }
+        if (AscIsChipHalted(iop_base)) {
+            ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n");
+            AscISR(asc_dvc);
+            loop = 0;
+        } else {
+            if (AscIsIntPending(iop_base)) {
+                ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n");
+                AscISR(asc_dvc);
+            }
+        }
+    }
+    return (sta);
 }
 
-int
+STATIC int
 AscCompareString(
-					ruchar * str1,
-					ruchar * str2,
-					int len
-)
-{
-	int                 i;
-	int                 diff;
-	for (i = 0; i < len; i++) {
-		diff = (int) (str1[i] - str2[i]);
-		if (diff != 0)
-			return (diff);
-	}
-	return (0);
+                    ruchar * str1,
+                    ruchar * str2,
+                    int len
+)
+{
+    int                 i;
+    int                 diff;
+
+    for (i = 0; i < len; i++) {
+        diff = (int) (str1[i] - str2[i]);
+        if (diff != 0)
+            return (diff);
+    }
+    return (0);
 }
 
-uchar
+STATIC uchar
 AscReadLramByte(
-				   PortAddr iop_base,
-				   ushort addr
+                   PortAddr iop_base,
+                   ushort addr
 )
 {
-	uchar               byte_data;
-	ushort              word_data;
-	if (isodd_word(addr)) {
-		AscSetChipLramAddr(iop_base, addr - 1);
-		word_data = AscGetChipLramData(iop_base);
-		byte_data = (uchar) ((word_data >> 8) & 0xFF);
-	} else {
-		AscSetChipLramAddr(iop_base, addr);
-		word_data = AscGetChipLramData(iop_base);
-		byte_data = (uchar) (word_data & 0xFF);
-	}
-	return (byte_data);
+    uchar               byte_data;
+    ushort              word_data;
+
+    if (isodd_word(addr)) {
+        AscSetChipLramAddr(iop_base, addr - 1);
+        word_data = AscGetChipLramData(iop_base);
+        byte_data = (uchar) ((word_data >> 8) & 0xFF);
+    } else {
+        AscSetChipLramAddr(iop_base, addr);
+        word_data = AscGetChipLramData(iop_base);
+        byte_data = (uchar) (word_data & 0xFF);
+    }
+    return (byte_data);
 }
 
-ushort
+STATIC ushort
 AscReadLramWord(
-				   PortAddr iop_base,
-				   ushort addr
+                   PortAddr iop_base,
+                   ushort addr
 )
 {
-	ushort              word_data;
-	AscSetChipLramAddr(iop_base, addr);
-	word_data = AscGetChipLramData(iop_base);
-	return (word_data);
+    ushort              word_data;
+
+    AscSetChipLramAddr(iop_base, addr);
+    word_data = AscGetChipLramData(iop_base);
+    return (word_data);
 }
 
-ulong
+STATIC ulong
 AscReadLramDWord(
-					PortAddr iop_base,
-					ushort addr
+                    PortAddr iop_base,
+                    ushort addr
 )
 {
-	ushort              val_low, val_high;
-	ulong               dword_data;
-	AscSetChipLramAddr(iop_base, addr);
-	val_low = AscGetChipLramData(iop_base);
-	val_high = AscGetChipLramData(iop_base);
-	dword_data = ((ulong) val_high << 16) | (ulong) val_low;
-	return (dword_data);
+    ushort              val_low, val_high;
+    ulong               dword_data;
+
+    AscSetChipLramAddr(iop_base, addr);
+    val_low = AscGetChipLramData(iop_base);
+    val_high = AscGetChipLramData(iop_base);
+    dword_data = ((ulong) val_high << 16) | (ulong) val_low;
+    return (dword_data);
 }
 
-void
+STATIC void
 AscWriteLramWord(
-					PortAddr iop_base,
-					ushort addr,
-					ushort word_val
+                    PortAddr iop_base,
+                    ushort addr,
+                    ushort word_val
 )
 {
-	AscSetChipLramAddr(iop_base, addr);
-	AscSetChipLramData(iop_base, word_val);
-	return;
+    AscSetChipLramAddr(iop_base, addr);
+    AscSetChipLramData(iop_base, word_val);
+    return;
 }
 
-void
+STATIC void
 AscWriteLramDWord(
-					 PortAddr iop_base,
-					 ushort addr,
-					 ulong dword_val
+                     PortAddr iop_base,
+                     ushort addr,
+                     ulong dword_val
 )
 {
-	ushort              word_val;
-	AscSetChipLramAddr(iop_base, addr);
-	word_val = (ushort) dword_val;
-	AscSetChipLramData(iop_base, word_val);
-	word_val = (ushort) (dword_val >> 16);
-	AscSetChipLramData(iop_base, word_val);
-	return;
+    ushort              word_val;
+
+    AscSetChipLramAddr(iop_base, addr);
+    word_val = (ushort) dword_val;
+    AscSetChipLramData(iop_base, word_val);
+    word_val = (ushort) (dword_val >> 16);
+    AscSetChipLramData(iop_base, word_val);
+    return;
 }
 
-void
+STATIC void
 AscWriteLramByte(
-					PortAddr iop_base,
-					ushort addr,
-					uchar byte_val
-)
-{
-	ushort              word_data;
-	if (isodd_word(addr)) {
-		addr--;
-		word_data = AscReadLramWord(iop_base, addr);
-		word_data &= 0x00FF;
-		word_data |= (((ushort) byte_val << 8) & 0xFF00);
-	} else {
-		word_data = AscReadLramWord(iop_base, addr);
-		word_data &= 0xFF00;
-		word_data |= ((ushort) byte_val & 0x00FF);
-	}
-	AscWriteLramWord(iop_base, addr, word_data);
-	return;
+                    PortAddr iop_base,
+                    ushort addr,
+                    uchar byte_val
+)
+{
+    ushort              word_data;
+
+    if (isodd_word(addr)) {
+        addr--;
+        word_data = AscReadLramWord(iop_base, addr);
+        word_data &= 0x00FF;
+        word_data |= (((ushort) byte_val << 8) & 0xFF00);
+    } else {
+        word_data = AscReadLramWord(iop_base, addr);
+        word_data &= 0xFF00;
+        word_data |= ((ushort) byte_val & 0x00FF);
+    }
+    AscWriteLramWord(iop_base, addr, word_data);
+    return;
 }
 
-
-
-
-void
+STATIC void
 AscMemWordCopyToLram(
-						PortAddr iop_base,
-						ushort s_addr,
-						ushort dosfar * s_buffer,
-						int words
+                        PortAddr iop_base,
+                        ushort s_addr,
+                        ushort * s_buffer,
+                        int words
 )
 {
-	AscSetChipLramAddr(iop_base, s_addr);
-	DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words);
-	return;
+    AscSetChipLramAddr(iop_base, s_addr);
+    DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words);
+    return;
 }
 
-void
+STATIC void
 AscMemDWordCopyToLram(
-						 PortAddr iop_base,
-						 ushort s_addr,
-						 ulong dosfar * s_buffer,
-						 int dwords
+                         PortAddr iop_base,
+                         ushort s_addr,
+                         ulong * s_buffer,
+                         int dwords
 )
 {
-	AscSetChipLramAddr(iop_base, s_addr);
-	DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords);
-	return;
+    AscSetChipLramAddr(iop_base, s_addr);
+    DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords);
+    return;
 }
 
-void
+STATIC void
 AscMemWordCopyFromLram(
-						  PortAddr iop_base,
-						  ushort s_addr,
-						  ushort dosfar * d_buffer,
-						  int words
+                          PortAddr iop_base,
+                          ushort s_addr,
+                          ushort * d_buffer,
+                          int words
 )
 {
-	AscSetChipLramAddr(iop_base, s_addr);
-	DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words);
-	return;
+    AscSetChipLramAddr(iop_base, s_addr);
+    DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words);
+    return;
 }
 
-ulong
+STATIC ulong
 AscMemSumLramWord(
-					 PortAddr iop_base,
-					 ushort s_addr,
-					 rint words
+                     PortAddr iop_base,
+                     ushort s_addr,
+                     rint words
 )
 {
-	ulong               sum;
-	int                 i;
-	sum = 0L;
-	for (i = 0; i < words; i++, s_addr += 2) {
-		sum += AscReadLramWord(iop_base, s_addr);
-	}
-	return (sum);
+    ulong               sum;
+    int                 i;
+
+    sum = 0L;
+    for (i = 0; i < words; i++, s_addr += 2) {
+        sum += AscReadLramWord(iop_base, s_addr);
+    }
+    return (sum);
 }
 
-void
+STATIC void
 AscMemWordSetLram(
-					 PortAddr iop_base,
-					 ushort s_addr,
-					 ushort set_wval,
-					 rint words
+                     PortAddr iop_base,
+                     ushort s_addr,
+                     ushort set_wval,
+                     rint words
 )
 {
-	rint                i;
-	AscSetChipLramAddr(iop_base, s_addr);
-	for (i = 0; i < words; i++) {
-		AscSetChipLramData(iop_base, set_wval);
-	}
-	return;
+    rint             i;
+
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < words; i++) {
+        AscSetChipLramData(iop_base, set_wval);
+    }
+    return;
 }
 
 
-int
+STATIC int
 AscScsiInquiry(
-				  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-				  REG ASC_SCSI_REQ_Q dosfar * scsiq,
-				  uchar dosfar * buf,
-				  int buf_len
-)
-{
-	if (AscScsiSetupCmdQ(asc_dvc, scsiq, buf,
-						 (ulong) buf_len) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	scsiq->cdb[0] = (uchar) SCSICMD_Inquiry;
-	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
-	scsiq->cdb[2] = 0;
-	scsiq->cdb[3] = 0;
-	scsiq->cdb[4] = buf_len;
-	scsiq->cdb[5] = 0;
-	scsiq->r2.cdb_len = 6;
-	return (0);
+                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                  REG ASC_SCSI_REQ_Q * scsiq,
+                  uchar * buf,
+                  int buf_len
+)
+{
+    if (AscScsiSetupCmdQ(asc_dvc, scsiq, buf,
+                         (ulong) buf_len) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    scsiq->cdb[0] = (uchar) SCSICMD_Inquiry;
+    scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+    scsiq->cdb[2] = 0;
+    scsiq->cdb[3] = 0;
+    scsiq->cdb[4] = buf_len;
+    scsiq->cdb[5] = 0;
+    scsiq->r2.cdb_len = 6;
+    return (0);
 }
 
-int
+STATIC int
 AscScsiReadCapacity(
-					   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-					   REG ASC_SCSI_REQ_Q dosfar * scsiq,
-					   uchar dosfar * info
-)
-{
-	if (AscScsiSetupCmdQ(asc_dvc, scsiq, info, 8L) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	scsiq->cdb[0] = (uchar) SCSICMD_ReadCapacity;
-	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
-	scsiq->cdb[2] = 0;
-	scsiq->cdb[3] = 0;
-	scsiq->cdb[4] = 0;
-	scsiq->cdb[5] = 0;
-	scsiq->cdb[6] = 0;
-	scsiq->cdb[7] = 0;
-	scsiq->cdb[8] = 0;
-	scsiq->cdb[9] = 0;
-	scsiq->r2.cdb_len = 10;
-	return (0);
+                       REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                       REG ASC_SCSI_REQ_Q * scsiq,
+                       uchar * info
+)
+{
+    if (AscScsiSetupCmdQ(asc_dvc, scsiq, info, 8L) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    scsiq->cdb[0] = (uchar) SCSICMD_ReadCapacity;
+    scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+    scsiq->cdb[2] = 0;
+    scsiq->cdb[3] = 0;
+    scsiq->cdb[4] = 0;
+    scsiq->cdb[5] = 0;
+    scsiq->cdb[6] = 0;
+    scsiq->cdb[7] = 0;
+    scsiq->cdb[8] = 0;
+    scsiq->cdb[9] = 0;
+    scsiq->r2.cdb_len = 10;
+    return (0);
 }
 
-int
+STATIC int
 AscScsiTestUnitReady(
-						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						REG ASC_SCSI_REQ_Q dosfar * scsiq
+                        REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                        REG ASC_SCSI_REQ_Q * scsiq
 )
 {
-	if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR,
-						 (ulong) 0L) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA;
-	scsiq->cdb[0] = (uchar) SCSICMD_TestUnitReady;
-	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
-	scsiq->cdb[2] = 0;
-	scsiq->cdb[3] = 0;
-	scsiq->cdb[4] = 0;
-	scsiq->cdb[5] = 0;
-	scsiq->r2.cdb_len = 6;
-	return (0);
+    if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR,
+                         (ulong) 0L) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA;
+    scsiq->cdb[0] = (uchar) SCSICMD_TestUnitReady;
+    scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+    scsiq->cdb[2] = 0;
+    scsiq->cdb[3] = 0;
+    scsiq->cdb[4] = 0;
+    scsiq->cdb[5] = 0;
+    scsiq->r2.cdb_len = 6;
+    return (0);
 }
 
-int
+STATIC int
 AscScsiStartStopUnit(
-						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-						REG ASC_SCSI_REQ_Q dosfar * scsiq,
-						uchar op_mode
-)
-{
-	if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, (ulong) 0L) == ERR) {
-		return (scsiq->r3.done_stat = QD_WITH_ERROR);
-	}
-	scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA;
-	scsiq->cdb[0] = (uchar) SCSICMD_StartStopUnit;
-	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
-	scsiq->cdb[2] = 0;
-	scsiq->cdb[3] = 0;
-	scsiq->cdb[4] = op_mode;
-	scsiq->cdb[5] = 0;
-	scsiq->r2.cdb_len = 6;
-	return (0);
+                        REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                        REG ASC_SCSI_REQ_Q * scsiq,
+                        uchar op_mode
+)
+{
+    if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, (ulong) 0L) == ERR) {
+        return (scsiq->r3.done_stat = QD_WITH_ERROR);
+    }
+    scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA;
+    scsiq->cdb[0] = (uchar) SCSICMD_StartStopUnit;
+    scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+    scsiq->cdb[2] = 0;
+    scsiq->cdb[3] = 0;
+    scsiq->cdb[4] = op_mode;
+    scsiq->cdb[5] = 0;
+    scsiq->r2.cdb_len = 6;
+    return (0);
+}
+
+
+/*
+ * --- Adv Library Functions
+ */
+
+/* a_qswap.h */
+STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = {
+  0x9C,  0xF0,  0x80,  0x01,  0x00,  0xF0,  0x40,  0x0A,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x72,  0x01,  0xD2,  0x11,  0x00,  0x00,  0x70,  0x01,
+  0x30,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x88,  0x0F,  0x22,  0x03,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x48,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x78,  0x56,  0x34,  0x12,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x04,  0xF7,  0x70,  0x01,  0x0C,  0x1C,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF2,  0xD2,  0x0A,
+  0x04,  0xF7,  0x70,  0x01,  0x06,  0xF7,  0x02,  0x00,  0x3E,  0x57,  0x3C,  0x56,  0x0C,  0x1C,  0x00,  0xFC,
+  0xA6,  0x00,  0x01,  0x58,  0xAA,  0x13,  0x20,  0xF0,  0x9A,  0x03,  0x06,  0xEC,  0xB9,  0x00,  0x0E,  0x47,
+  0x03,  0xE6,  0x10,  0x00,  0xCE,  0x45,  0x02,  0x13,  0x3E,  0x57,  0x06,  0xEA,  0xB9,  0x00,  0x47,  0x4B,
+  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x01,  0x48,  0x4E,  0x12,  0x03,  0xF6,  0xC0,  0x00,
+  0x00,  0xF2,  0x64,  0x0A,  0x41,  0x58,  0x03,  0xF6,  0xD0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x49,  0x44,
+  0x59,  0xF0,  0x0A,  0x02,  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x44,  0x58,  0x00,  0xF2,
+  0xDE,  0x0D,  0x02,  0xCC,  0x4A,  0xE4,  0x01,  0x00,  0x55,  0xF0,  0x08,  0x03,  0x45,  0xF4,  0x02,  0x00,
+  0x83,  0x5A,  0x04,  0xCC,  0x01,  0x4A,  0x12,  0x12,  0x00,  0xF2,  0xDE,  0x0D,  0x00,  0xCD,  0x48,  0xE4,
+  0x01,  0x00,  0xE9,  0x13,  0x00,  0xF2,  0xC2,  0x0F,  0xFA,  0x10,  0x0E,  0x47,  0x03,  0xE6,  0x10,  0x00,
+  0xCE,  0x45,  0x02,  0x13,  0x3E,  0x57,  0xCE,  0x47,  0x97,  0x13,  0x04,  0xEC,  0xB4,  0x00,  0x00,  0xF2,
+  0xDE,  0x0D,  0x00,  0xCD,  0x48,  0xE4,  0x00,  0x00,  0x12,  0x12,  0x3E,  0x57,  0x06,  0xCC,  0x45,  0xF4,
+  0x02,  0x00,  0x83,  0x5A,  0x00,  0xCC,  0x00,  0xEA,  0xB4,  0x00,  0x92,  0x10,  0x00,  0xF0,  0x8C,  0x01,
+  0x43,  0xF0,  0x5C,  0x02,  0x44,  0xF0,  0x60,  0x02,  0x45,  0xF0,  0x64,  0x02,  0x46,  0xF0,  0x68,  0x02,
+  0x47,  0xF0,  0x6E,  0x02,  0x48,  0xF0,  0x9E,  0x02,  0xB9,  0x54,  0x62,  0x10,  0x00,  0x1C,  0x5A,  0x10,
+  0x02,  0x1C,  0x56,  0x10,  0x1E,  0x1C,  0x52,  0x10,  0x00,  0xF2,  0x1A,  0x11,  0x50,  0x10,  0x06,  0xFC,
+  0xA8,  0x00,  0x03,  0xF6,  0xBE,  0x00,  0x00,  0xF2,  0x4A,  0x0A,  0x8C,  0x10,  0x01,  0xF6,  0x01,  0x00,
+  0x01,  0xFA,  0xA8,  0x00,  0x00,  0xF2,  0x28,  0x0B,  0x06,  0x10,  0xB9,  0x54,  0x01,  0xFA,  0xA8,  0x00,
+  0x03,  0xF6,  0xBE,  0x00,  0x00,  0xF2,  0x54,  0x0A,  0x01,  0xFC,  0xA8,  0x00,  0x20,  0x10,  0x58,  0x1C,
+  0x00,  0xF2,  0x18,  0x0B,  0x5A,  0x1C,  0x01,  0xF6,  0x01,  0x00,  0x38,  0x54,  0x00,  0xFA,  0xA6,  0x00,
+  0x01,  0xFA,  0xA8,  0x00,  0x20,  0x1C,  0x00,  0xF0,  0x72,  0x01,  0x01,  0xF6,  0x01,  0x00,  0x38,  0x54,
+  0x00,  0xFA,  0xA6,  0x00,  0x01,  0xFA,  0xA8,  0x00,  0x20,  0x1C,  0x00,  0xF0,  0x80,  0x01,  0x03,  0xF6,
+  0xE0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x01,  0x48,  0x0A,  0x13,  0x00,  0xF2,  0x34,  0x10,  0x00,  0xF2,
+  0x50,  0x0F,  0x24,  0x10,  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x02,  0xF6,  0xD0,  0x00,
+  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x49,  0x44,  0x5B,  0xF0,  0x04,  0x03,  0x00,  0xF2,  0x98,  0x0F,
+  0x00,  0xF0,  0x80,  0x01,  0x00,  0xF2,  0x10,  0x10,  0x0C,  0x1C,  0x02,  0x4B,  0xBF,  0x57,  0x9E,  0x43,
+  0x77,  0x57,  0x07,  0x4B,  0x20,  0xF0,  0x9A,  0x03,  0x40,  0x1C,  0x1E,  0xF0,  0x30,  0x03,  0x26,  0xF0,
+  0x2C,  0x03,  0xA0,  0xF0,  0x1A,  0x03,  0x11,  0xF0,  0x9A,  0x03,  0x12,  0x10,  0x9F,  0xF0,  0x3E,  0x03,
+  0x46,  0x1C,  0x82,  0xE7,  0x05,  0x00,  0x9E,  0xE7,  0x11,  0x00,  0x00,  0xF0,  0x02,  0x0A,  0x0C,  0x1C,
+  0x48,  0x1C,  0x46,  0x1C,  0x38,  0x54,  0x00,  0xEC,  0xBA,  0x00,  0x08,  0x44,  0x00,  0xEA,  0xBA,  0x00,
+  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x08,  0x44,  0x00,  0x4C,  0x82,  0xE7,  0x02,  0x00,
+  0x00,  0xF2,  0x0E,  0x11,  0x00,  0xF2,  0x0E,  0x11,  0x06,  0xF0,  0x74,  0x03,  0x1E,  0xF0,  0xF8,  0x09,
+  0x00,  0xF0,  0xFE,  0x09,  0x00,  0xFC,  0xBE,  0x00,  0x98,  0x57,  0x55,  0xF0,  0xA0,  0x04,  0x01,  0xE6,
+  0x0C,  0x00,  0x00,  0xF2,  0x4A,  0x0D,  0x00,  0xF2,  0x0E,  0x11,  0x00,  0xF2,  0xB8,  0x11,  0x00,  0xF2,
+  0xC4,  0x11,  0x01,  0xF0,  0x7C,  0x02,  0x00,  0xF0,  0x8A,  0x02,  0x46,  0x1C,  0x0C,  0x1C,  0x67,  0x1B,
+  0xBF,  0x57,  0x77,  0x57,  0x02,  0x4B,  0x48,  0x1C,  0x32,  0x1C,  0x00,  0xF2,  0x8E,  0x0D,  0x30,  0x1C,
+  0x96,  0xF0,  0xB0,  0x03,  0xB1,  0xF0,  0xB4,  0x03,  0x1E,  0xF0,  0xF8,  0x09,  0x85,  0xF0,  0xFE,  0x09,
+  0x00,  0xFC,  0xBE,  0x00,  0x98,  0x57,  0x14,  0x12,  0x01,  0xE6,  0x0C,  0x00,  0x00,  0xF2,  0x4A,  0x0D,
+  0x00,  0xF2,  0x0E,  0x11,  0x01,  0xF0,  0x7C,  0x02,  0x00,  0xF0,  0x8A,  0x02,  0x03,  0xF6,  0xE0,  0x00,
+  0x00,  0xF2,  0x64,  0x0A,  0x01,  0x48,  0x55,  0xF0,  0x8C,  0x04,  0x03,  0x82,  0x03,  0xFC,  0xA0,  0x00,
+  0x9B,  0x57,  0x40,  0x12,  0x69,  0x18,  0x00,  0xF2,  0x0E,  0x11,  0x85,  0xF0,  0x36,  0x04,  0x69,  0x08,
+  0x00,  0xF2,  0x0E,  0x11,  0x85,  0xF0,  0xFE,  0x09,  0x68,  0x08,  0x4C,  0x44,  0x28,  0x12,  0x44,  0x48,
+  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x45,  0x58,  0x00,  0xF2,  0xF2,  0x0D,  0x00,  0xCC,
+  0x01,  0x48,  0x55,  0xF0,  0x8C,  0x04,  0x4C,  0x44,  0xEF,  0x13,  0x00,  0xF2,  0xC2,  0x0F,  0x00,  0xF2,
+  0x10,  0x10,  0x08,  0x10,  0x68,  0x18,  0x45,  0x5A,  0x00,  0xF2,  0xF2,  0x0D,  0x04,  0x80,  0x18,  0xE4,
+  0x10,  0x00,  0x28,  0x12,  0x01,  0xE6,  0x06,  0x00,  0x04,  0x80,  0x18,  0xE4,  0x01,  0x00,  0x04,  0x12,
+  0x01,  0xE6,  0x0D,  0x00,  0x00,  0xF2,  0x4A,  0x0D,  0x00,  0xF2,  0x0E,  0x11,  0x04,  0xE6,  0x02,  0x00,
+  0x9E,  0xE7,  0x15,  0x00,  0x01,  0xF0,  0x18,  0x0A,  0x00,  0xF0,  0xFE,  0x09,  0x69,  0x08,  0x05,  0x80,
+  0x48,  0xE4,  0x00,  0x00,  0x0C,  0x12,  0x00,  0xE6,  0x11,  0x00,  0x00,  0xEA,  0xB8,  0x00,  0x00,  0xF2,
+  0xB2,  0x10,  0x82,  0xE7,  0x02,  0x00,  0x1C,  0x90,  0x40,  0x5C,  0x00,  0x16,  0x01,  0xE6,  0x06,  0x00,
+  0x00,  0xF2,  0x4A,  0x0D,  0x01,  0xF0,  0x80,  0x01,  0x1E,  0xF0,  0x80,  0x01,  0x00,  0xF0,  0x94,  0x04,
+  0x42,  0x5B,  0x06,  0xF7,  0x03,  0x00,  0x46,  0x59,  0xBF,  0x57,  0x77,  0x57,  0x01,  0xE6,  0x80,  0x00,
+  0x07,  0x80,  0x31,  0x44,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x5E,  0x13,  0x20,  0x80,  0x48,  0xE4,
+  0x03,  0x00,  0x56,  0x12,  0x04,  0x80,  0x18,  0xE4,  0x02,  0x00,  0x4C,  0x13,  0x00,  0xFC,  0xA2,  0x00,
+  0x98,  0x57,  0x55,  0xF0,  0x18,  0x05,  0x31,  0xE4,  0x40,  0x00,  0x00,  0xFC,  0xA0,  0x00,  0x98,  0x57,
+  0x36,  0x12,  0x4C,  0x1C,  0x00,  0xF2,  0x0E,  0x11,  0x89,  0x48,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,
+  0x2A,  0x05,  0x82,  0xE7,  0x06,  0x00,  0x1B,  0x80,  0x48,  0xE4,  0x22,  0x00,  0x5B,  0xF0,  0x08,  0x05,
+  0x48,  0xE4,  0x20,  0x00,  0x59,  0xF0,  0x0C,  0x05,  0x00,  0xE6,  0x20,  0x00,  0x09,  0x48,  0x00,  0xF2,
+  0x0E,  0x11,  0x86,  0xF0,  0x2A,  0x05,  0x83,  0x80,  0x04,  0x10,  0x00,  0xF2,  0x9E,  0x0D,  0x00,  0xE6,
+  0x01,  0x00,  0x00,  0xEA,  0x26,  0x01,  0x01,  0xEA,  0x27,  0x01,  0x04,  0x80,  0x18,  0xE4,  0x10,  0x00,
+  0x36,  0x12,  0xB9,  0x54,  0x00,  0xF2,  0xF2,  0x0E,  0x01,  0xE6,  0x06,  0x00,  0x04,  0x80,  0x18,  0xE4,
+  0x01,  0x00,  0x04,  0x12,  0x01,  0xE6,  0x0D,  0x00,  0x00,  0xF2,  0x4A,  0x0D,  0x00,  0xF2,  0x0E,  0x11,
+  0x00,  0xF2,  0xB8,  0x11,  0x00,  0xF2,  0xC4,  0x11,  0x04,  0xE6,  0x02,  0x00,  0x9E,  0xE7,  0x15,  0x00,
+  0x01,  0xF0,  0x18,  0x0A,  0x00,  0xF0,  0xFE,  0x09,  0x00,  0xFC,  0x20,  0x01,  0x98,  0x57,  0x34,  0x12,
+  0x00,  0xFC,  0x24,  0x01,  0x98,  0x57,  0x2C,  0x13,  0xB9,  0x54,  0x00,  0xF2,  0xF2,  0x0E,  0x86,  0xF0,
+  0xA4,  0x05,  0x03,  0xF6,  0x01,  0x00,  0x00,  0xF2,  0x88,  0x0E,  0x85,  0xF0,  0x9A,  0x05,  0x82,  0xE7,
+  0x03,  0x00,  0x00,  0xF2,  0x5C,  0x0B,  0x82,  0xE7,  0x02,  0x00,  0x00,  0xFC,  0x24,  0x01,  0xB0,  0x57,
+  0x00,  0xFA,  0x24,  0x01,  0x00,  0xFC,  0x9E,  0x00,  0x98,  0x57,  0x5A,  0x12,  0x00,  0xFC,  0xB6,  0x00,
+  0x98,  0x57,  0x52,  0x13,  0x03,  0xE6,  0x0C,  0x00,  0x00,  0xFC,  0x9C,  0x00,  0x98,  0x57,  0x04,  0x13,
+  0x03,  0xE6,  0x19,  0x00,  0x05,  0xE6,  0x08,  0x00,  0x00,  0xF6,  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,
+  0x03,  0x58,  0x00,  0xDC,  0x18,  0xF4,  0x00,  0x80,  0x04,  0x13,  0x05,  0xE6,  0x0F,  0x00,  0xB9,  0x54,
+  0x00,  0xF2,  0xF2,  0x0E,  0x86,  0xF0,  0x06,  0x06,  0x00,  0xF2,  0xB6,  0x0E,  0x85,  0xF0,  0xFC,  0x05,
+  0x82,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x5C,  0x0B,  0x82,  0xE7,  0x02,  0x00,  0x00,  0xFC,  0xB6,  0x00,
+  0xB0,  0x57,  0x00,  0xFA,  0xB6,  0x00,  0x01,  0xF6,  0x01,  0x00,  0x00,  0xF2,  0xF2,  0x0E,  0x9C,  0x32,
+  0x4E,  0x1C,  0x32,  0x1C,  0x00,  0xF2,  0x8E,  0x0D,  0x30,  0x1C,  0x82,  0xE7,  0x04,  0x00,  0xB1,  0xF0,
+  0x1E,  0x06,  0x0A,  0xF0,  0x3A,  0x06,  0x05,  0xF0,  0xD2,  0x06,  0x06,  0xF0,  0xD8,  0x06,  0x09,  0xF0,
+  0x20,  0x09,  0x1E,  0xF0,  0xF8,  0x09,  0x00,  0xF0,  0xFE,  0x09,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,
+  0x30,  0x12,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x21,  0x80,  0x18,  0xE4,  0xE0,  0x00,
+  0x09,  0x48,  0x00,  0xF2,  0x0E,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x09,  0xE7,
+  0x00,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x99,  0xA4,  0x00,  0xF2,  0x0E,  0x11,  0x09,  0xE7,  0x00,  0x00,
+  0x9A,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x02,  0x00,  0x34,  0x12,  0x09,  0xE7,  0x1B,  0x00,  0x00,  0xF2,
+  0x0E,  0x11,  0x21,  0x80,  0x18,  0xE4,  0xE0,  0x00,  0x09,  0x48,  0x00,  0xF2,  0x0E,  0x11,  0x09,  0xE7,
+  0x00,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x09,  0xE7,
+  0x01,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF0,  0x08,  0x09,  0xBB,  0x55,
+  0x9A,  0x81,  0x03,  0xF7,  0x20,  0x00,  0x09,  0x6F,  0x93,  0x45,  0x55,  0xF0,  0xDE,  0x06,  0xB1,  0xF0,
+  0xBE,  0x06,  0x0A,  0xF0,  0xB6,  0x06,  0x09,  0xF0,  0x20,  0x09,  0x1E,  0xF0,  0xF8,  0x09,  0x00,  0xF0,
+  0xFE,  0x09,  0x00,  0xF2,  0x5C,  0x0B,  0x47,  0x10,  0x09,  0xE7,  0x08,  0x00,  0x41,  0x10,  0x05,  0x80,
+  0x48,  0xE4,  0x00,  0x00,  0x1E,  0x12,  0x00,  0xE6,  0x11,  0x00,  0x00,  0xEA,  0xB8,  0x00,  0x00,  0xF2,
+  0xB2,  0x10,  0x2C,  0x90,  0xAE,  0x90,  0x08,  0x50,  0x8A,  0x50,  0x38,  0x54,  0x1F,  0x40,  0x00,  0xF2,
+  0xB0,  0x0D,  0x08,  0x10,  0x08,  0x90,  0x8A,  0x90,  0x30,  0x50,  0xB2,  0x50,  0x9C,  0x32,  0x0C,  0x92,
+  0x8E,  0x92,  0x38,  0x54,  0x04,  0x80,  0x30,  0xE4,  0x08,  0x00,  0x04,  0x40,  0x0C,  0x1C,  0x00,  0xF6,
+  0x03,  0x00,  0xB1,  0xF0,  0x22,  0x07,  0x9E,  0xF0,  0x36,  0x07,  0x01,  0x48,  0x55,  0xF0,  0xF8,  0x09,
+  0x0C,  0x1C,  0x10,  0x44,  0xED,  0x10,  0x0B,  0xF0,  0x5A,  0x07,  0x0C,  0xF0,  0x5E,  0x07,  0x05,  0xF0,
+  0x4E,  0x07,  0x06,  0xF0,  0x54,  0x07,  0x09,  0xF0,  0x20,  0x09,  0x00,  0xF0,  0xFE,  0x09,  0x00,  0xF2,
+  0x5C,  0x0B,  0xCF,  0x10,  0x09,  0xE7,  0x08,  0x00,  0xC9,  0x10,  0x2E,  0x1C,  0x02,  0x10,  0x2C,  0x1C,
+  0xAA,  0xF0,  0x60,  0x07,  0xAC,  0xF0,  0x6E,  0x07,  0x40,  0x10,  0x34,  0x1C,  0xF3,  0x10,  0xAD,  0xF0,
+  0x78,  0x07,  0xC8,  0x10,  0x36,  0x1C,  0xE9,  0x10,  0x2B,  0xF0,  0x7E,  0x08,  0x6B,  0x18,  0x18,  0xF4,
+  0x00,  0xFE,  0x20,  0x12,  0x01,  0x58,  0xD2,  0xF0,  0x7E,  0x08,  0x76,  0x18,  0x18,  0xF4,  0x03,  0x00,
+  0xEC,  0x12,  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0xE2,  0x12,  0x0B,  0xF0,  0x60,  0x07,
+  0x0C,  0xF0,  0x60,  0x07,  0x36,  0x1C,  0x34,  0x1C,  0xB7,  0x10,  0x38,  0x54,  0xB9,  0x54,  0x84,  0x80,
+  0x19,  0xE4,  0x20,  0x00,  0xB2,  0x13,  0x85,  0x80,  0x81,  0x48,  0x66,  0x12,  0x04,  0x80,  0x18,  0xE4,
+  0x08,  0x00,  0x58,  0x13,  0x1F,  0x80,  0x08,  0x44,  0xC8,  0x44,  0x9F,  0x12,  0x1F,  0x40,  0x34,  0x91,
+  0xB6,  0x91,  0x44,  0x55,  0xE5,  0x55,  0x02,  0xEC,  0xB8,  0x00,  0x02,  0x49,  0xBB,  0x55,  0x82,  0x81,
+  0xC0,  0x55,  0x48,  0xF4,  0x0F,  0x00,  0x5A,  0xF0,  0x16,  0x08,  0x4A,  0xE4,  0x17,  0x00,  0xD5,  0xF0,
+  0xF6,  0x07,  0x02,  0xF6,  0x0F,  0x00,  0x02,  0xF4,  0x02,  0x00,  0x02,  0xEA,  0xB8,  0x00,  0x04,  0x91,
+  0x86,  0x91,  0x02,  0x4B,  0x2C,  0x90,  0x08,  0x50,  0x2E,  0x90,  0x0A,  0x50,  0x2C,  0x51,  0xAE,  0x51,
+  0x00,  0xF2,  0xB2,  0x10,  0x38,  0x54,  0x00,  0xF2,  0xB0,  0x0D,  0x56,  0x10,  0x34,  0x91,  0xB6,  0x91,
+  0x0C,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x08,  0x00,  0x41,  0x12,  0x0C,  0x91,  0x8E,  0x91,  0x04,  0x80,
+  0x18,  0xE4,  0xF7,  0x00,  0x04,  0x40,  0x30,  0x90,  0xB2,  0x90,  0x36,  0x10,  0x02,  0x80,  0x48,  0xE4,
+  0x10,  0x00,  0x31,  0x12,  0x82,  0xE7,  0x10,  0x00,  0x84,  0x80,  0x19,  0xE4,  0x20,  0x00,  0x10,  0x13,
+  0x0C,  0x90,  0x8E,  0x90,  0x5D,  0xF0,  0x74,  0x07,  0x0C,  0x58,  0x8D,  0x58,  0x00,  0xF0,  0x60,  0x07,
+  0x38,  0x54,  0xB9,  0x54,  0x19,  0x80,  0xF1,  0x10,  0x3A,  0x55,  0x19,  0x81,  0xBB,  0x55,  0x10,  0x90,
+  0x92,  0x90,  0x10,  0x58,  0x91,  0x58,  0x14,  0x59,  0x95,  0x59,  0x00,  0xF0,  0x60,  0x07,  0x04,  0x80,
+  0x18,  0xE4,  0x20,  0x00,  0x06,  0x12,  0x6C,  0x19,  0x19,  0x41,  0x7C,  0x10,  0x6C,  0x19,  0x0C,  0x51,
+  0xED,  0x19,  0x8E,  0x51,  0x6B,  0x18,  0x18,  0xF4,  0x00,  0xFF,  0x02,  0x13,  0x6A,  0x10,  0x01,  0x58,
+  0xD2,  0xF0,  0xBC,  0x08,  0x76,  0x18,  0x18,  0xF4,  0x03,  0x00,  0x0A,  0x12,  0x00,  0xFC,  0x22,  0x01,
+  0x18,  0xF4,  0x01,  0x00,  0x06,  0x13,  0x9E,  0xE7,  0x16,  0x00,  0x4C,  0x10,  0xD1,  0xF0,  0xC6,  0x08,
+  0x9E,  0xE7,  0x17,  0x00,  0x42,  0x10,  0xD0,  0xF0,  0xD0,  0x08,  0x9E,  0xE7,  0x19,  0x00,  0x38,  0x10,
+  0xCF,  0xF0,  0xDA,  0x08,  0x9E,  0xE7,  0x20,  0x00,  0x2E,  0x10,  0xCE,  0xF0,  0xE4,  0x08,  0x9E,  0xE7,
+  0x21,  0x00,  0x24,  0x10,  0xCD,  0xF0,  0xEE,  0x08,  0x9E,  0xE7,  0x22,  0x00,  0x1A,  0x10,  0xCC,  0xF0,
+  0x00,  0x09,  0x84,  0x80,  0x19,  0xE4,  0x04,  0x00,  0x06,  0x12,  0x9E,  0xE7,  0x12,  0x00,  0x08,  0x10,
+  0xCB,  0xF0,  0x08,  0x09,  0x9E,  0xE7,  0x24,  0x00,  0xB1,  0xF0,  0x08,  0x09,  0x05,  0xF0,  0x1A,  0x09,
+  0x09,  0xF0,  0x20,  0x09,  0x1E,  0xF0,  0xF8,  0x09,  0xE4,  0x10,  0x00,  0xF2,  0x5C,  0x0B,  0xE9,  0x10,
+  0x9C,  0x32,  0x82,  0xE7,  0x20,  0x00,  0x32,  0x1C,  0xE9,  0x09,  0x00,  0xF2,  0x0E,  0x11,  0x85,  0xF0,
+  0xFE,  0x09,  0x69,  0x08,  0x01,  0xF0,  0x40,  0x09,  0x1E,  0xF0,  0xF8,  0x09,  0x00,  0xF0,  0x34,  0x09,
+  0x30,  0x44,  0x06,  0x12,  0x9E,  0xE7,  0x42,  0x00,  0xB8,  0x10,  0x04,  0xF6,  0x01,  0x00,  0xB3,  0x45,
+  0x74,  0x12,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x22,  0x13,  0x4B,  0xE4,  0x02,  0x00,  0x36,  0x12,
+  0x4B,  0xE4,  0x28,  0x00,  0xAC,  0x13,  0x00,  0xF2,  0xB8,  0x11,  0x00,  0xF2,  0xC4,  0x11,  0x03,  0xF6,
+  0xD0,  0x00,  0xFA,  0x14,  0x82,  0xE7,  0x01,  0x00,  0x00,  0xF0,  0x80,  0x01,  0x9E,  0xE7,  0x44,  0x00,
+  0x4B,  0xE4,  0x02,  0x00,  0x06,  0x12,  0x03,  0xE6,  0x02,  0x00,  0x76,  0x10,  0x00,  0xF2,  0x9E,  0x0D,
+  0x03,  0xE6,  0x02,  0x00,  0x6C,  0x10,  0x00,  0xF2,  0x9E,  0x0D,  0x19,  0x82,  0x34,  0x46,  0x0A,  0x13,
+  0x03,  0xE6,  0x02,  0x00,  0x9E,  0xE7,  0x43,  0x00,  0x68,  0x10,  0x04,  0x80,  0x30,  0xE4,  0x20,  0x00,
+  0x04,  0x40,  0x00,  0xF2,  0xB8,  0x11,  0x00,  0xF2,  0xC4,  0x11,  0x82,  0xE7,  0x01,  0x00,  0x06,  0xF7,
+  0x02,  0x00,  0x00,  0xF0,  0x08,  0x03,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x06,  0x12,  0x03,  0xE6,
+  0x02,  0x00,  0x3E,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x02,  0x00,  0x3A,  0x12,  0x04,  0x80,  0x18,  0xE4,
+  0xFD,  0x00,  0x04,  0x40,  0x1C,  0x1C,  0x9D,  0xF0,  0xE6,  0x09,  0x1C,  0x1C,  0x9D,  0xF0,  0xEC,  0x09,
+  0xC1,  0x10,  0x9E,  0xE7,  0x13,  0x00,  0x0A,  0x10,  0x9E,  0xE7,  0x41,  0x00,  0x04,  0x10,  0x9E,  0xE7,
+  0x24,  0x00,  0x00,  0xFC,  0xBE,  0x00,  0x98,  0x57,  0xD5,  0xF0,  0x8A,  0x02,  0x04,  0xE6,  0x04,  0x00,
+  0x06,  0x10,  0x04,  0xE6,  0x04,  0x00,  0x9D,  0x41,  0x1C,  0x42,  0x9F,  0xE7,  0x00,  0x00,  0x06,  0xF7,
+  0x02,  0x00,  0x03,  0xF6,  0xE0,  0x00,  0x3C,  0x14,  0x44,  0x58,  0x45,  0x58,  0x00,  0xF2,  0xF2,  0x0D,
+  0x00,  0xF2,  0x7A,  0x10,  0x00,  0xF2,  0xC2,  0x0F,  0x3C,  0x14,  0x1E,  0x1C,  0x00,  0xF0,  0x80,  0x01,
+  0x12,  0x1C,  0x22,  0x1C,  0xD2,  0x14,  0x00,  0xF0,  0x72,  0x01,  0x83,  0x59,  0x03,  0xDC,  0x73,  0x57,
+  0x80,  0x5D,  0x00,  0x16,  0x83,  0x59,  0x03,  0xDC,  0x38,  0x54,  0x70,  0x57,  0x33,  0x54,  0x3B,  0x54,
+  0x80,  0x5D,  0x00,  0x16,  0x03,  0x57,  0x83,  0x59,  0x38,  0x54,  0x00,  0xCC,  0x00,  0x16,  0x03,  0x57,
+  0x83,  0x59,  0x00,  0x4C,  0x00,  0x16,  0x02,  0x80,  0x48,  0xE4,  0x01,  0x00,  0x0E,  0x12,  0x48,  0xE4,
+  0x05,  0x00,  0x08,  0x12,  0x00,  0xF2,  0xB8,  0x11,  0x00,  0xF2,  0xC4,  0x11,  0xC1,  0x5A,  0x3A,  0x55,
+  0x02,  0xEC,  0xB5,  0x00,  0x45,  0x59,  0x00,  0xF2,  0xF2,  0x0D,  0x83,  0x58,  0x30,  0xE7,  0x00,  0x00,
+  0x10,  0x4D,  0x30,  0xE7,  0x40,  0x00,  0x10,  0x4F,  0x38,  0x90,  0xBA,  0x90,  0x10,  0x5C,  0x80,  0x5C,
+  0x83,  0x5A,  0x10,  0x4E,  0x04,  0xEA,  0xB5,  0x00,  0x43,  0x5B,  0x03,  0xF4,  0xE0,  0x00,  0x83,  0x59,
+  0x04,  0xCC,  0x01,  0x4A,  0x0A,  0x12,  0x45,  0x5A,  0x00,  0xF2,  0xF2,  0x0D,  0x00,  0xF2,  0x34,  0x10,
+  0x00,  0x16,  0x08,  0x1C,  0x00,  0xFC,  0xAC,  0x00,  0x06,  0x58,  0x67,  0x18,  0x18,  0xF4,  0x8F,  0xE1,
+  0x01,  0xFC,  0xAE,  0x00,  0x19,  0xF4,  0x70,  0x1E,  0xB0,  0x54,  0x07,  0x58,  0x00,  0xFC,  0xB0,  0x00,
+  0x08,  0x58,  0x00,  0xFC,  0xB2,  0x00,  0x09,  0x58,  0x0A,  0x1C,  0x00,  0xE6,  0x0F,  0x00,  0x00,  0xEA,
+  0xB9,  0x00,  0x38,  0x54,  0x00,  0xFA,  0x24,  0x01,  0x00,  0xFA,  0xB6,  0x00,  0x18,  0x1C,  0x14,  0x1C,
+  0x10,  0x1C,  0x32,  0x1C,  0x12,  0x1C,  0x00,  0x16,  0x3E,  0x57,  0x0C,  0x14,  0x0E,  0x47,  0x07,  0xE6,
+  0x10,  0x00,  0xCE,  0x47,  0xF5,  0x13,  0x00,  0x16,  0x00,  0xF2,  0x9E,  0x0D,  0x02,  0x4B,  0x03,  0xF6,
+  0xE0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x01,  0x48,  0x20,  0x12,  0x44,  0x58,  0x45,  0x58,  0x9E,  0xE7,
+  0x15,  0x00,  0x9C,  0xE7,  0x04,  0x00,  0x00,  0xF2,  0xF2,  0x0D,  0x00,  0xF2,  0x7A,  0x10,  0x00,  0xF2,
+  0xC2,  0x0F,  0x00,  0xF2,  0x76,  0x0A,  0x1E,  0x1C,  0xD5,  0x10,  0x00,  0x16,  0x69,  0x08,  0x48,  0xE4,
+  0x04,  0x00,  0x64,  0x12,  0x48,  0xE4,  0x02,  0x00,  0x20,  0x12,  0x48,  0xE4,  0x03,  0x00,  0x1A,  0x12,
+  0x48,  0xE4,  0x08,  0x00,  0x14,  0x12,  0x48,  0xE4,  0x01,  0x00,  0xF0,  0x12,  0x48,  0xE4,  0x07,  0x00,
+  0x12,  0x12,  0x01,  0xE6,  0x07,  0x00,  0x00,  0xF2,  0x4A,  0x0D,  0x00,  0xF2,  0x0E,  0x11,  0x05,  0xF0,
+  0x5C,  0x0B,  0x00,  0x16,  0x00,  0xE6,  0x01,  0x00,  0x00,  0xEA,  0x99,  0x00,  0x02,  0x80,  0x48,  0xE4,
+  0x03,  0x00,  0xB9,  0x12,  0x48,  0xE4,  0x06,  0x00,  0xB3,  0x12,  0x01,  0xE6,  0x06,  0x00,  0x00,  0xF2,
+  0x4A,  0x0D,  0x00,  0xF2,  0x0E,  0x11,  0x04,  0xE6,  0x02,  0x00,  0x9E,  0xE7,  0x15,  0x00,  0x01,  0xF0,
+  0x18,  0x0A,  0x00,  0xF0,  0xFE,  0x09,  0x00,  0x16,  0x02,  0x80,  0x48,  0xE4,  0x10,  0x00,  0x1C,  0x12,
+  0x82,  0xE7,  0x08,  0x00,  0x3C,  0x56,  0x03,  0x82,  0x00,  0xF2,  0xDE,  0x0D,  0x30,  0xE7,  0x08,  0x00,
+  0x04,  0xF7,  0x70,  0x01,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF0,  0x80,  0x01,  0x6C,  0x19,  0xED,  0x19,
+  0x5D,  0xF0,  0xD0,  0x0B,  0x44,  0x55,  0xE5,  0x55,  0x59,  0xF0,  0x4E,  0x0C,  0x04,  0x55,  0xA5,  0x55,
+  0x1F,  0x80,  0x01,  0xEC,  0xB8,  0x00,  0x82,  0x48,  0x82,  0x80,  0x49,  0x44,  0x2E,  0x13,  0x01,  0xEC,
+  0xB8,  0x00,  0x41,  0xE4,  0x02,  0x00,  0x01,  0xEA,  0xB8,  0x00,  0x49,  0xE4,  0x11,  0x00,  0x59,  0xF0,
+  0x2A,  0x0C,  0x01,  0xE6,  0x17,  0x00,  0x01,  0xEA,  0xB8,  0x00,  0x02,  0x4B,  0x88,  0x90,  0xAC,  0x50,
+  0x8A,  0x90,  0xAE,  0x50,  0x01,  0xEC,  0xB8,  0x00,  0x82,  0x48,  0x82,  0x80,  0x10,  0x44,  0x02,  0x4B,
+  0x1F,  0x40,  0xC0,  0x44,  0x00,  0xF2,  0xB0,  0x0D,  0x04,  0x55,  0xA5,  0x55,  0x9F,  0x10,  0x0C,  0x51,
+  0x8E,  0x51,  0x30,  0x90,  0xB2,  0x90,  0x00,  0x56,  0xA1,  0x56,  0x30,  0x50,  0xB2,  0x50,  0x34,  0x90,
+  0xB6,  0x90,  0x40,  0x56,  0xE1,  0x56,  0x34,  0x50,  0xB6,  0x50,  0x65,  0x10,  0xB1,  0xF0,  0x6C,  0x0C,
+  0x85,  0xF0,  0xC6,  0x0B,  0xE9,  0x09,  0x4B,  0xE4,  0x03,  0x00,  0x78,  0x12,  0x4B,  0xE4,  0x02,  0x00,
+  0x01,  0x13,  0xB1,  0xF0,  0x82,  0x0C,  0x85,  0xF0,  0xC6,  0x0B,  0x69,  0x08,  0x48,  0xE4,  0x03,  0x00,
+  0xD5,  0xF0,  0x82,  0x0B,  0x00,  0xF2,  0x0E,  0x11,  0x85,  0xF0,  0xC6,  0x0B,  0xE8,  0x09,  0x3C,  0x56,
+  0x00,  0xFC,  0x20,  0x01,  0x98,  0x57,  0x02,  0x13,  0xBB,  0x45,  0x4B,  0xE4,  0x00,  0x00,  0x08,  0x12,
+  0x03,  0xE6,  0x01,  0x00,  0x04,  0xF6,  0x00,  0x80,  0xA8,  0x14,  0xD2,  0x14,  0x30,  0x1C,  0x02,  0x80,
+  0x48,  0xE4,  0x03,  0x00,  0x10,  0x13,  0x00,  0xFC,  0xB6,  0x00,  0x98,  0x57,  0x02,  0x13,  0x4C,  0x1C,
+  0x3E,  0x1C,  0x00,  0xF0,  0x8A,  0x0B,  0x00,  0xFC,  0x24,  0x01,  0xB0,  0x57,  0x00,  0xFA,  0x24,  0x01,
+  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,  0x8A,  0x0B,  0x00,  0xF2,  0x88,  0x0E,
+  0x00,  0xF0,  0x8A,  0x0B,  0xB1,  0xF0,  0xF4,  0x0C,  0x85,  0xF0,  0x82,  0x0B,  0x69,  0x08,  0x48,  0xE4,
+  0x01,  0x00,  0xD5,  0xF0,  0x82,  0x0B,  0xFC,  0x14,  0x42,  0x58,  0x6C,  0x14,  0x80,  0x14,  0x30,  0x1C,
+  0x4A,  0xF4,  0x02,  0x00,  0x55,  0xF0,  0x82,  0x0B,  0x4A,  0xF4,  0x01,  0x00,  0x0E,  0x12,  0x02,  0x80,
+  0x48,  0xE4,  0x03,  0x00,  0x06,  0x13,  0x3E,  0x1C,  0x00,  0xF0,  0x8A,  0x0B,  0x00,  0xFC,  0xB6,  0x00,
+  0xB0,  0x57,  0x00,  0xFA,  0xB6,  0x00,  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,
+  0x8A,  0x0B,  0x00,  0xF2,  0xB6,  0x0E,  0x00,  0xF0,  0x8A,  0x0B,  0x4C,  0x1C,  0xB1,  0xF0,  0x4C,  0x0D,
+  0x85,  0xF0,  0x58,  0x0D,  0x69,  0x08,  0xF3,  0x10,  0x86,  0xF0,  0x60,  0x0D,  0x4E,  0x1C,  0x89,  0x48,
+  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x18,  0xF4,
+  0xFF,  0x7F,  0x30,  0x56,  0x00,  0x5C,  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,
+  0x03,  0x58,  0x00,  0xDC,  0x18,  0xF4,  0x00,  0x80,  0x30,  0x56,  0x00,  0x5C,  0x00,  0x16,  0x00,  0xF6,
+  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x0B,  0x58,  0x00,  0x16,  0x03,  0xF6,
+  0x24,  0x01,  0x00,  0xF2,  0x54,  0x0A,  0x03,  0xF6,  0xB6,  0x00,  0x00,  0xF2,  0x54,  0x0A,  0x00,  0x16,
+  0x02,  0xEC,  0xB8,  0x00,  0x02,  0x49,  0x18,  0xF4,  0xFF,  0x00,  0x00,  0x54,  0x00,  0x54,  0x00,  0x54,
+  0x00,  0xF4,  0x08,  0x00,  0xE1,  0x18,  0x80,  0x54,  0x03,  0x58,  0x00,  0xDD,  0x01,  0xDD,  0x02,  0xDD,
+  0x03,  0xDC,  0x02,  0x4B,  0x30,  0x50,  0xB2,  0x50,  0x34,  0x51,  0xB6,  0x51,  0x00,  0x16,  0x45,  0x5A,
+  0x1D,  0xF4,  0xFF,  0x00,  0x85,  0x56,  0x85,  0x56,  0x85,  0x56,  0x05,  0xF4,  0x02,  0x12,  0x83,  0x5A,
+  0x00,  0x16,  0x1D,  0xF4,  0xFF,  0x00,  0x85,  0x56,  0x85,  0x56,  0x85,  0x56,  0x05,  0xF4,  0x00,  0x12,
+  0x83,  0x5A,  0x00,  0x16,  0x38,  0x54,  0xBB,  0x55,  0x3C,  0x56,  0xBD,  0x56,  0x00,  0xF2,  0x0E,  0x11,
+  0x85,  0xF0,  0x7E,  0x0E,  0xE9,  0x09,  0xC1,  0x59,  0x00,  0xF2,  0x0E,  0x11,  0x85,  0xF0,  0x7E,  0x0E,
+  0xE8,  0x0A,  0x83,  0x55,  0x83,  0x55,  0x4B,  0xF4,  0x90,  0x01,  0x5C,  0xF0,  0x32,  0x0E,  0xBD,  0x56,
+  0x40,  0x10,  0x4B,  0xF4,  0x30,  0x00,  0x59,  0xF0,  0x44,  0x0E,  0x01,  0xF6,  0x0C,  0x00,  0x00,  0xF6,
+  0x01,  0x00,  0x2E,  0x10,  0x02,  0xFC,  0x9C,  0x00,  0x9A,  0x57,  0x14,  0x13,  0x4B,  0xF4,  0x64,  0x00,
+  0x59,  0xF0,  0x60,  0x0E,  0x03,  0xF6,  0x64,  0x00,  0x01,  0xF6,  0x19,  0x00,  0x00,  0xF6,  0x01,  0x00,
+  0x43,  0xF4,  0x33,  0x00,  0x56,  0xF0,  0x72,  0x0E,  0x04,  0xF4,  0x00,  0x01,  0x43,  0xF4,  0x19,  0x00,
+  0xF3,  0x10,  0xB4,  0x56,  0xC3,  0x58,  0x02,  0xFC,  0x9E,  0x00,  0x9A,  0x57,  0x08,  0x13,  0x3C,  0x56,
+  0x00,  0xF6,  0x02,  0x00,  0x00,  0x16,  0x00,  0x16,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,  0x0E,  0x11,
+  0x86,  0xF0,  0xB4,  0x0E,  0x09,  0xE7,  0x02,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,  0xB4,  0x0E,
+  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,  0xB4,  0x0E,  0x4E,  0x1C,  0x89,  0x49,
+  0x00,  0xF2,  0x0E,  0x11,  0x00,  0x16,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,
+  0xEE,  0x0E,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,  0xEE,  0x0E,  0x09,  0xE7,
+  0x01,  0x00,  0x00,  0xF2,  0x0E,  0x11,  0x86,  0xF0,  0xEE,  0x0E,  0x89,  0x49,  0x00,  0xF2,  0x0E,  0x11,
+  0x86,  0xF0,  0xEE,  0x0E,  0x4E,  0x1C,  0x89,  0x4A,  0x00,  0xF2,  0x0E,  0x11,  0x00,  0x16,  0x3C,  0x56,
+  0x00,  0x16,  0x00,  0xEC,  0x26,  0x01,  0x48,  0xE4,  0x01,  0x00,  0x1E,  0x13,  0x38,  0x44,  0x00,  0xEA,
+  0x26,  0x01,  0x49,  0xF4,  0x00,  0x00,  0x04,  0x12,  0x4E,  0x1C,  0x02,  0x10,  0x4C,  0x1C,  0x01,  0xEC,
+  0x27,  0x01,  0x89,  0x48,  0x00,  0xF2,  0x0E,  0x11,  0x02,  0x14,  0x00,  0x16,  0x85,  0xF0,  0x4E,  0x0F,
+  0x38,  0x54,  0x00,  0xEA,  0x99,  0x00,  0x00,  0xF2,  0x5C,  0x0B,  0x02,  0x80,  0x48,  0xE4,  0x06,  0x00,
+  0x1C,  0x13,  0x00,  0xEC,  0x99,  0x00,  0x48,  0xE4,  0x01,  0x00,  0x0A,  0x12,  0x04,  0x80,  0x30,  0xE4,
+  0x01,  0x00,  0x04,  0x40,  0x08,  0x10,  0x04,  0x80,  0x18,  0xE4,  0xFE,  0x00,  0x04,  0x40,  0x00,  0x16,
+  0x02,  0xF6,  0xE0,  0x00,  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x81,  0x48,  0x22,  0x12,  0x00,  0x4E,
+  0x83,  0x5A,  0x90,  0x4C,  0x20,  0xE7,  0x00,  0x00,  0xC3,  0x58,  0x1B,  0xF4,  0xFF,  0x00,  0x83,  0x55,
+  0x83,  0x55,  0x83,  0x55,  0x03,  0xF4,  0x00,  0x12,  0x8B,  0x55,  0x83,  0x59,  0x00,  0x4E,  0x00,  0x16,
+  0x00,  0x4E,  0x02,  0xF6,  0xF0,  0x00,  0x02,  0x57,  0x03,  0x59,  0x00,  0x4E,  0x83,  0x5A,  0x30,  0xE7,
+  0x00,  0x00,  0x20,  0xE7,  0x00,  0x00,  0x00,  0x16,  0x02,  0xF6,  0xF0,  0x00,  0x02,  0x57,  0x03,  0x59,
+  0x01,  0xCC,  0x00,  0x4E,  0x83,  0x5A,  0x30,  0xE7,  0x00,  0x00,  0x80,  0x4C,  0xC3,  0x58,  0x1B,  0xF4,
+  0xFF,  0x00,  0x83,  0x55,  0x83,  0x55,  0x83,  0x55,  0x03,  0xF4,  0x00,  0x12,  0x83,  0x59,  0x00,  0x4E,
+  0x00,  0x16,  0x03,  0xF6,  0xE0,  0x00,  0x03,  0x57,  0x83,  0x59,  0x3A,  0x55,  0x02,  0xCC,  0x45,  0x5A,
+  0x00,  0xF2,  0xF2,  0x0D,  0xC0,  0x5A,  0x40,  0x5C,  0x38,  0x54,  0x00,  0xCD,  0x01,  0xCC,  0x4A,  0x46,
+  0x0A,  0x13,  0x83,  0x59,  0x00,  0x4C,  0x01,  0x48,  0x16,  0x13,  0x0C,  0x10,  0xC5,  0x58,  0x00,  0xF2,
+  0xF2,  0x0D,  0x00,  0x4C,  0x01,  0x48,  0x08,  0x13,  0x05,  0xF6,  0xF0,  0x00,  0x05,  0x57,  0x08,  0x10,
+  0x45,  0x58,  0x00,  0xF2,  0xF2,  0x0D,  0x8D,  0x56,  0x83,  0x5A,  0x80,  0x4C,  0x05,  0x17,  0x00,  0x16,
+  0x02,  0x4B,  0x06,  0xF7,  0x04,  0x00,  0x62,  0x0B,  0x03,  0x82,  0x00,  0xF2,  0xDE,  0x0D,  0x02,  0x80,
+  0x00,  0x4C,  0x45,  0xF4,  0x02,  0x00,  0x52,  0x14,  0x06,  0xF7,  0x02,  0x00,  0x06,  0x14,  0x00,  0xF2,
+  0x50,  0x0F,  0x00,  0x16,  0x02,  0x4B,  0x01,  0xF6,  0xFF,  0x00,  0x38,  0x1C,  0x05,  0xF4,  0x04,  0x00,
+  0x83,  0x5A,  0x18,  0xDF,  0x19,  0xDF,  0x1D,  0xF7,  0x3C,  0x00,  0xB8,  0xF0,  0x4A,  0x10,  0x9C,  0x14,
+  0x01,  0x48,  0x1C,  0x13,  0x0E,  0xF7,  0x3C,  0x00,  0x03,  0xF7,  0x04,  0x00,  0xAF,  0x19,  0x03,  0x42,
+  0x45,  0xF4,  0x02,  0x00,  0x83,  0x5A,  0x02,  0xCC,  0x02,  0x41,  0x45,  0xF4,  0x02,  0x00,  0x00,  0x16,
+  0x91,  0x44,  0xD5,  0xF0,  0x3A,  0x10,  0x00,  0xF0,  0x9E,  0x02,  0x01,  0xF6,  0xFF,  0x00,  0x38,  0x1C,
+  0x05,  0xF4,  0x04,  0x00,  0x83,  0x5A,  0x18,  0xDF,  0x19,  0xDF,  0x0E,  0xF7,  0x3C,  0x00,  0x03,  0xF7,
+  0x04,  0x00,  0x0F,  0x79,  0x1C,  0xF7,  0x3C,  0x00,  0xB8,  0xF0,  0x98,  0x10,  0x4E,  0x14,  0x01,  0x48,
+  0x06,  0x13,  0x45,  0xF4,  0x04,  0x00,  0x00,  0x16,  0x91,  0x44,  0xD5,  0xF0,  0x7E,  0x10,  0x00,  0xF0,
+  0x9E,  0x02,  0x02,  0xF6,  0xFF,  0x00,  0x38,  0x1C,  0x2C,  0xBC,  0xAE,  0xBC,  0xE2,  0x08,  0x00,  0xEC,
+  0xB8,  0x00,  0x02,  0x48,  0x1D,  0xF7,  0x80,  0x00,  0xB8,  0xF0,  0xC8,  0x10,  0x1E,  0x14,  0x01,  0x48,
+  0x0E,  0x13,  0x0E,  0xF7,  0x80,  0x00,  0x38,  0x54,  0x03,  0x58,  0xAF,  0x19,  0x82,  0x48,  0x00,  0x16,
+  0x82,  0x48,  0x12,  0x45,  0xD5,  0xF0,  0xB6,  0x10,  0x00,  0xF0,  0x9E,  0x02,  0x39,  0xF0,  0xF4,  0x10,
+  0x38,  0x44,  0x00,  0x16,  0x7E,  0x18,  0x18,  0xF4,  0x03,  0x00,  0x04,  0x13,  0x61,  0x18,  0x00,  0x16,
+  0x38,  0x1C,  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0xF1,  0x12,  0xE3,  0x10,  0x30,  0x44,
+  0x30,  0x44,  0x30,  0x44,  0xB1,  0xF0,  0x14,  0x11,  0x00,  0x16,  0x3E,  0x57,  0x03,  0xF6,  0xE0,  0x00,
+  0x03,  0x57,  0x83,  0x59,  0x04,  0xCC,  0x01,  0x4A,  0x6A,  0x12,  0x45,  0x5A,  0x00,  0xF2,  0xF2,  0x0D,
+  0x02,  0x4B,  0x70,  0x14,  0x34,  0x13,  0x02,  0x80,  0x48,  0xE4,  0x08,  0x00,  0x18,  0x12,  0x9C,  0xE7,
+  0x02,  0x00,  0x9E,  0xE7,  0x15,  0x00,  0x00,  0xF2,  0xC2,  0x0F,  0x00,  0xF2,  0x76,  0x0A,  0x1E,  0x1C,
+  0x01,  0xF6,  0x01,  0x00,  0x00,  0x16,  0x30,  0xE4,  0x10,  0x00,  0x04,  0x40,  0x00,  0xF2,  0xDE,  0x0D,
+  0x20,  0xE7,  0x01,  0x00,  0x01,  0xF6,  0x01,  0x00,  0x00,  0x16,  0x04,  0xDC,  0x01,  0x4A,  0x24,  0x12,
+  0x45,  0x5A,  0x00,  0xF2,  0xF2,  0x0D,  0x43,  0x5B,  0x06,  0xEC,  0x98,  0x00,  0x00,  0xF2,  0x34,  0x10,
+  0xC6,  0x59,  0x20,  0x14,  0x0A,  0x13,  0x00,  0xF2,  0xC2,  0x0F,  0x00,  0xF2,  0x10,  0x10,  0xA7,  0x10,
+  0x83,  0x5A,  0xD7,  0x10,  0x0E,  0x47,  0x07,  0xE6,  0x10,  0x00,  0xCE,  0x47,  0x5A,  0xF0,  0x1C,  0x11,
+  0xB9,  0x54,  0x00,  0x16,  0x14,  0x90,  0x96,  0x90,  0x02,  0xFC,  0xA8,  0x00,  0x03,  0xFC,  0xAA,  0x00,
+  0x48,  0x55,  0x02,  0x13,  0xC9,  0x55,  0x00,  0x16,  0x00,  0xEC,  0xBA,  0x00,  0x10,  0x44,  0x00,  0xEA,
+  0xBA,  0x00,  0x00,  0x16,  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x64,  0x0A,  0x10,  0x44,  0x00,  0x4C,
+  0x00,  0x16 };
+
+unsigned short _adv_mcode_size ASC_INITDATA =
+    sizeof(_adv_mcode_buf); /* 0x11D2 */
+unsigned long  _adv_mcode_chksum ASC_INITDATA = 0x0347D07AUL;
+
+/* a_init.c */
+/*
+ * EEPROM Configuration.
+ *
+ * All drivers should use this structure to set the default EEPROM
+ * configuration. The BIOS now uses this structure when it is built.
+ * Additional structure information can be found in a_condor.h where
+ * the structure is defined.
+ */
+STATIC ADVEEP_CONFIG
+Default_EEPROM_Config ASC_INITDATA = {
+    ADV_EEPROM_BIOS_ENABLE,     /* cfg_msw */
+    0x0000,                     /* cfg_lsw */
+    0xFFFF,                     /* disc_enable */
+    0xFFFF,                     /* wdtr_able */
+    0xFFFF,                     /* sdtr_able */
+    0xFFFF,                     /* start_motor */
+    0xFFFF,                     /* tagqng_able */
+    0xFFFF,                     /* bios_scan */
+    0,                          /* scam_tolerant */
+    7,                          /* adapter_scsi_id */
+    0,                          /* bios_boot_delay */
+    3,                          /* scsi_reset_delay */
+    0,                          /* bios_id_lun */
+    0,                          /* termination */
+    0,                          /* reserved1 */
+    0xFFEF,                     /* bios_ctrl */
+    0xFFFF,                     /* ultra_able */
+    0,                          /* reserved2 */
+    ASC_DEF_MAX_HOST_QNG,       /* max_host_qng */
+    ASC_DEF_MAX_DVC_QNG,        /* max_dvc_qng */
+    0,                          /* dvc_cntl */
+    0,                          /* bug_fix */
+    0,                          /* serial_number_word1 */
+    0,                          /* serial_number_word2 */
+    0,                          /* serial_number_word3 */
+    0,                          /* check_sum */
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* oem_name[16] */
+    0,                          /* dvc_err_code */
+    0,                          /* adv_err_code */
+    0,                          /* adv_err_addr */
+    0,                          /* saved_dvc_err_code */
+    0,                          /* saved_adv_err_code */
+    0,                          /* saved_adv_err_addr */
+    0                           /* num_of_err */
+};
+
+/*
+ * Initialize the ADV_DVC_VAR structure.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+ASC_INITFUNC(
+int
+AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+)
+{
+    ushort      warn_code;
+    AdvPortAddr iop_base;
+    uchar       pci_cmd_reg;
+    int         status;
+
+    warn_code = 0;
+    asc_dvc->err_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * PCI Command Register
+     */
+
+    if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
+                            AscPCIConfigCommandRegister))
+         & AscPCICmdRegBits_BusMastering)
+        != AscPCICmdRegBits_BusMastering)
+    {
+        pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
+
+        DvcAdvWritePCIConfigByte(asc_dvc,
+                AscPCIConfigCommandRegister, pci_cmd_reg);
+
+        if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister))
+             & AscPCICmdRegBits_BusMastering)
+            != AscPCICmdRegBits_BusMastering)
+        {
+            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+        }
+    }
+
+    /*
+     * PCI Latency Timer
+     *
+     * If the "latency timer" register is 0x20 or above, then we don't need
+     * to change it.  Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
+     * comes up less than 0x20).
+     */
+    if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
+        DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, 0x20);
+        if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20)
+        {
+            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+        }
+    }
+
+    /*
+     * Save the state of the PCI Configuration Command Register
+     * "Parity Error Response Control" Bit. If the bit is clear (0),
+     * in AdvInitAsc3550Driver() tell the microcode to ignore DMA
+     * parity errors.
+     */
+    asc_dvc->cfg->control_flag = 0;
+    if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
+         & AscPCICmdRegBits_ParErrRespCtrl)) == 0)
+    {
+        asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
+    }
+
+    asc_dvc->cur_host_qng = 0;
+
+    asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
+      ADV_LIB_VERSION_MINOR;
+    asc_dvc->cfg->chip_version =
+      AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+
+    /*
+     * Reset the chip to start and allow register writes.
+     */
+    if (AdvFindSignature(iop_base) == 0)
+    {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+        return ADV_ERROR;
+    }
+    else {
+
+        AdvResetChip(asc_dvc);
+
+        if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR)
+        {
+            return ADV_ERROR;
+        }
+        warn_code |= status;
+
+        /*
+         * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+         * Resets should be performed.
+         */
+        if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+        {
+            AdvResetSCSIBus(asc_dvc);
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Initialize the ASC3550.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+ASC_INITFUNC(
+int
+AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+)
+{
+    AdvPortAddr iop_base;
+    ushort      warn_code;
+    ulong       sum;
+    int         begin_addr;
+    int         end_addr;
+    int         code_sum;
+    int         word;
+    int         rql_addr;                   /* RISC Queue List address */
+    int         i;
+    ushort      scsi_cfg1;
+    uchar       biosmem[ASC_MC_BIOSLEN];    /* BIOS RISC Memory 0x40-0x8F. */
+
+    /* If there is already an error, don't continue. */
+    if (asc_dvc->err_code != 0)
+    {
+        return ADV_ERROR;
+    }
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save the RISC memory BIOS region before writing the microcode.
+     * The BIOS may already be loaded and using its RISC LRAM region
+     * so its region must be saved and restored.
+     *
+     * Note: This code makes the assumption, which is currently true,
+     * that a chip reset does not clear RISC LRAM.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN; i++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+    }
+
+    /*
+     * Load the Microcode
+     *
+     * Write the microcode image to RISC memory starting at address 0.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+    for (word = 0; word < _adv_mcode_size; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base,
+            *((ushort *) (&_adv_mcode_buf[word])));
+    }
+
+    /*
+     * Clear the rest of Condor's Internal RAM (8KB).
+     */
+    for (; word < ADV_CONDOR_MEMSIZE; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base, 0);
+    }
+
+    /*
+     * Verify the microcode checksum.
+     */
+    sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+    for (word = 0; word < _adv_mcode_size; word += 2)
+    {
+        sum += AdvReadWordAutoIncLram(iop_base);
+    }
+
+    if (sum != _adv_mcode_chksum)
+    {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Restore the RISC memory BIOS region.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN; i++)
+    {
+        AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+    }
+
+    /*
+     * Calculate and write the microcode code checksum to the microcode
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).  
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+    code_sum = 0;
+    for (word = begin_addr; word < end_addr; word += 2)
+    {
+        code_sum += *((ushort *) (&_adv_mcode_buf[word]));
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+    /*
+     * Read microcode version and date.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+    /*
+     * Initialize microcode operating variables
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID,
+                       asc_dvc->chip_scsi_id);
+
+    /*
+     * If the PCI Configuration Command Register "Parity Error Response
+     * Control" Bit was clear (0), then set the microcode variable
+     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+     * to ignore DMA parity errors.
+     */
+    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+    {
+        /* 
+         * Note: Don't remove the use of a temporary variable in
+         * the following code, otherwise the Microsoft C compiler
+         * will turn the following lines into a no-op.
+         */
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_IGNORE_PERR;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * Set default microcode operating variables for WDTR, SDTR, and
+     * command tag queuing based on the EEPROM configuration values.
+     *
+     * These ADV_DVC_VAR fields and the microcode variables will be
+     * changed in AdvInquiryHandling() if it is found a device is
+     * incapable of a particular feature.
+     */
+
+    /*
+     * Set the microcode ULTRA target mask from EEPROM value. The
+     * SDTR target mask overrides the ULTRA target mask in the
+     * microcode so it is safe to set this value without determining
+     * whether the device supports SDTR.
+     * 
+     * Note: There is no way to know whether a device supports ULTRA
+     * speed without attempting a SDTR ULTRA speed negotiation with
+     * the device. The device will reject the speed if it does not
+     * support it by responding with an SDTR message containing a
+     * slower speed.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able);
+    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+
+
+    /*
+     * Set SCSI_CFG0 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG0 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+        PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
+  
+    /*
+     * Determine SCSI_CFG1 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+
+    /* Read current SCSI_CFG1 Register value. */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+    /*
+     * If all three connectors are in use, return an error.
+     */
+    if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+        (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
+    {
+        asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If the internal narrow cable is reversed all of the SCSI_CTRL
+     * register signals will be set. Check for and return an error if
+     * this condition is found.
+     */
+    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+    {
+        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If this is a differential board and a single-ended device
+     * is attached to one of the connectors, return an error.
+     */
+    if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0)
+    {
+        asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If automatic termination control is enabled, then set the
+     * termination value based on a table listed in a_condor.h.
+     *
+     * If manual termination was specified with an EEPROM setting
+     * then 'termination' was set-up in AdvInitFromEEP() and
+     * is ready to be 'ored' into SCSI_CFG1.
+     */
+    if (asc_dvc->cfg->termination == 0)
+    {
+        /*
+         * The software always controls termination by setting TERM_CTL_SEL.
+         * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+         */
+        asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+        switch(scsi_cfg1 & CABLE_DETECT)
+        {
+            /* TERM_CTL_H: on, TERM_CTL_L: on */
+            case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
+                asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+                break;
+
+            /* TERM_CTL_H: on, TERM_CTL_L: off */
+            case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
+                asc_dvc->cfg->termination |= TERM_CTL_H;
+                break;
+
+            /* TERM_CTL_H: off, TERM_CTL_L: off */
+            case 0x2: case 0x6:
+                break;
+        }
+    }
+
+    /*
+     * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+     */
+    scsi_cfg1 &= ~TERM_CTL;
+
+    /*
+     * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+     * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+     * referenced, because the hardware internally inverts
+     * the Termination High and Low bits if TERM_POL is set.
+     */
+    scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+
+    /*
+     * Set SCSI_CFG1 Microcode Default Value
+     *
+     * Set filter value and possibly modified termination control
+     * bits in the Microcode SCSI_CFG1 Register Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+                       FLTR_11_TO_20NS | scsi_cfg1);
+
+    /*
+     * Set SEL_MASK Microcode Default Value
+     *
+     * The microcode will set the SEL_MASK register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+    /*
+     * Link all the RISC Queue Lists together in a doubly-linked
+     * NULL terminated list.
+     *
+     * Skip the NULL (0) queue which is not used.
+     */
+    for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE;
+         i < ASC_MC_RISC_Q_TOTAL_CNT;
+         i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE)
+    {
+        /*
+         * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers
+         * in a one word write and set the state (RQL_STATE) to free.
+         */
+        AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8)));
+        AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+    }
+
+    /*
+     * Set the Host and RISC Queue List pointers.
+     *
+     * Both sets of pointers are initialized with the same values:
+     * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF).
+     */
+    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST);
+    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+
+    AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST);
+    AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+
+    /*
+     * Finally, set up the last RISC Queue List (255) with
+     * a NULL forward pointer.
+     */
+    AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8)));
+    AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+         (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+
+    /* 
+     * Note: Don't remove the use of a temporary variable in
+     * the following code, otherwise the Microsoft C compiler
+     * will turn the following lines into a no-op.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ 
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+ASC_INITFUNC(
+STATIC int
+AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
+)
+{
+    AdvPortAddr         iop_base;
+    ushort              warn_code;
+    ADVEEP_CONFIG       eep_config;
+    int                 i;
+
+    iop_base = asc_dvc->iop_base;
+
+    warn_code = 0;
+
+    /*
+     * Read the board's EEPROM configuration.
+     *
+     * Set default values if a bad checksum is found.
+     */
+    if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    {
+        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+        /*
+         * Set EEPROM default values.
+         */
+        for (i = 0; i < sizeof(ADVEEP_CONFIG); i++)
+        {
+            *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_EEPROM_Config + i);
+        }
+
+        /*
+         * Assume the 6 byte board serial number that was read
+         * from EEPROM is correct even if the EEPROM checksum
+         * failed.
+         */
+        eep_config.serial_number_word3 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+        eep_config.serial_number_word2 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+        eep_config.serial_number_word1 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
+        AdvSetEEPConfig(iop_base, &eep_config);
+    }
+
+    /*
+     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * EEPROM configuration that was read.
+     *
+     * This is the mapping of EEPROM fields to Adv Library fields.
+     */
+    asc_dvc->wdtr_able = eep_config.wdtr_able;
+    asc_dvc->sdtr_able = eep_config.sdtr_able;
+    asc_dvc->ultra_able = eep_config.ultra_able;
+    asc_dvc->tagqng_able = eep_config.tagqng_able;
+    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+    asc_dvc->start_motor = eep_config.start_motor;
+    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+    asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay;
+    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+    asc_dvc->no_scam = eep_config.scam_tolerant;
+    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+    /*
+     * Set the host maximum queuing (max. 253, min. 16) and the per device
+     * maximum queuing (max. 63, min. 4).
+     */
+    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+    {
+        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_host_qng == 0)
+        {
+            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+        } else
+        {
+            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+        }
+    }
+
+    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+    {
+        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_dvc_qng == 0)
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+        } else
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+        }
+    }
+
+    /*
+     * If 'max_dvc_qng' is greater than 'max_host_qng', then
+     * set 'max_dvc_qng' to 'max_host_qng'.
+     */
+    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+    {
+        eep_config.max_dvc_qng = eep_config.max_host_qng;
+    }
+
+    /*
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng'
+     * values based on possibly adjusted EEPROM values.
+     */
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+
+    /*
+     * If the EEPROM 'termination' field is set to automatic (0), then set
+     * the ADV_DVC_CFG 'termination' field to automatic also.
+     *
+     * If the termination is specified with a non-zero 'termination'
+     * value check that a legal value is set and set the ADV_DVC_CFG
+     * 'termination' field appropriately.
+     */
+    if (eep_config.termination == 0)
+    {
+        asc_dvc->cfg->termination = 0;    /* auto termination */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination == 1)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination == 2)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination == 3)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+        } else
+        {
+            /*
+             * The EEPROM 'termination' field contains a bad value. Use
+             * automatic termination instead.
+             */
+            asc_dvc->cfg->termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+ASC_INITFUNC(
+STATIC ushort
+AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+)
+{
+    ushort              wval, chksum;
+    ushort              *wbuf;
+    int                 eep_addr;
+
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
+         eep_addr < ASC_EEP_DVC_CFG_END;
+         eep_addr++, wbuf++)
+    {
+        wval = AdvReadEEPWord(iop_base, eep_addr);
+        chksum += wval;
+        *wbuf = wval;
+    }
+    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    wbuf++;
+    for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
+         eep_addr < ASC_EEP_MAX_WORD_ADDR;
+         eep_addr++, wbuf++)
+    {
+        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    }
+    return chksum;
+}
+
+/*
+ * Read the EEPROM from specified location
+ */
+ASC_INITFUNC(
+STATIC ushort
+AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+)
+{
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+        ASC_EEP_CMD_READ | eep_word_addr);
+    AdvWaitEEPCmd(iop_base);
+    return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
+}
+
+/*
+ * Wait for EEPROM command to complete
+ */
+ASC_INITFUNC(
+STATIC void
+AdvWaitEEPCmd(AdvPortAddr iop_base)
+)
+{
+    int eep_delay_ms;
+
+    for (eep_delay_ms = 0; eep_delay_ms < ASC_EEP_DELAY_MS; eep_delay_ms++)
+    {
+        if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE)
+        {
+            break;
+        }
+        DvcSleepMilliSecond(1);
+    }
+    if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0)
+    {
+        ADV_ASSERT(0);
+    }
+    return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+ASC_INITFUNC(
+STATIC void
+AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+)
+{
+    ushort       *wbuf;
+    ushort       addr, chksum;
+
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+    AdvWaitEEPCmd(iop_base);
+
+    /*
+     * Write EEPROM from word 0 to word 15
+     */
+    for (addr = ASC_EEP_DVC_CFG_BEGIN;
+         addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
+    {
+        chksum += *wbuf;
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+        DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+    }
+
+    /*
+     * Write EEPROM checksum at word 18
+     */
+    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+    AdvWaitEEPCmd(iop_base);
+    wbuf++;        /* skip over check_sum */
+
+    /*
+     * Write EEPROM OEM name at words 19 to 26 
+     */
+    for (addr = ASC_EEP_DVC_CTL_BEGIN;
+         addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    {
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+    }
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+    AdvWaitEEPCmd(iop_base);
+    return;
+}
+
+/*
+ * This function resets the chip and SCSI bus
+ *
+ * It is up to the caller to add a delay to let the bus settle after
+ * calling this function.
+ *
+ * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in
+ * AdvInitAsc3550Driver(). Here when doing a write to one of these
+ * registers read first and then write.
+ *
+ * Note: A SCSI Bus Reset can not be done until after the EEPROM
+ * configuration is read to determine whether SCSI Bus Resets
+ * should be performed.
+ */
+ASC_INITFUNC(
+STATIC void
+AdvResetChip(ADV_DVC_VAR *asc_dvc)
+)
+{
+    AdvPortAddr    iop_base;
+    ushort         word;
+    uchar          byte;
+
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Reset Chip.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+    DvcSleepMilliSecond(100);
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+
+    /*
+     * Initialize Chip registers.
+     * 
+     * Note: Don't remove the use of a temporary variable in the following
+     * code, otherwise the Microsoft C compiler will turn the following lines
+     * into a no-op.
+     */
+    byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG);
+    byte |= RAM_SZ_8KB;
+    AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte);
+
+    word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+    word &= ~BIG_ENDIAN;
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word);
+
+    /*
+     * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold
+     * of 128 bytes. This register is only accessible to the host.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        START_CTL_EMFU | READ_CMD_MRM);
+}
+
+/* a_advlib.c */
+/*
+ * Description:
+ *      Send a SCSI request to the ASC3550 chip
+ *
+ * If there is no SG list for the request, set 'sg_entry_cnt' to 0.
+ *
+ * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be
+ * called. It is assumed the caller has already initialized 'sg_real_addr'.
+ *
+ * Return:
+ *      ADV_SUCCESS(1) - the request is in the mailbox
+ *      ADV_BUSY(0) - total request count > 253, try later
+ *      ADV_ERROR(-1) - invalid scsi request Q
+ */
+STATIC int
+AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
+                ADV_SCSI_REQ_Q *scsiq)
+{
+    if (scsiq == (ADV_SCSI_REQ_Q *) 0L)
+    {
+        /* 'scsiq' should never be NULL. */
+        ADV_ASSERT(0);
+        return ADV_ERROR;
+    }
+
+    return AdvSendScsiCmd(asc_dvc, scsiq);
+}
+
+/*
+ * Reset SCSI Bus and purge all outstanding requests.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
+ *
+ * Note: Should always return ADV_TRUE.
+ */
+STATIC int
+AdvResetSB(ADV_DVC_VAR *asc_dvc)
+{
+    int         status;
+
+    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0);
+
+    AdvResetSCSIBus(asc_dvc);
+
+    return status;
+}
+
+/*
+ * Reset SCSI Bus and delay.
+ */
+STATIC void
+AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr    iop_base;
+    ushort         scsi_ctrl;
+
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * The microcode currently sets the SCSI Bus Reset signal while
+     * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above.
+     * But the SCSI Bus Reset Hold Time in the microcode is not deterministic
+     * (it may in fact be for less than the SCSI Spec. minimum of 25 us).
+     * Therefore on return the Adv Library sets the SCSI Bus Reset signal
+     * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
+     * than 25 us.
+     */
+    scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL);
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
+        scsi_ctrl | ADV_SCSI_CTRL_RSTOUT);
+    DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
+        scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT);
+
+    DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
+}
+
+
+/*
+ * Adv Library Interrupt Service Routine
+ *
+ *  This function is called by a driver's interrupt service routine.
+ *  The function disables and re-enables interrupts.
+ *
+ *  When a microcode idle command is completed, the ADV_DVC_VAR
+ *  'idle_cmd_done' field is set to ADV_TRUE.
+ *
+ *  Note: AdvISR() can be called when interrupts are disabled or even
+ *  when there is no hardware interrupt condition present. It will
+ *  always check for completed idle commands and microcode requests.
+ *  This is an important feature that shouldn't be changed because it
+ *  allows commands to be completed from polling mode loops.
+ *
+ * Return:
+ *   ADV_TRUE(1) - interrupt was pending
+ *   ADV_FALSE(0) - no interrupt was pending
+ */
+STATIC int
+AdvISR(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr                 iop_base;
+    uchar                       int_stat;
+    ushort                      next_done_loc, target_bit;
+    int                         completed_q;
+    int                         flags;
+    ADV_SCSI_REQ_Q              *scsiq;
+    ASC_REQ_SENSE               *sense_data;
+    int                         ret;
+
+    flags = DvcEnterCritical();
+    iop_base = asc_dvc->iop_base;
+
+    if (AdvIsIntPending(iop_base))
+    {
+        ret = ADV_TRUE;
+    } else
+    {
+        ret = ADV_FALSE;
+    }
+
+    /* Reading the register clears the interrupt. */
+    int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+
+    if (int_stat & ADV_INTR_STATUS_INTRB)
+    {
+        asc_dvc->idle_cmd_done = ADV_TRUE;
+    }
+
+    /*
+     * Notify the driver of a hardware detected SCSI Bus Reset.
+     */
+    if (int_stat & ADV_INTR_STATUS_INTRC)
+    {
+        if (asc_dvc->sbreset_callback != 0)
+        {
+            (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc);
+        }
+    }
+
+    /*
+     * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC
+     * Queue List request. Its forward pointer (RQL_FWD) points to the
+     * current completed RISC Queue List request.
+     */
+    AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc);
+    next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
+        (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD;
+
+    AdvReadByteLram(iop_base, next_done_loc, completed_q);
+
+    /* Loop until all completed Q's are processed. */
+    while (completed_q != ASC_MC_NULL_Q)
+    {
+        AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q);
+
+        next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
+          (completed_q * ASC_MC_RISC_Q_LIST_SIZE);
+
+        /*
+         * Read the ADV_SCSI_REQ_Q virtual address pointer from
+         * the RISC list entry. The microcode has changed the
+         * ADV_SCSI_REQ_Q physical address to its virtual address.
+         *
+         * Refer to comments at the end of AdvSendScsiCmd() for
+         * more information on the RISC list structure.
+         */
+        {
+            ushort lsw, msw;
+            AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw);
+            AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw);
+
+            scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw);
+        }
+        ADV_ASSERT(scsiq != NULL);
+
+        target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+
+        /*
+         * Clear request microcode control flag.
+         */
+        scsiq->cntl = 0;
+
+        /*
+         * Check Condition handling
+         */
+        if ((scsiq->done_status == QD_WITH_ERROR) &&
+            (scsiq->scsi_status == SS_CHK_CONDITION) &&
+            (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 &&
+            (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN)
+        {
+            /*
+             * Command returned with a check condition and valid
+             * sense data.
+             */
+        }
+        /*
+         * If the command that completed was a SCSI INQUIRY and
+         * LUN 0 was sent the command, then process the INQUIRY
+         * command information for the device.
+         */
+        else if (scsiq->done_status == QD_NO_ERROR &&
+                   scsiq->cdb[0] == SCSICMD_Inquiry &&
+                   scsiq->target_lun == 0)
+        {
+            AdvInquiryHandling(asc_dvc, scsiq);
+        }
+
+        
+        /* Change the RISC Queue List state to free. */
+        AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE);
+
+        /* Get the RISC Queue List forward pointer. */
+        AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q);
+
+        /*
+         * Notify the driver of the completed request by passing
+         * the ADV_SCSI_REQ_Q pointer to its callback function.
+         */
+        ADV_ASSERT(asc_dvc->cur_host_qng > 0);
+        asc_dvc->cur_host_qng--;
+        scsiq->a_flag |= ADV_SCSIQ_DONE;
+        (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq);
+        /*
+         * Note: After the driver callback function is called, 'scsiq'
+         * can no longer be referenced.
+         *
+         * Fall through and continue processing other completed
+         * requests...
+         */
+
+        /*
+         * Disable interrupts again in case the driver inadvertently
+         * enabled interrupts in its callback function.
+         *
+         * The DvcEnterCritical() return value is ignored, because
+         * the 'flags' saved when AdvISR() was first entered will be
+         * used to restore the interrupt flag on exit.
+         */
+        (void) DvcEnterCritical();
+    }
+    DvcLeaveCritical(flags);
+    return ret;
+}
+
+/*
+ * Send an idle command to the chip and wait for completion.
+ *
+ * Interrupts do not have to be enabled on entry.
+ *
+ * Return Values:
+ *   ADV_TRUE - command completed successfully
+ *   ADV_FALSE - command failed
+ */
+STATIC int
+AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
+               ushort idle_cmd,
+               ulong idle_cmd_parameter,
+               int flags)
+{
+    int         last_int_level;
+    ulong       i;
+    AdvPortAddr iop_base;
+    int         ret;
+
+    asc_dvc->idle_cmd_done = 0;
+
+    last_int_level = DvcEnterCritical();
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Write the idle command value after the idle command parameter
+     * has been written to avoid a race condition. If the order is not
+     * followed, the microcode may process the idle command before the
+     * parameters have been written to LRAM.
+     */
+    AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter);
+    AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+    DvcLeaveCritical(last_int_level);
+
+    /*
+     * If the 'flags' argument contains the ADV_NOWAIT flag, then
+     * return with success.
+     */
+    if (flags & ADV_NOWAIT)
+    {
+        return ADV_TRUE;
+    }
+
+    for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++)
+    {
+        /*
+         * 'idle_cmd_done' is set by AdvISR().
+         */
+        if (asc_dvc->idle_cmd_done)
+        {
+            break;
+        }
+        DvcSleepMilliSecond(1);
+
+        /*
+         * If interrupts were disabled on entry to AdvSendIdleCmd(),
+         * then they will still be disabled here. Call AdvISR() to
+         * check for the idle command completion.
+         */
+        (void) AdvISR(asc_dvc);
+    }
+
+    last_int_level = DvcEnterCritical();
+
+    if (asc_dvc->idle_cmd_done == ADV_FALSE)
+    {
+        ADV_ASSERT(0); /* The idle command should never timeout. */
+        return ADV_FALSE;
+    } else
+    {
+        AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret);
+        return ret;
+    }
+}
+
+/*
+ * Send the SCSI request block to the adapter
+ *
+ * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the
+ * following structure:
+ *
+ * 0: RQL_FWD - RISC list forward pointer (1 byte)
+ * 1: RQL_BWD - RISC list backward pointer (1 byte)
+ * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte)
+ * 3: RQL_TID - request target id (1 byte)
+ * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes)
+ *
+ * Return:
+ *      ADV_SUCCESS(1) - the request is in the mailbox
+ *      ADV_BUSY(0) - total request count > 253, try later
+ */
+STATIC int
+AdvSendScsiCmd(
+    ADV_DVC_VAR *asc_dvc,
+    ADV_SCSI_REQ_Q  *scsiq)
+{
+    ushort                 next_ready_loc;
+    uchar                  next_ready_loc_fwd;
+    int                    last_int_level;
+    AdvPortAddr            iop_base;
+    long                   req_size;
+    ulong                  q_phy_addr;
+
+    /*
+     * The ADV_SCSI_REQ_Q 'target_id' field should never be equal
+     * to the host adapter ID or exceed ADV_MAX_TID.
+     */
+    if (scsiq->target_id == asc_dvc->chip_scsi_id ||
+        scsiq->target_id > ADV_MAX_TID)
+    {
+        scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+        scsiq->done_status = QD_WITH_ERROR;
+        return ADV_ERROR;
+    }
+
+    iop_base = asc_dvc->iop_base;
+
+    last_int_level = DvcEnterCritical();
+
+    if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng)
+    {
+        DvcLeaveCritical(last_int_level);
+        return ADV_BUSY;
+    } else
+    {
+        ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT);
+        asc_dvc->cur_host_qng++;
+    }
+
+    /*
+     * Clear the ADV_SCSI_REQ_Q done flag.
+     */
+    scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+
+    /*
+     * Save the original sense buffer length.
+     *
+     * After the request completes 'sense_len' will be set to the residual
+     * byte count of the Auto-Request Sense if a command returns CHECK
+     * CONDITION and the Sense Data is valid indicated by 'host_status' not
+     * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid
+     * Sense Data Length subtract 'sense_len' from 'orig_sense_len'.
+     */
+    scsiq->orig_sense_len = scsiq->sense_len;
+
+    AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc);
+    next_ready_loc = ASC_MC_RISC_Q_LIST_BASE +
+        (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE);
+
+    /*
+     * Write the physical address of the Q to the mailbox.
+     * We need to skip the first four bytes, because the microcode
+     * uses them internally for linking Q's together.
+     */
+    req_size = sizeof(ADV_SCSI_REQ_Q);
+    q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq,
+                    (uchar *) scsiq, &req_size,
+                    ADV_IS_SCSIQ_FLAG);
+    ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr);
+    ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+
+    scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
+
+    /*
+     * The RISC list structure, which 'next_ready_loc' is a pointer
+     * to in microcode LRAM, has the format detailed in the comment
+     * header for this function.
+     *
+     * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request.
+     */
+    AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr);
+
+    /* Write target_id to 'next_ready_loc' request. */
+    AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id);
+
+    /*
+     * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to
+     * the 'next_ready_loc' request forward pointer.
+     *
+     * Do this *before* changing the 'next_ready_loc' queue to QS_READY.
+     * After the state is changed to QS_READY 'RQL_FWD' will be changed
+     * by the microcode.
+     *
+     * NOTE: The temporary variable 'next_ready_loc_fwd' is required to
+     * prevent some compilers from optimizing out 'AdvReadByteLram()' if
+     * it were used as the 3rd argument to 'AdvWriteByteLram()'.
+     */
+    AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd);
+    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd);
+
+    /*
+     * Change the state of 'next_ready_loc' request from QS_FREE to
+     * QS_READY which will cause the microcode to pick it up and
+     * execute it.
+     *
+     * Can't reference 'next_ready_loc' after changing the request
+     * state to QS_READY. The microcode now owns the request.
+     */
+    AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY);
+
+    DvcLeaveCritical(last_int_level);
+    return ADV_SUCCESS;
+}
+
+/*
+ * Inquiry Information Byte 7 Handling
+ *
+ * Handle SCSI Inquiry Command information for a device by setting
+ * microcode operating variables that affect WDTR, SDTR, and Tag 
+ * Queuing.
+ */
+STATIC void
+AdvInquiryHandling(
+    ADV_DVC_VAR          *asc_dvc,
+    ADV_SCSI_REQ_Q       *scsiq)
+{
+    AdvPortAddr          iop_base;
+    uchar                tid;
+    ASC_SCSI_INQUIRY     *inq;
+    ushort               tidmask;
+    ushort               cfg_word;
+
+    /*
+     * AdvInquiryHandling() requires up to INQUIRY information Byte 7
+     * to be available.
+     *
+     * If less than 8 bytes of INQUIRY information were requested or less
+     * than 8 bytes were transferred, then return. cdb[4] is the request
+     * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
+     * microcode to the transfer residual count.
+     */
+    if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8)
+    {
+        return;
+    }
+
+    iop_base = asc_dvc->iop_base;
+    tid = scsiq->target_id;
+    inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr;
+
+    /*
+     * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
+     */
+    if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2)
+    {
+        return;
+    } else
+    {
+        /*
+         * INQUIRY Byte 7 Handling
+         *
+         * Use a device's INQUIRY byte 7 to determine whether it
+         * supports WDTR, SDTR, and Tag Queuing. If the feature
+         * is enabled in the EEPROM and the device supports the
+         * feature, then enable it in the microcode.
+         */
+
+        tidmask = ADV_TID_TO_TIDMASK(tid);
+
+        /*
+         * Wide Transfers
+         *
+         * If the EEPROM enabled WDTR for the device and the device
+         * supports wide bus (16 bit) transfers, then turn on the
+         * device's 'wdtr_able' bit and write the new value to the
+         * microcode.
+         */
+        if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16)
+        {
+            AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+            if ((cfg_word & tidmask) == 0)
+            {
+                cfg_word |= tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+
+                /*
+                 * Clear the microcode "WDTR negotiation" done indicator
+                 * for the target to cause it to negotiate with the new
+                 * setting set above.
+                 */
+                AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+                cfg_word &= ~tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+            }
+        }
+
+        /*
+         * Synchronous Transfers
+         *
+         * If the EEPROM enabled SDTR for the device and the device
+         * supports synchronous transfers, then turn on the device's
+         * 'sdtr_able' bit. Write the new value to the microcode.
+         */
+        if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync)
+        {
+            AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+            if ((cfg_word & tidmask) == 0)
+            {
+                cfg_word |= tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+
+                /*
+                 * Clear the microcode "SDTR negotiation" done indicator
+                 * for the target to cause it to negotiate with the new
+                 * setting set above.
+                 */
+                AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+                cfg_word &= ~tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+            }
+        }
+
+        /*
+         * If the EEPROM enabled Tag Queuing for device and the
+         * device supports Tag Queuing, then turn on the device's
+         * 'tagqng_enable' bit in the microcode and set the microcode
+         * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
+         * value.
+         *
+         * Tag Queuing is disabled for the BIOS which runs in polled
+         * mode and would see no benefit from Tag Queuing. Also by
+         * disabling Tag Queuing in the BIOS devices with Tag Queuing
+         * bugs will at least work with the BIOS.
+         */
+        if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue)
+        {
+            AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+            cfg_word |= tidmask;
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+            AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                asc_dvc->max_dvc_qng);
+        }
+    }
 }
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h
--- v2.0.33/linux/drivers/scsi/advansys.h	Wed Oct 15 15:12:17 1997
+++ linux/drivers/scsi/advansys.h	Wed Jun  3 15:17:48 1998
@@ -1,26 +1,31 @@
-/* $Id: advansys.h,v 1.12 1996/09/23 18:12:02 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.17 1998/01/08 21:23:49 bobf Exp bobf $ */
+
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
- *
- * Copyright (c) 1995-1996 Advanced System Products, Inc.
+ * 
+ * Copyright (c) 1995-1998 Advanced System Products, Inc.
+ * All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that redistributions of source
  * code retain the above copyright notice and this comment without
  * modification.
  *
- * The latest version of this driver is available at the AdvanSys
- * FTP and BBS sites listed below.
+ * There is an AdvanSys Linux WWW page at:
+ *  http://www.advansys.com/linux.html
  *
- * Please send questions, comments, and bug reports to:
- * bobf@advansys.com (Bob Frey)
+ * The latest version of the AdvanSys driver is available at:
+ *  ftp://ftp.advansys.com/pub/linux
+ *
+ * Please send questions, comments, bug reports to:
+ *  bobf@advansys.com (Bob Frey)
  */
 
 #ifndef _ADVANSYS_H
 #define _ADVANSYS_H
 
 /* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
-#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#define ASC_LINUX_VERSION(V, P, S)    (((V) * 65536) + ((P) * 256) + (S))
 
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
@@ -56,84 +61,114 @@
  */
 #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 */ \
+    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 */ \
 }
-#else /* version >= v1.3.0 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
 #define ADVANSYS { \
-	NULL,					/* struct SHT *next */ \
-	NULL,					/* long *usage_count */ \
-	&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 */ \
+    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 */
+#else /* version >= v2.1.75 */
+#define ADVANSYS { \
+    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, \
+}
+#endif /* version >= v2.1.75 */
 #endif /* _ADVANSYS_H */
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
--- v2.0.33/linux/drivers/scsi/aic7xxx/aic7xxx.reg	Tue Dec  2 13:52:31 1997
+++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Wed Jun  3 15:17:48 1998
@@ -10,10 +10,7 @@
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
@@ -393,6 +390,27 @@
 }
 
 /*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection.  On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+	address			0x01b
+	access_mode RW
+	bit	SOFT1		0x80
+	bit	SOFT0		0x40
+	bit	SOFTCMDEN	0x20	
+	bit	HAS_BRDCTL	0x10	/* External Board control */
+	bit	SEEPROM		0x08	/* External serial eeprom logic */
+	bit	EEPROM		0x04	/* Writable external BIOS ROM */
+	bit	ROM		0x02	/* Logic for accessing external ROM */
+	bit	SSPIOCPS	0x01	/* Termination and cable detection */
+}
+
+/*
  * SCSI Block Control (p. 3-32)
  * Controls Bus type and channel selection.  In a twin channel configuration
  * addresses 0x00-0x1e are gated to the appropriate channel based on this
@@ -622,26 +640,19 @@
 	mask	NO_IDENT	0x20|SEQINT	/* no IDENTIFY after reconnect*/
 	mask	NO_MATCH	0x30|SEQINT	/* no cmd match for reconnect */
 	mask	EXTENDED_MSG	0x40|SEQINT	/* Extended message received */
-	mask	NO_MATCH_BUSY	0x50|SEQINT	/* Couldn't find BUSY SCB */
+	mask	ABORT_REQUESTED 0x50|SEQINT	/* Reconect of aborted SCB */
 	mask	REJECT_MSG	0x60|SEQINT	/* Reject message received */
 	mask	BAD_STATUS	0x70|SEQINT	/* Bad status from target */
 	mask	RESIDUAL	0x80|SEQINT	/* Residual byte count != 0 */
-	mask	ABORT_CMDCMPLT	0x91		/*
-						 * Command tagged for abort
-						 * completed successfully.
-						 */
 	mask	AWAITING_MSG	0xa0|SEQINT	/*
 						 * Kernel requested to specify
-                                                 * a message to this target
-                                                 * (command was null), so tell
-                                                 * it that it can fill the
-                                                 * message buffer.
-                                                 */
-	mask	MSG_BUFFER_BUSY	0xc0|SEQINT	/*
-						 * Sequencer wants to use the
-						 * message buffer, but it
-						 * already contains a message
+						 * a message to this target
+						 * (command was null), so tell
+						 * it that it can fill the
+						 * message buffer.
 						 */
+	mask	TRACEPOINT	0xb0|SEQINT
+	mask	TRACEPOINT2	0xc0|SEQINT
 	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
 						 * Target changed phase on us
 						 * when we were expecting
@@ -665,7 +676,10 @@
 register ERROR {
 	address			0x092
 	access_mode RO
-	bit	PARERR		0x08
+	bit	PCIERRSTAT	0x40	/* PCI only */
+	bit	MPARERR		0x20	/* PCI only */
+	bit	DPARERR		0x10	/* PCI only */
+	bit	SQPARERR	0x08
 	bit	ILLOPCODE	0x04
 	bit	ILLSADDR	0x02
 	bit	ILLHADDR	0x01
@@ -677,6 +691,7 @@
 register CLRINT {
 	address			0x092
 	access_mode WO
+	bit	CLRPARERR	0x10	/* PCI only */
 	bit	CLRBRKADRINT	0x08
 	bit	CLRSCSIINT      0x04
 	bit	CLRCMDINT 	0x02
@@ -771,8 +786,6 @@
 		bit	MK_MESSAGE      0x80
 		bit	DISCENB         0x40
 		bit	TAG_ENB		0x20
-		bit	MUST_DMAUP_SCB	0x10
-		bit	ABORT_SCB	0x08
 		bit	DISCONNECTED	0x04
 		mask	SCB_TAG_TYPE	0x03
 	}
@@ -801,10 +814,11 @@
 		size	4
 	}
 	SCB_DATACNT {
-		size	3
-	}
-	SCB_LINKED_NEXT {
-		size	1
+		/*
+		 * Really only 3 bytes, but padded to make
+		 * the kernel's job easier.
+		 */
+		size	4
 	}
 	SCB_CMDPTR {
 		size	4
@@ -924,6 +938,9 @@
 	TARG_SCRATCH {
 		size		16
 	}
+	/*
+	 * Bit vector of targets that have ULTRA enabled.
+	 */
 	ULTRA_ENB {
 		size		2
 	}
@@ -934,14 +951,11 @@
 		size		2
 	}
 	/*
-	 * Length of pending message
+	 * Single byte buffer used to designate the type or message
+	 * to send to a target.
 	 */
-	MSG_LEN	{
-		size		1
-	}
-	/* We reserve 8bytes to store outgoing messages */
 	MSG_OUT {
-		size		8
+		size		1
 	}
 	/* Parameters for DMA Logic */
 	DMAPARAMS {
@@ -956,35 +970,12 @@
 		bit	FIFOFLUSH	0x02
 		bit	FIFORESET	0x01
 	}
-	/*
-	 * Number of SCBs supported by
-	 * this card.
-	 */
-	SCBCOUNT {
-		size		1
-	}
-	/*
-	 * Two's complement of SCBCOUNT
-	 */
-	COMP_SCBCOUNT {
-		size		1
-	}
-	/*
-	 * Mask of bits to test against
-	 * when looking at the Queue Count
-	 * registers.  Works around a bug
-	 * on aic7850 chips. 
-	 */
-	QCNTMASK {
-		size		1
-	}
 	SEQ_FLAGS {
 		size		1
-		bit	RESELECTED	0x80
-		bit	IDENTIFY_SEEN	0x40
-		bit	TAGGED_SCB	0x20
+		bit	IDENTIFY_SEEN	0x80
+		bit	SCBPTR_VALID	0x20
 		bit	DPHASE		0x10
-		bit	PAGESCBS	0x04
+		bit	AMTARGET	0x08
 		bit	WIDE_BUS	0x02
 		bit	TWIN_BUS	0x01
 	}
@@ -996,34 +987,15 @@
 	SAVED_TCL {
 		size		1
 	}
+	/* Working value of the number of SG segments left */
 	SG_COUNT {
 		size		1
 	}
-	/* working value of SG pointer */
+	/* Working value of SG pointer */
 	SG_NEXT	{
 		size		4
 	}
 	/*
-	 * head of list of SCBs awaiting
-	 * selection
-	 */
-	WAITING_SCBH {
-		size		1
-	}
-	SAVED_LINKPTR {
-		size		1
-	}
-	SAVED_SCBPTR {
-		size		1
-	}
-	/*
-	 * The sequencer will stick the frist byte of any rejected message here
-	 * so we can see what is getting thrown away.
-	 */
-	REJBYTE	{
-		size		1
-	}
-	/*
 	 * The last bus phase as seen by the sequencer. 
 	 */
 	LASTPHASE {
@@ -1040,23 +1012,12 @@
 		mask	P_MESGIN	CDI|IOI|MSGI
 		mask	P_BUSFREE	0x01
 	}
-	MSGIN_EXT_LEN {
-		size		1
-	}
-	MSGIN_EXT_OPCODE {
-		size		1
-	}
 	/*
-	 * location 3, stores the last
-	 * byte of an extended message if
-	 * it passes the two bytes of space
-	 * we allow now.  This byte isn't
-	 * used for anything, it just makes
-	 * the code shorter for tossing
-	 * extra bytes.
+	 * head of list of SCBs awaiting
+	 * selection
 	 */
-	MSGIN_EXT_BYTES	{
-		size		3
+	WAITING_SCBH {
+		size		1
 	}
 	/*
 	 * head of list of SCBs that are
@@ -1073,10 +1034,40 @@
 	FREE_SCBH {
 		size		1
 	}
+	/*
+	 * Address of the hardware scb array in the host.
+	 */
 	HSCB_ADDR {
 		size		4
 	}
-	CUR_SCBID {
+	/*
+	 * Address of the 256 byte array storing the SCBID of outstanding
+	 * untagged SCBs indexed by TCL.
+	 */
+	SCBID_ADDR {
+		size		4
+	}
+	/*
+	 * Address of the array of command descriptors used to store
+	 * information about incoming selections.
+	 */
+	TMODE_CMDADDR {
+		size		4
+	}
+	KERNEL_QINPOS {
+		size		1
+	}
+	QINPOS {
+		size		1
+	}
+	QOUTPOS {
+		size		1
+	}
+	/*
+	 * Offset into the command descriptor array for the next
+	 * available desciptor to use.
+	 */
+	TMODE_CMDADDR_NEXT {
 		size		1
 	}
 	ARG_1 {
@@ -1084,30 +1075,13 @@
 		mask	SEND_MSG	0x80
 		mask	SEND_SENSE	0x40
 		mask	SEND_REJ	0x20
+		mask	MSGOUT_PHASEMIS	0x10
 		alias	RETURN_1
 	}
 	/*
-	 * Running count of commands placed in
-	 * the QOUTFIFO.  This is cleared by the
-	 * kernel driver every FIFODEPTH commands.
-	 *
-	 * NOTE: These scratch RAM registers are overlaying SCSICONF
-	 *       and SCSICONF2 and are only used on cards that are
-	 *       capable of SCB paging.   Currently, only the PCI
-	 *       controllers can do this, which is good because the
-	 *       AIC-7770 based controllers use the SCSICONF register
-	 *       to control termination.  In other words, do not
-	 *       destroy the contents of SCSICONF and SCSICONF2 for
-	 *       AIC-7770 based controllers.
+	 * Snapshot of MSG_OUT taken after each message is sent.
 	 */
-	CMDOUTCNT {
-		size		1
-	}
-	/*
-	 * Maximum number of entries allowed in
-	 * the QOUT/INFIFO.
-	 */
-	FIFODEPTH {
+	LAST_MSG {
 		size		1
 	}
 	/*
@@ -1118,12 +1092,10 @@
 	SCSICONF {
 		address		0x05a
 		size		1
+		bit	TERM_ENB	0x80
 		bit	RESET_SCSI	0x40
-	}
-        SCSICONF2 {
-		address		0x05b
-		size		1
-		bit	RESET_SCSI	0x40
+		mask	HSCSIID		0x07	/* our SCSI ID */
+		mask	HWSCSIID	0x0f	/* our SCSI ID if Wide Bus */
 	}
 	HOSTCONF {
 		address		0x05d
@@ -1140,6 +1112,10 @@
 
 const SCB_LIST_NULL	0xff
 
+/* Offsets into the SCBID array where different data is stored */
+const UNTAGGEDSCB_OFFSET	0
+const QOUTFIFO_OFFSET		1
+const QINFIFO_OFFSET		2
 
 /* WDTR Message values */
 const BUS_8_BIT		0x00
@@ -1147,3 +1123,24 @@
 const BUS_32_BIT		0x02
 const MAX_OFFSET_8BIT		0x0f
 const MAX_OFFSET_16BIT	0x08
+const HOST_MSG		0xFF
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT	0x05
+const CMD_GROUP0_BYTE_DELTA	-4
+const CMD_GROUP2_BYTE_DELTA	-6
+const CMD_GROUP4_BYTE_DELTA	4
+const CMD_GROUP5_BYTE_DELTA	11
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+/*
+ * Mask of bits to test against when looking at the Queue Count
+ * registers.  Works around a bug on aic7850 chips. 
+ */
+const QCNTMASK		download
+/*
+ * Number of command descriptors in the command descriptor array.
+ */
+const TMODE_NUMCMDS	download
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
--- v2.0.33/linux/drivers/scsi/aic7xxx/aic7xxx.seq	Tue Mar 10 13:19:09 1998
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Wed Jun  3 15:17:48 1998
@@ -10,10 +10,7 @@
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
@@ -38,8 +35,8 @@
  *	$Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
  */
 
-#include <aic7xxx.reg>
-#include <scsi_message.h>
+#include "aic7xxx.reg"
+#include "scsi_message.h"
 
 /*
  * A few words on the waiting SCB list:
@@ -59,18 +56,21 @@
  * automatically consume the entries.
  */
 
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
 reset:
 	clr	SCSISIGO;		/* De-assert BSY */
 	/* Always allow reselection */
+.if ( TARGET_MODE )
+	mvi	SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+.else
 	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;
+.endif
 	call	clear_target_state;
+	and	SXFRCTL0, ~SPIOEN;
 poll_for_work:
-	test	SSTAT0,SELDO	jnz select;
-	test	SSTAT0,SELDI	jnz reselect;
+	mov	A, QINPOS;
+poll_for_work_loop:
+	and	SEQCTL, ~PAUSEDIS;
+	test	SSTAT0, SELDO|SELDI	jnz selection;
 	test	SCSISEQ, ENSELO	jnz poll_for_work;
 .if ( TWIN_CHANNEL )
 	/*
@@ -80,16 +80,17 @@
 	 * either a selection or reselection occurs.
 	 */
 	xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
-	test	SSTAT0,SELDO	jnz select;
-	test	SSTAT0,SELDI	jnz reselect;
+	test	SSTAT0, SELDO|SELDI	jnz selection;
 	test	SCSISEQ, ENSELO	jnz poll_for_work;
 	xor	SBLKCTL,SELBUSB;	/* Toggle back */
 .endif
 	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
 test_queue:
 	/* Has the driver posted any work for us? */
-	mov	A, QCNTMASK;
-	test	QINCNT,A	jz poll_for_work;
+	or	SEQCTL, PAUSEDIS;
+	cmp	KERNEL_QINPOS, A je poll_for_work_loop;
+	inc	QINPOS;
+	and	SEQCTL, ~PAUSEDIS;
 
 /*
  * We have at least one queued SCB now and we don't have any 
@@ -99,76 +100,24 @@
  */
 .if ( SCB_PAGING )
 	mov	ALLZEROS	call	get_free_or_disc_scb;
-	cmp	SINDEX, SCB_LIST_NULL	je poll_for_work;
 .endif
 dequeue_scb:
-	mov	CUR_SCBID,QINFIFO;
+	add	A, -1, QINPOS;
+	mvi	QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+	call	dma_finish;
+	mov	SINDEX, DFDAT;
 .if !( SCB_PAGING )
 	/* In the non-paging case, the SCBID == hardware SCB index */
-	mov	SCBPTR, CUR_SCBID;
+	mov	SCBPTR, SINDEX;
 .endif
 dma_queued_scb:
 /*
  * DMA the SCB from host ram into the current SCB location.
  */
 	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-	mov	CUR_SCBID	call dma_scb;
-
-/*
- * See if there is not already an active SCB for this target.  This code
- * locks out on a per target basis instead of target/lun.  Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands.  We also don't have enough spare SCB space for us to store the
- * SCBID of the currently busy transaction for each target/lun making it
- * impossible to link up the SCBs.
- */
-test_busy:
-	test	SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
-	mvi	SEQCTL, PAUSEDIS|FASTMODE;
-	mov	SAVED_SCBPTR, SCBPTR;
-	mov	SCB_TCL		call	index_untagged_scb;
-	mov	ARG_1, SINDIR;			/*
-						 * ARG_1 should
-						 * now have the SCB ID of
-						 * any active, non-tagged,
-						 * command for this target.
-						 */
-	cmp	ARG_1, SCB_LIST_NULL je make_busy;
-.if ( SCB_PAGING )
-	/*
-	 * Put this SCB back onto the free list.  It
-	 * may be necessary to satisfy the search for
-	 * the active SCB.
-	 */
-	mov	SCBPTR, SAVED_SCBPTR;
-	call	add_scb_to_free_list;
-	/* Find the active SCB */
-	mov	ALLZEROS	call findSCB;
-	/*
-	 * If we couldn't find it, tell the kernel.  This should
-	 * never happen.
-	 */
-	cmp	SINDEX, SCB_LIST_NULL	jne paged_busy_link;
-	mvi	INTSTAT, NO_MATCH_BUSY;
-paged_busy_link:
-	/* Link us in */
-	mov	SCB_LINKED_NEXT, CUR_SCBID;
-	/* Put it back on the disconnected list */
-	call	add_scb_to_disc_list;
-	mvi	SEQCTL, FASTMODE;
-	jmp	poll_for_work;
-.else
-simple_busy_link:
-	mov	SCBPTR, ARG_1;
-	mov	SCB_LINKED_NEXT, CUR_SCBID;
-	mvi	SEQCTL, FASTMODE;
-	jmp	poll_for_work;
-.endif
-make_busy:
-	mov	DINDIR, CUR_SCBID;
-	mov	SCBPTR, SAVED_SCBPTR;
-	mvi	SEQCTL, FASTMODE;
+	call	dma_scb;
 
 start_scb:
 	/*
@@ -179,9 +128,7 @@
 	mov	WAITING_SCBH, SCBPTR;
 start_waiting:
 	/*
-	 * Pull the first entry off of the waiting SCB list
-	 * We don't have to "test_busy" because only transactions that
-	 * have passed that test can be in the WAITING_SCB list.
+	 * Pull the first entry off of the waiting SCB list.
 	 */
 	mov	SCBPTR, WAITING_SCBH;
 	call	start_selection;
@@ -199,17 +146,170 @@
 	and	SCSIID, OID;		/* Clear old target */
 	or	SCSIID, A;
 	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ * SINDEX should contain any additional bit's the client wants
+ * set in SXFRCTL0.
+ */
+initialize_channel:
+	or	A, CLRSTCNT|CLRCHN, SINDEX;
+	or	SXFRCTL0, A;
+.if ( ULTRA )
+ultra:
+	mvi	SINDEX, ULTRA_ENB+1;
+	test	SAVED_TCL, 0x80		jnz ultra_2;	/* Target ID > 7 */
+	dec	SINDEX;
+ultra_2:
+	mov     FUNCTION1,SAVED_TCL;
+	mov     A,FUNCTION1;
+	test	SINDIR, A	jz ndx_dtr;
+	or	SXFRCTL0, FAST20;
+.endif
+ 
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCRATCH.
+ */
+ndx_dtr:
+	shr	A,4,SAVED_TCL;
+	test	SBLKCTL,SELBUSB	jz ndx_dtr_2;
+	or	SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
+	or	A,0x08;			/* Channel B entries add 8 */
+ndx_dtr_2:
+	add	SINDEX,TARG_SCRATCH,A;
+	mov	SCSIRATE,SINDIR ret;
+
+
+selection:
+	test	SSTAT0,SELDO	jnz select_out;
+select_in:
+.if ( TARGET_MODE )
+	test	SSTAT0, TARGET	jz initiator_reselect;
+	/*
+	 * We've just been selected.  Assert BSY and
+	 * setup the phase for receiving the messages
+	 * from the target.
+	 */
+	mvi	SCSISIGO, P_MESGOUT|BSYO;
+	mvi	CLRSINT0, CLRSELDO;
+
+	/*
+	 * If ATN isn't asserted, go directly to bus free.
+	 */
+	test	SCSISIGI, ATNI	jz	target_busfree;
+
+	/*
+	 * Setup the DMA for sending the identify and
+	 * command information.
+	 */
+	mov	A, TMODE_CMDADDR_NEXT;
+	mvi	TMODE_CMDADDR call set_32byte_haddr_and_clrcnt;
+	mvi	DFCNTRL, FIFORESET;
+
+	clr	SINDEX;
+	/* Watch ATN closely now */
+message_loop:
+	or	SXFRCTL0, SPIOEN;
+	test	SSTAT0, SPIORDY jz .;
+	and	SXFRCTL0, ~SPIOEN;
+	mov	DINDEX, SCSIDATL;
+	mov	DFDAT, DINDEX;
+	inc	SINDEX;
+
+	/* Message Testing... */
+	test	DINDEX, MSG_IDENTIFYFLAG jz . + 2;
+	mov	ARG_1, DINDEX;
+
+	test	SCSISIGI, ATNI	jnz	message_loop;
+	add	A, -4, SINDEX;
+	jc	target_cmdphase;
+	mvi	DFDAT, SCB_LIST_NULL;	/* Terminate the message list */
+
+target_cmdphase:
+	add	HCNT[0], 1, A;
+	mvi	SCSISIGO, P_COMMAND|BSYO;
+	or	SXFRCTL0, SPIOEN;
+	test	SSTAT0, SPIORDY jz .;
+	mov	A, SCSIDATL;
+	mov	DFDAT, A;	/* Store for host */
+
+	/*
+	 * Determine the number of bytes to read
+	 * based on the command group code.  Count is
+	 * one less than the total since we've already
+	 * fetched the first byte.
+	 */
+	clr	SINDEX;
+	shr	A, CMD_GROUP_CODE_SHIFT;
+	add	SEQADDR0, A;
+
+	add	SINDEX, CMD_GROUP0_BYTE_DELTA;
+	nop;	/* Group 1 and 2 are the same */
+	add	SINDEX, CMD_GROUP2_BYTE_DELTA;
+	nop;	/* Group 3 is reserved */
+	add	SINDEX, CMD_GROUP4_BYTE_DELTA;
+	add	SINDEX, CMD_GROUP5_BYTE_DELTA;
+		/* Group 6 and 7 are not handled yet */
+
+	mov	A, SINDEX;
+	add	HCNT[0], A;
+
+command_loop:
+	test	SSTAT0, SPIORDY jz .;
+	cmp	SINDEX, 1 jne . + 2;
+	and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
+	mov	DFDAT, SCSIDATL;
+	dec	SINDEX;
+	test	SINDEX, 0xFF jnz command_loop;
+
+	or	DFCNTRL, HDMAEN|FIFOFLUSH;
+	
+	call	dma_finish;
+
+	test	ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
+
+	mvi	SCSISIGO, P_MESGIN|BSYO;
+
+	or	SXFRCTL0, SPIOEN;
+
+	mvi	MSG_DISCONNECT call target_outb;
+	
+selectin_post:
+	inc	TMODE_CMDADDR_NEXT;
+	cmp	TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
+	clr	TMODE_CMDADDR_NEXT;
+	mvi	QOUTFIFO, SCB_LIST_NULL;
+	mvi	INTSTAT,CMDCMPLT;
+
+	test	ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
+
+	/* Busy loop on something then go to data or status phase */
+
+target_busfree:
+	clr	SCSISIGO;
+	jmp	poll_for_work;
+
+.endif /* TARGET_MODE */
 /*
  * Reselection has been initiated by a target. Make a note that we've been
  * reselected, but haven't seen an IDENTIFY message from the target yet.
  */
-reselect:
-	clr	MSG_LEN;	/* Don't have anything in the mesg buffer */
+initiator_reselect:
 	mvi	CLRSINT0, CLRSELDI;
 	/* XXX test for and handle ONE BIT condition */
 	and	SAVED_TCL, SELID_MASK, SELID;
-	or	SEQ_FLAGS,RESELECTED;
-	jmp	select2;
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;		/*
+						 * We aren't expecting a
+						 * bus free, so interrupt
+						 * the kernel driver if it
+						 * happens.
+						 */
+	mvi	SPIOEN call	initialize_channel;
+	mvi	MSG_OUT, MSG_NOOP;		/* No message to send */
+	jmp	ITloop;
 
 /*
  * After the selection, remove this SCB from the "waiting SCB"
@@ -217,7 +317,7 @@
  * WAITING_SCBH.  Our next pointer will be set to null the next time this
  * SCB is used, so don't bother with it now.
  */
-select:
+select_out:
 	/* Turn off the selection hardware */
 	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;	/*
 						 * ATN on parity errors
@@ -227,41 +327,6 @@
 	mov	SCBPTR, WAITING_SCBH;
 	mov	WAITING_SCBH,SCB_NEXT;
 	mov	SAVED_TCL, SCB_TCL;
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted.  Prepare
- * the message to send.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
-
-mk_identify:
-	and	MSG_OUT,0x7,SCB_TCL;	/* lun */
-	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
-	or	MSG_OUT,A;		/* or in disconnect privledge */
-	or	MSG_OUT,MSG_IDENTIFYFLAG;
-	mvi	MSG_LEN, 1;
-
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-mk_tag:
-	test	SCB_CONTROL,TAG_ENB jz  mk_message;
-	and	MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
-	mov	MSG_OUT[2],SCB_TAG;
-	add	MSG_LEN,2;	/* update message length */
-
-/*
- * Interrupt the driver, and allow it to tweak the message buffer
- * if it asks.
- */
-mk_message:
-	test	SCB_CONTROL,MK_MESSAGE  jz select2;
-	mvi     INTSTAT,AWAITING_MSG;
-
-select2:
 	mvi	CLRSINT1,CLRBUSFREE;
 	or	SIMODE1, ENBUSFREE;		/*
 						 * We aren't expecting a
@@ -269,54 +334,24 @@
 						 * the kernel driver if it
 						 * happens.
 						 */
+	mvi	SPIOEN call	initialize_channel;
 /*
- * Initialize Ultra mode setting and clear the SCSI channel.
- */
-	or	SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
-.if ( ULTRA )
-ultra:
-	mvi	SINDEX, ULTRA_ENB+1;
-	test	SAVED_TCL, 0x80		jnz ultra_2;	/* Target ID > 7 */
-	dec	SINDEX;
-ultra_2:
-	mov     FUNCTION1,SAVED_TCL;
-	mov     A,FUNCTION1;
-	test	SINDIR, A	jz ndx_dtr;
-	or	SXFRCTL0, FAST20;
-.endif
- 
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- * The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCRATCH.
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
  */
-ndx_dtr:
-	shr	A,4,SAVED_TCL;
-	test	SBLKCTL,SELBUSB	jz ndx_dtr_2;
-	or	SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
-	or	A,0x08;			/* Channel B entries add 8 */
-ndx_dtr_2:
-	add	SINDEX,TARG_SCRATCH,A;
-	mov	SCSIRATE,SINDIR;
-
+	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
+	or	SEQ_FLAGS, IDENTIFY_SEEN;
 
 /*
- * Main loop for information transfer phases.  If BSY is false, then
- * we have a bus free condition, expected or not.  Otherwise, wait
- * for the target to assert REQ before checking MSG, C/D and I/O
- * for the bus phase.
- *
+ * Main loop for information transfer phases.  Wait for the target
+ * to assert REQ before checking MSG, C/D and I/O for the bus phase.
  */
 ITloop:
-	test	SSTAT1,REQINIT		jz ITloop;
-	test	SSTAT1, SCSIPERR	jnz ITloop;
+	call	phase_lock;
 
-	and	A,PHASE_MASK,SCSISIGI;
-	mov	LASTPHASE,A;
-	mov	SCSISIGO,A;
+	mov	A, LASTPHASE;
 
-	cmp	ALLZEROS,A	je p_dataout;
-	cmp	A,P_DATAIN	je p_datain;
+	test	A, ~P_DATAIN	jz p_data;
 	cmp	A,P_COMMAND	je p_command;
 	cmp	A,P_MESGOUT	je p_mesgout;
 	cmp	A,P_STATUS	je p_status;
@@ -329,25 +364,27 @@
 	and	SIMODE1, ~ENBUSFREE;
 	call	clear_target_state;
 	mov	NONE, SCSIDATL;		/* Ack the last byte */
+	and	SXFRCTL0, ~SPIOEN;
 	test	SSTAT1,REQINIT|BUSFREE	jz .;
 	test	SSTAT1, BUSFREE jnz poll_for_work;
 	mvi	INTSTAT, BAD_PHASE;
 	
 clear_target_state:
-	clr	DFCNTRL;
+	clr	DFCNTRL;		/*
+					 * We assume that the kernel driver
+					 * may reset us at any time, even
+					 * in the middle of a DMA, so clear
+					 * DFCNTRL too.
+					 */
 	clr	SCSIRATE;		/*
 					 * We don't know the target we will
 					 * connect to, so default to narrow
 					 * transfers to avoid parity problems.
 					 */
-	and	SXFRCTL0, ~FAST20;	
+	and	SXFRCTL0, ~(FAST20);
 	mvi	LASTPHASE, P_BUSFREE;
 	/* clear target specific flags */
-	and	SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
-
-p_dataout:
-	mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
-	jmp	data_phase_init;
+	and	SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
 
 /*
  * If we re-enter the data phase after going through another phase, the
@@ -358,9 +395,10 @@
 	mvi	SCB_RESID_DCNT	call bcopy_3;
 	jmp	data_phase_loop;
 
-p_datain:
+p_data:
 	mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
-data_phase_init:
+	test	LASTPHASE, IOI jnz . + 2;
+	or	DMAPARAMS, DIRECTION;
 	call	assert;			/*
 					 * Ensure entering a data
 					 * phase is okay - seen identify, etc.
@@ -398,6 +436,7 @@
 	mvi	HCNT[1], 0xff;
 	mvi	HCNT[2], 0xff;
 	call	set_stcnt_from_hcnt;
+	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
 
 data_phase_inbounds:
 /* If we are the last SG block, ensure wideodd is off. */
@@ -512,54 +551,85 @@
 	jmp	ITloop;
 
 /*
- * Message out phase.  If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
+ * Message out phase.  If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target.  In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the hsot to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
  */
 p_mesgout:
-	test	MSG_LEN, 0xff	jnz  p_mesgout_start;
-	mvi	MSG_NOOP	call mk_mesg;	/* build NOP message */
-p_mesgout_start:
-/*
- * Set up automatic PIO transfer from MSG_OUT.  Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
- */
-	mvi	SINDEX,MSG_OUT;
-	mov	DINDEX,MSG_LEN;
-
-/*
- * When target asks for a byte, drop ATN if it's the last one in
- * the message.  Otherwise, keep going until the message is exhausted.
- * ATN must be dropped *at least* 90ns before we ack the last byte, so
- * the code is aranged to execute two instructions before the byte is
- * transferred to give a good margin of safety
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
+	mov	SINDEX, MSG_OUT;
+	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+p_mesgout_identify:
+.if ( WIDE )
+	and	SINDEX,0xf,SCB_TCL;	/* lun */
+.else
+	and	SINDEX,0x7,SCB_TCL;	/* lun */
+.endif
+	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
+	or	SINDEX,A;		/* or in disconnect privledge */
+	or	SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+	test	SCB_CONTROL,MK_MESSAGE  jz p_mesgout_tag;
+	mov	SCSIDATL, SINDEX;	/* Send the last byte */
+	jmp	p_mesgout_from_host + 1;/* Skip HOST_MSG test */
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
  */
-p_mesgout_loop:
-	test	SSTAT1, REQINIT		jz p_mesgout_loop;
-	test	SSTAT1, SCSIPERR	jnz p_mesgout_loop;
-	and	LASTPHASE, PHASE_MASK, SCSISIGI;
-	cmp	LASTPHASE, P_MESGOUT jne p_mesgout_done;
-p_mesgout_testretry:
-	test	DINDEX,0xff	jnz p_mesgout_dropatn;
-	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
-	jmp	p_mesgout_start;
+p_mesgout_tag:
+	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+	mov	SCSIDATL, SINDEX;	/* Send the identify message */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	mov	SCB_TAG	jmp p_mesgout_onebyte;
+/*
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
+ */
+p_mesgout_from_host:
+	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
+	mvi     INTSTAT,AWAITING_MSG;
+	/*
+	 * Did the host detect a phase change?
+	 */
+	cmp	RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+
+p_mesgout_onebyte:
+	mvi	CLRSINT1, CLRATNO;
+	mov	SCSIDATL, SINDEX;
+
 /*
  * If the next bus phase after ATN drops is a message out, it means
  * that the target is requesting that the last message(s) be resent.
  */
-p_mesgout_dropatn:
-	cmp	DINDEX,1	jne p_mesgout_outb;	/* last byte? */
-	mvi	CLRSINT1,CLRATNO;			/* drop ATN */
-p_mesgout_outb:
-	dec	DINDEX;
-	mov	SCSIDATL,SINDIR;
-	jmp	p_mesgout_loop;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+	jmp	p_mesgout;
 
 p_mesgout_done:
 	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
-	clr	MSG_LEN;		/* no active msg */
+	mov	LAST_MSG, MSG_OUT;
+	cmp	MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
 	jmp	ITloop;
 
 /*
@@ -567,7 +637,6 @@
  */
 p_mesgin:
 	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
-	mov	REJBYTE,A;			/* save it for the driver */
 
 	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
 	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
@@ -597,8 +666,8 @@
 /*
  * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
  * and trigger a completion interrupt.  Before doing so, check to see if there
- * is a residual or the status byte is something other than NO_ERROR (0).  In
- * either of these conditions, we upload the SCB back to the host so it can
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
  * process this information.  In the case of a non zero status byte, we 
  * additionally interrupt the kernel driver synchronously, allowing it to
  * decide if sense should be retrieved.  If the kernel driver wishes to request
@@ -616,60 +685,17 @@
  * First check for residuals
  */
 	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
-	test	SCB_TARGET_STATUS,0xff	jz status_ok;	/* Good Status? */
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Good Status? */
 upload_scb:
 	mvi	DMAPARAMS, FIFORESET;
 	mov	SCB_TAG		call dma_scb;
 check_status:
-	test	SCB_TARGET_STATUS,0xff	jz status_ok;	/* Just a residual? */
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Just a residual? */
 	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
-	cmp	RETURN_1, SEND_SENSE	jne status_ok;
+	cmp	RETURN_1, SEND_SENSE	jne complete;
 	/* This SCB becomes the next to execute as it will retrieve sense */
-	mov	SCB_LINKED_NEXT, SCB_TAG;
-	jmp	dma_next_scb;
-
-status_ok:
-/* First, mark this target as free. */
-	test	SCB_CONTROL,TAG_ENB jnz complete;	/*
-							 * Tagged commands
-							 * don't busy the
-							 * target.
-							 */
-	mov	SAVED_SCBPTR, SCBPTR;
-	mov	SAVED_LINKPTR, SCB_LINKED_NEXT;
-	mov	SCB_TCL	call index_untagged_scb;
-	mov	DINDIR, SAVED_LINKPTR;
-	mov	SCBPTR, SAVED_SCBPTR;
-
-complete:
-	/* Post the SCB and issue an interrupt */
-.if ( SCB_PAGING )
-	/*
-	 * Spin loop until there is space
-	 * in the QOUTFIFO.
-	 */
-	mov	A, FIFODEPTH;
-	cmp	CMDOUTCNT, A	je .;
-	inc	CMDOUTCNT;
-.endif
-	mov	QOUTFIFO,SCB_TAG;
-	mvi	INTSTAT,CMDCMPLT;
-	test	SCB_CONTROL, ABORT_SCB jz dma_next_scb;
-	mvi	INTSTAT, ABORT_CMDCMPLT;
-
-dma_next_scb:
-	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list;
-.if !( SCB_PAGING )
-	/* Only DMA on top of ourselves if we are the SCB to download */
-	mov	A, SCB_LINKED_NEXT;
-	cmp	SCB_TAG, A	je dma_next_scb2;
-	call	add_scb_to_free_list;
-	mov	SCBPTR, A;
-	jmp	add_to_waiting_list;
-.endif
-dma_next_scb2:
 	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-	mov	SCB_LINKED_NEXT		call dma_scb;
+	mov	SCB_TAG		call dma_scb;
 add_to_waiting_list:
 	mov	SCB_NEXT,WAITING_SCBH;
 	mov	WAITING_SCBH, SCBPTR;
@@ -679,6 +705,28 @@
 	 */
 	call	start_selection;
 	jmp	await_busfree;
+
+complete:
+	/* If we are untagged, clear our address up in host ram */
+	test	SCB_CONTROL, TAG_ENB jnz complete_post;
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, FIFORESET;
+	mvi	DFDAT, SCB_LIST_NULL;
+	or	DFCNTRL, HDMAEN|FIFOFLUSH;
+	call	dma_finish;
+
+complete_post:
+	/* Post the SCB and issue an interrupt */
+	mov	A, QOUTPOS;
+	mvi	QOUTFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, FIFORESET;
+	mov	DFDAT, SCB_TAG;
+	or	DFCNTRL, HDMAEN|FIFOFLUSH;
+	call	dma_finish;
+	inc 	QOUTPOS;
+	mvi	INTSTAT,CMDCMPLT;
+
 add_to_free_list:
 	call	add_scb_to_free_list;
 	jmp	await_busfree;
@@ -690,22 +738,8 @@
  * or simply to do nothing.
  */
 mesgin_extended:
-	mvi	MSGIN_EXT_LEN	 call inb_next;
-	mov	A, MSGIN_EXT_LEN;
-mesgin_extended_loop:
-	mov	DINDEX	call	inb_next;
-	dec	A;
-	cmp	DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
-	dec	DINDEX;		/* dump by repeatedly filling the last byte */
-mesgin_extended_loop_test:
-	test	A, 0xFF		jnz mesgin_extended_loop;
-mesgin_extended_intr:
 	mvi	INTSTAT,EXTENDED_MSG;		/* let driver know */
-	cmp	RETURN_1,SEND_REJ je rej_mesgin;
-	cmp	RETURN_1,SEND_MSG jne mesgin_done;
-/* The kernel has setup a message to be sent */
-	or	SCSISIGO,ATNO,LASTPHASE;	/* turn on ATNO */
-	jmp	mesgin_done;
+	jmp	ITloop;
 
 /*
  * Is it a disconnect message?  Set a flag in the SCB to remind us
@@ -713,9 +747,7 @@
  */
 mesgin_disconnect:
 	or	SCB_CONTROL,DISCONNECTED;
-.if ( SCB_PAGING )
 	call	add_scb_to_disc_list;
-.endif
 	jmp	await_busfree;
 
 /*
@@ -764,24 +796,30 @@
  * clearing the "disconnected" bit so we don't "find" it by accident later.
  */
 mesgin_identify:
-	test	A,0x78	jnz rej_mesgin;	/*!DiscPriv|!LUNTAR|!Reserved*/
+.if ( WIDE )
+	and	A,0x0f;			/* lun in lower four bits */
+.else
 	and	A,0x07;			/* lun in lower three bits */
+.endif
 	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
-	mov	SAVED_TCL call index_untagged_scb;
-	mov	ARG_1, SINDIR;
+
+	call	get_untagged_SCBID;
+	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
 .if ( SCB_PAGING )
-	cmp	ARG_1,SCB_LIST_NULL	jne use_findSCB;
-.else
-	cmp	ARG_1,SCB_LIST_NULL	je snoop_tag;
-	/* Directly index the SCB */
-	mov	SCBPTR,ARG_1;
-	test	SCB_CONTROL,DISCONNECTED jz not_found;
-	jmp	setup_SCB;
+	test	SEQ_FLAGS, SCBPTR_VALID	jz use_retrieveSCB;
 .endif
+	/*
+	 * If the SCB was found in the disconnected list (as is
+	 * always the case in non-paging scenarios), SCBPTR is already
+	 * set to the correct SCB.  So, simply setup the SCB and get
+	 * on with things.
+	 */
+	mov	SCBPTR	call rem_scb_from_disc_list;
+	jmp	setup_SCB;
 /*
  * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
  * If we get one, we use the tag returned to find the proper
- * SCB.  With SCB paging, this requires using findSCB for both tagged
+ * SCB.  With SCB paging, this requires using search for both tagged
  * and non-tagged transactions since the SCB may exist in any slot.
  * If we're not using SCB paging, we can use the tag as the direct
  * index to the SCB.
@@ -789,44 +827,42 @@
 snoop_tag:
 	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
 snoop_tag_loop:
-	test	SSTAT1,REQINIT		jz snoop_tag_loop;
-	test	SSTAT1, SCSIPERR	jnz snoop_tag_loop;
-	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	call	phase_lock;
 	cmp	LASTPHASE, P_MESGIN	jne not_found;
 	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
 get_tag:
-	or	SEQ_FLAGS, TAGGED_SCB;
 	mvi	ARG_1	call inb_next;	/* tag value */
-/*
- * See if the tag is in range.  The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incomming tag and there is
- * no carry.
- */
-	mov	A,COMP_SCBCOUNT;
-	add	SINDEX,A,ARG_1;
-	jc	not_found;
 
 .if ! ( SCB_PAGING )
 index_by_tag:
 	mov	SCBPTR,ARG_1;
-	mov	A, SAVED_TCL;
-	cmp	SCB_TCL,A		jne not_found;
 	test	SCB_CONTROL,TAG_ENB	jz  not_found;
-	test	SCB_CONTROL,DISCONNECTED jz not_found;
+	mov	SCBPTR	call rem_scb_from_disc_list;
 .else
 /*
  * Ensure that the SCB the tag points to is for an SCB transaction
  * to the reconnecting target.
  */
-use_findSCB:
-	mov	ALLZEROS	call findSCB;	  /* Have to search */
-	cmp	SINDEX, SCB_LIST_NULL	je not_found;
+use_retrieveSCB:
+	call	retrieveSCB;
 .endif
 setup_SCB:
+	mov	A, SAVED_TCL;
+	cmp	SCB_TCL, A	jne not_found_cleanup_scb;
+	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
 	and	SCB_CONTROL,~DISCONNECTED;
 	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
+	/* See if the host wants to send a message upon reconnection */
+	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	HOST_MSG	call mk_mesg;
 	jmp	mesgin_done;
 
+not_found_cleanup_scb:
+	test	SCB_CONTROL, DISCONNECTED jz . + 3;
+	call	add_scb_to_disc_list;
+	jmp	not_found;
+	call	add_scb_to_free_list;
 not_found:
 	mvi	INTSTAT, NO_MATCH;
 	mvi	MSG_BUS_DEV_RESET	call mk_mesg;
@@ -851,23 +887,8 @@
  * if there is no active message already.  SINDEX is returned intact.
  */
 mk_mesg:
-	mvi	SEQCTL, PAUSEDIS|FASTMODE;
-	test	MSG_LEN,0xff	jz mk_mesg1;	/* Should always succeed */
-	
-	/*
-	 * Hmmm.  For some reason the mesg buffer is in use.
-	 * Tell the driver.  It should look at SINDEX to find
-	 * out what we wanted to use the buffer for and resolve
-	 * the conflict.
-	 */
-	mvi	SEQCTL,FASTMODE;
-	mvi	INTSTAT,MSG_BUFFER_BUSY;
-
-mk_mesg1:
 	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
-	mvi	MSG_LEN,1;		/* length = 1 */
-	mov	MSG_OUT,SINDEX;		/* 1-byte message */
-	mvi	SEQCTL,FASTMODE	ret;
+	mov	MSG_OUT,SINDEX ret;
 
 /*
  * Functions to read data in Automatic PIO mode.
@@ -903,6 +924,17 @@
 inb_last:
 	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
 
+.if ( TARGET_MODE )
+/*
+ * Send a byte to an initiator in Automatic PIO mode.
+ * SPIOEN must be on prior to calling this routine.
+ */
+target_outb:
+	mov	SCSIDATL, SINDEX;
+	test	SSTAT0, SPIORDY	jz .;
+	ret;
+.endif
+	
 mesgin_phasemis:
 /*
  * We expected to receive another byte, but the target changed phase
@@ -957,60 +989,114 @@
  * message.
  */
 assert:
-	test	SEQ_FLAGS,RESELECTED	jz return;	/* reselected? */
 	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
 
 	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
 
-.if ( SCB_PAGING )
 /*
  * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
- * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
- * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
- * otherwise, SCBPTR is set to the proper SCB.
+ * or by the SCBID ARG_1.  The search begins at the SCB index passed in
+ * via SINDEX which is an SCB that must be on the disconnected list.  If
+ * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
+ * is set to the proper SCB.
  */
 findSCB:
-	mov	SCBPTR,SINDEX;			/* switch to next SCB */
+	mov	SCBPTR,SINDEX;			/* Initialize SCBPTR */
+	cmp	ARG_1, SCB_LIST_NULL	jne findSCB_by_SCBID;
+	mov	A, SAVED_TCL;
+	mvi	SCB_TCL	jmp findSCB_loop;	/* &SCB_TCL -> SINDEX */
+findSCB_by_SCBID:
 	mov	A, ARG_1;			/* Tag passed in ARG_1 */
-	cmp	SCB_TAG,A	jne findSCB_loop;
-	test	SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
+	mvi	SCB_TAG	jmp findSCB_loop;	/* &SCB_TAG -> SINDEX */
+findSCB_next:
+	cmp	SCB_NEXT, SCB_LIST_NULL je notFound;
+	mov	SCBPTR,SCB_NEXT;
+	dec	SINDEX;		/* Last comparison moved us too far */
 findSCB_loop:
-	inc	SINDEX;
-	mov	A,SCBCOUNT;
-	cmp	SINDEX,A	jne findSCB;
+	cmp	SINDIR, A	jne findSCB_next;
+	mov	SINDEX, SCBPTR 	ret;
+notFound:
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+
+/*
+ * Retrieve an SCB by SCBID first searching the disconnected list falling
+ * back to DMA'ing the SCB down from the host.  This routine assumes that
+ * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
+ * we go directly to the host for the SCB.
+ */
+retrieveSCB:
+	test	SEQ_FLAGS, SCBPTR_VALID	jz retrieve_from_host;
+	mov	SCBPTR	call findSCB;	/* Continue the search */
+	cmp	SINDEX, SCB_LIST_NULL	je retrieve_from_host;
+
 /*
- * We didn't find it.  If we're paging, pull an SCB and DMA down the
- * one we want.  If we aren't paging or the SCB we dma down has the
- * abort flag set, return not found.
+ * This routine expects SINDEX to contain the index of the SCB to be
+ * removed and SCBPTR to be pointing to that SCB.
  */
-	mov	ALLZEROS	call	get_free_or_disc_scb;
-	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-	mov	ARG_1	call dma_scb;
-	test	SCB_RESID_SGCNT, 0xff jz . + 2;
-	or	SCB_CONTROL, MUST_DMAUP_SCB;
-	test	SCB_CONTROL, ABORT_SCB jz return;
-find_error:
-	mvi	SINDEX, SCB_LIST_NULL ret;
-foundSCB:
-	test	SCB_CONTROL, ABORT_SCB jnz find_error;
 rem_scb_from_disc_list:
 /* Remove this SCB from the disconnection list */
 	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev;
-	mov	SAVED_LINKPTR, SCB_PREV;
+	mov	DINDEX, SCB_PREV;
 	mov	SCBPTR, SCB_NEXT;
-	mov	SCB_PREV, SAVED_LINKPTR;
+	mov	SCB_PREV, DINDEX;
 	mov	SCBPTR, SINDEX;
 unlink_prev:
 	cmp	SCB_PREV,SCB_LIST_NULL	je rHead;/* At the head of the list */
-	mov	SAVED_LINKPTR, SCB_NEXT;
+	mov	DINDEX, SCB_NEXT;
 	mov	SCBPTR, SCB_PREV;
-	mov	SCB_NEXT, SAVED_LINKPTR;
+	mov	SCB_NEXT, DINDEX;
 	mov	SCBPTR, SINDEX ret;
 rHead:
 	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
-.else
-	ret;
-.endif
+
+retrieve_from_host:
+/*
+ * We didn't find it.  Pull an SCB and DMA down the one we want.
+ * We should never get here in the non-paging case.
+ */
+	mov	ALLZEROS	call	get_free_or_disc_scb;
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	/* Jump instead of call as we want to return anyway */
+	mov	ARG_1	jmp dma_scb;
+
+/*
+ * Determine whether a target is using tagged or non-tagged transactions
+ * by first looking for a matching transaction based on the TCL and if
+ * that fails, looking up this device in the host's untagged SCB array.
+ * The TCL to search for is assumed to be in SAVED_TCL.  The value is
+ * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
+ * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
+ * in an SCB instead of having to go to the host.
+ */
+get_untagged_SCBID:
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
+	mvi	ARG_1, SCB_LIST_NULL;
+	mov	DISCONNECTED_SCBH call findSCB;
+	cmp	SINDEX, SCB_LIST_NULL	je get_SCBID_from_host;
+	or	SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
+	test	SCB_CONTROL, TAG_ENB	jnz . + 2;
+	mov	ARG_1, SCB_TAG	ret;
+	mvi	ARG_1, SCB_LIST_NULL ret;
+
+set_SCBID_host_addr_and_cnt:
+	mov	DINDEX, SINDEX;
+	mvi	SCBID_ADDR call	set_1byte_haddr_and_clrcnt;
+	mvi	HCNT[0], 1 ret;
+
+get_SCBID_from_host:
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+	call	dma_finish;
+	mov	ARG_1, DFDAT ret;
+
+phase_lock:     
+	test	SSTAT1, REQINIT jz phase_lock;
+	test	SSTAT1, SCSIPERR jnz phase_lock;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	mov	SCSISIGO, LASTPHASE ret;
 
 set_stcnt_from_hcnt:
 	mov	STCNT[0], HCNT[0];
@@ -1029,23 +1115,32 @@
 	mov	DINDIR, SINDIR;
 	mov	DINDIR, SINDIR ret;
 
+/*
+ * Setup haddr and count assuming that A is an
+ * index into an array of 32byte objects.
+ */
+set_32byte_haddr_and_clrcnt:
+	shr	DINDEX, 3, A;
+	shl	A, 5;
+set_1byte_haddr_and_clrcnt:	/* DINDEX must be 0 upon call */
+	add	HADDR[0], A, SINDIR;
+	mov	A, DINDEX;
+	adc	HADDR[1], A, SINDIR;
+	clr	A;
+	adc	HADDR[2], A, SINDIR;
+	adc	HADDR[3], A, SINDIR;
+	/* Clear Count */
+	clr	HCNT[1];
+	clr	HCNT[2] ret;
+
 dma_scb:
 	/*
 	 * SCB index is in SINDEX.  Determine the physical address in
 	 * the host where this SCB is located and load HADDR with it.
 	 */
-	shr	DINDEX, 3, SINDEX;
-	shl	A, 5, SINDEX;
-	add	HADDR[0], A, HSCB_ADDR[0];
-	mov	A, DINDEX;
-	adc	HADDR[1], A, HSCB_ADDR[1];
-	clr	A;
-	adc	HADDR[2], A, HSCB_ADDR[2];
-	adc	HADDR[3], A, HSCB_ADDR[3];
-	/* Setup Count */
+	mov	A, SINDEX;
+	mvi	HSCB_ADDR call set_32byte_haddr_and_clrcnt;
 	mvi	HCNT[0], 28;
-	clr	HCNT[1];
-	clr	HCNT[2];
 	mov	DFCNTRL, DMAPARAMS;
 	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
 	/* Fill it with the SCB data */
@@ -1092,25 +1187,12 @@
 	test	DFCNTRL, HDMAEN jnz .;
 	ret;
 
-index_untagged_scb:
-	mov	DINDEX, SINDEX;
-	shr	DINDEX, 4;
-	and	DINDEX, 0x03;			/* Bottom two bits of tid */
-	add	DINDEX, SCB_BUSYTARGETS;
-	shr	A, 6, SINDEX;			/* Target ID divided by 4 */
-	test	SINDEX, SELBUSB jz index_untagged_scb2;
-	add	A, 2;				/* Add 2 positions */
-index_untagged_scb2:
-	mov	SCBPTR, A;			/*
-						 * Select the SCB with this 
-						 * target's information.
-						 */
-	mov	SINDEX, DINDEX	ret;
-
 add_scb_to_free_list:
+.if ( SCB_PAGING )
 	mov	SCB_NEXT, FREE_SCBH;
-	mvi	SCB_TAG, SCB_LIST_NULL;
-	mov	FREE_SCBH, SCBPTR ret;
+	mov	FREE_SCBH, SCBPTR;
+.endif
+	mvi	SCB_TAG, SCB_LIST_NULL ret;
 
 .if ( SCB_PAGING )
 get_free_or_disc_scb:
@@ -1120,11 +1202,6 @@
 	mvi	SINDEX, SCB_LIST_NULL	ret;
 dequeue_disc_scb:
 	mov	SCBPTR, DISCONNECTED_SCBH;
-/*
- * Whenever we are going to dequeue a disconnected SCB and wipe it out
- * with a new SCB, we always send the SCB back to the kernel to make sure
- * any residual info and any save/restore pointers are saved for later use..
- */
 dma_up_scb:
 	mvi	DMAPARAMS, FIFORESET;
 	mov	SCB_TAG		call dma_scb;
@@ -1134,6 +1211,7 @@
 dequeue_free_scb:
 	mov	SCBPTR, FREE_SCBH;
 	mov	FREE_SCBH, SCB_NEXT ret;
+.endif
 
 add_scb_to_disc_list:
 /*
@@ -1148,4 +1226,3 @@
 	mov	SCBPTR,SCB_NEXT;
 	mov	SCB_PREV,DISCONNECTED_SCBH;
 	mov	SCBPTR,DISCONNECTED_SCBH ret;
-.endif
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx/scsi_message.h linux/drivers/scsi/aic7xxx/scsi_message.h
--- v2.0.33/linux/drivers/scsi/aic7xxx/scsi_message.h	Thu Jul 31 12:37:17 1997
+++ linux/drivers/scsi/aic7xxx/scsi_message.h	Wed Jun  3 15:17:48 1998
@@ -1,7 +1,3 @@
-/*
- * SCSI messages definitions.
- */
-
 /* Messages (1 byte) */		     /* I/T (M)andatory or (O)ptional */
 #define MSG_CMDCOMPLETE		0x00 /* M/M */
 #define MSG_EXTENDED		0x01 /* O/O */
@@ -30,6 +26,7 @@
 
 /* Identify message */		     /* M/M */	
 #define MSG_IDENTIFYFLAG	0x80 
+#define MSG_IDENTIFY_DISCFLAG	0x40 
 #define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
 #define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
 
@@ -39,3 +36,6 @@
 
 #define MSG_EXT_WDTR		0x03
 #define MSG_EXT_WDTR_LEN	0x02
+#define MSG_EXT_WDTR_BUS_8_BIT	0x00
+#define MSG_EXT_WDTR_BUS_16_BIT	0x01
+#define MSG_EXT_WDTR_BUS_32_BIT	0x02 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx/sequencer.h linux/drivers/scsi/aic7xxx/sequencer.h
--- v2.0.33/linux/drivers/scsi/aic7xxx/sequencer.h	Thu Jul 31 12:37:17 1997
+++ linux/drivers/scsi/aic7xxx/sequencer.h	Wed Jun  3 15:17:48 1998
@@ -11,10 +11,7 @@
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
@@ -36,49 +33,46 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *      $Id: sequencer.h,v 1.2 1997/06/27 19:38:52 gibbs Exp $
+ *      $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
  */
 
-#if defined(__KERNEL__)
-typedef unsigned char u_int8_t;
-#endif
-
 struct ins_format1 {
-	u_int8_t immediate;
-	u_int8_t source;
-	u_int8_t destination;
-	u_int8_t opcode_ret;
+	unsigned char immediate;
+	unsigned char source;
+	unsigned char destination;
+	unsigned char opcode_ret;
+#define DOWNLOAD_CONST_IMMEDIATE 0x80
 };
 
 struct ins_format2 {
-	u_int8_t shift_control;
-	u_int8_t source;
-	u_int8_t destination;
-	u_int8_t opcode_ret;
+	unsigned char shift_control;
+	unsigned char source;
+	unsigned char destination;
+	unsigned char opcode_ret;
 #define RETURN_BIT 0x01
 };
 
 struct ins_format3 {
-	u_int8_t immediate;
-	u_int8_t source;
-	u_int8_t address;
-	u_int8_t opcode_addr;
+	unsigned char immediate;
+	unsigned char source;
+	unsigned char address;
+	unsigned char opcode_addr;
 #define ADDR_HIGH_BIT 0x01
 };
 
+#ifndef __KERNEL__
 struct instruction {
 	union {
 		struct ins_format1 format1;
 		struct ins_format2 format2;
 		struct ins_format3 format3;
-		u_int8_t	   bytes[4];
+		unsigned char	   bytes[4];
 	} format;
 	u_int	srcline;
 	struct symbol *patch_label;
-	struct {
-		struct instruction *stqe_next; /* next element */
-	} links;
+	STAILQ_ENTRY(instruction) links;
 };
+#endif
 
 #define	AIC_OP_OR	0x0
 #define	AIC_OP_AND	0x1
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.0.33/linux/drivers/scsi/aic7xxx.c	Tue Mar 10 13:19:09 1998
+++ linux/drivers/scsi/aic7xxx.c	Wed Jun  3 15:17:48 1998
@@ -38,7 +38,7 @@
  *  Parts of this driver were also based on the FreeBSD driver by
  *  Justin T. Gibbs.  His copyright follows:
  *
- * --------------------------------------------------------------------------
+ * --------------------------------------------------------------------------  
  * Copyright (c) 1994-1997 Justin Gibbs.
  * All rights reserved.
  *
@@ -96,6 +96,73 @@
  *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
  *-M*************************************************************************/
 
+/*+M**************************************************************************
+ *
+ * Further driver modifications made by Doug Ledford <dledford@dialnet.net>
+ *
+ * Copyright (c) 1997-1998 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accomodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ * Overall, this driver represents a significant departure from the official
+ * aic7xxx driver released by Dan Eischen in two ways.  First, in the code
+ * itself.  A diff between the two version of the driver is now a several
+ * thousand line diff.  Second, in approach to solving the same problem.  The
+ * problem is importing the FreeBSD aic7xxx driver code to linux can be a
+ * difficult and time consuming process, that also can be error prone.  Dan
+ * Eischen's official driver uses the approach that the linux and FreeBSD
+ * drivers should be as identical as possible.  To that end, his next version
+ * of this driver will be using a mid-layer code library that he is developing
+ * to moderate communications between the linux mid-level SCSI code and the
+ * low level FreeBSD driver.  He intends to be able to essentially drop the
+ * FreeBSD driver into the linux kernel with only a few minor tweaks to some
+ * include files and the like and get things working, making for fast easy
+ * imports of the FreeBSD code into linux.
+ *
+ * I disagree with Dan's approach.  Not that I don't think his way of doing
+ * things would be nice, easy to maintain, and create a more uniform driver
+ * between FreeBSD and Linux.  I have no objection to those issues.  My
+ * disagreement is on the needed functionality.  There simply are certain
+ * things that are done differently in FreeBSD than linux that will cause
+ * problems for this driver regardless of any middle ware Dan implements.
+ * The biggest example of this at the moment is interrupt semantics.  Linux
+ * doesn't provide the same protection techniques as FreeBSD does, nor can
+ * they be easily implemented in any middle ware code since they would truly
+ * belong in the kernel proper and would effect all drivers.  For the time
+ * being, I see issues such as these as major stumbling blocks to the 
+ * reliability of code based upon such middle ware.  Therefore, I choose to
+ * use a different approach to importing the FreeBSD code that doesn't
+ * involve any middle ware type code.  My approach is to import the sequencer
+ * code from FreeBSD wholesale.  Then, to only make changes in the kernel
+ * portion of the driver as they are needed for the new sequencer semantics.
+ * In this way, the portion of the driver that speaks to the rest of the
+ * linux kernel is fairly static and can be changed/modified to solve
+ * any problems one might encounter without concern for the FreeBSD driver.
+ *
+ * Note: If time and experience should prove me wrong that the middle ware
+ * code Dan writes is reliable in its operation, then I'll retract my above
+ * statements.  But, for those that don't know, I'm from Missouri (in the US)
+ * and our state motto is "The Show-Me State".  Well, before I will put
+ * faith into it, you'll have to show me that it works :)
+ *
+ *_M*************************************************************************/
+
 #ifdef MODULE
 #include <linux/module.h>
 #endif
@@ -103,16 +170,18 @@
 #include <stdarg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/bios32.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
+#include <linux/tqueue.h>
+#include <linux/tasks.h>
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -122,10 +191,11 @@
 #include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
 #include "aic7xxx_seq.h"
+
 #include <linux/stat.h>
-#include <linux/malloc.h>	/* for kmalloc() */
+#include <linux/malloc.h>        /* for kmalloc() */
 
-#include <linux/config.h>	/* for CONFIG_PCI */
+#include <linux/config.h>        /* for CONFIG_PCI */
 
 /*
  * To generate the correct addresses for the controller to issue
@@ -139,13 +209,13 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.1.1 $"
+#define AIC7XXX_C_VERSION  "5.0.14"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
 #define ALL_TARGETS -1
-#define ALL_CHANNELS '\0'
+#define ALL_CHANNELS -1
 #define ALL_LUNS -1
 #define MAX_TARGETS  16
 #define MAX_LUNS     8
@@ -156,75 +226,78 @@
 #  define FALSE 0
 #endif
 
+#ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
 /*
- * Defines for PCI bus support, testing twin bus support, DMAing of
- * SCBs, tagged queueing, commands (SCBs) per lun, and SCSI bus reset
- * delay time.
- *
- *   o PCI bus support - this has been implemented and working since
- *     the December 1, 1994 release of this driver. If you don't have
- *     a PCI bus, then you can configure your kernel without PCI
- *     support because all PCI dependent code is bracketed with
- *     "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
- *
- *   o Twin bus support - this has been tested and does work.  It is
- *     not an option anymore.
- *
- *   o Tagged queueing - this driver is capable of tagged queueing
- *     but I am unsure as to how well the higher level driver implements
- *     tagged queueing. Therefore, the maximum commands per lun is
- *     set to 2. If you want to implement tagged queueing, ensure
- *     this define is not commented out.
- *
- *   o Commands per lun - If tagged queueing is enabled, then you
- *     may want to try increasing AIC7XXX_CMDS_PER_LUN to more
- *     than 2.  By default, we limit the SCBs per LUN to 2 with
- *     or without tagged queueing enabled.  If tagged queueing is
- *     disabled, the sequencer will keep the 2nd SCB in the input
- *     queue until the first one completes - so it is OK to to have
- *     more than 1 SCB queued.  If tagged queueing is enabled, then
- *     the sequencer will attempt to send the 2nd SCB to the device
- *     while the first SCB is executing and the device is disconnected.
- *     For adapters limited to 4 SCBs, you may want to actually
- *     decrease the commands per LUN to 1, if you often have more
- *     than 2 devices active at the same time.  This will allocate
- *     1 SCB for each device and ensure that there will always be
- *     a free SCB for up to 4 devices active at the same time.
- *     When SCB paging is enabled, set the commands per LUN to 8
- *     or higher (see SCB paging support below).  Note that if
- *     AIC7XXX_CMDS_PER_LUN is not defined and tagged queueing is
- *     enabled, the driver will attempt to set the commands per
- *     LUN using its own heuristic based on the number of available
- *     SCBs.
- *
- *   o 3985 support - The 3985 adapter is much like the 3940, but has
- *     three 7870 controllers as opposed to two for the 3940.  It will
- *     be probed and recognized as three different adapters, but all
- *     three controllers can share the same external bank of 255 SCBs.
- *     If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
- *     to use and share the common bank of SCBs between the three
- *     controllers of the 3985.  This is experimental and hasn't been
- *     been tested.  By default, we do not use external SCB RAM, and
- *     force the controllers to use their own internal bank of 16 SCBs.
- *     Please let us know if using the external SCB array works.
- *
- *   o SCB paging support - SCB paging is enabled by defining
- *     AIC7XXX_PAGE_ENABLE.  Support for this was taken from the
- *     FreeBSD driver (by Justin Gibbs) and allows for up to 255
- *     active SCBs.  This will increase performance when tagged
- *     queueing is enabled.  Note that you should increase the
- *     AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices
- *     allow at least this many.
- *
- *  Note that sharing of IRQs is not an option any longer.  Linux supports
- *  it so we support it.
- *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
- */
-
-/* Uncomment this for tagged queueing. */
-#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
-#define AIC7XXX_TAGGED_QUEUEING
+ * We need the bios32.h file if we are kernel version 2.1.92 or less.  The
+ * full set of pci_* changes wasn't in place until 2.1.93
+ */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
+#  if defined(__sparc_v9__) || defined(__powerpc__)
+#    error "PPC and Sparc platforms are only support under 2.1.x and above"
+#  endif
+#  include <linux/bios32.h>
+#endif
+
+#if !defined(__alpha__) && !defined(__sparc__)
+#  define MMAPIO
+#endif
+
+#if defined(__powerpc__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("eieio" ::: "memory")
+#elif defined(__i386__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory")
+#elif defined(__alpha__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("mb": : :"memory")
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+#  include <asm/spinlock.h>
+#  include <linux/smp.h>
+#  define cpuid smp_processor_id()
+#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+#    define DRIVER_LOCK_INIT \
+       spin_lock_init(&p->spin_lock);
+#    define DRIVER_LOCK \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#    define DRIVER_UNLOCK \
+       if(--p->cpu_lock_count[cpuid] == 0) \
+         spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
+#  else
+#    define DRIVER_LOCK_INIT
+#    define DRIVER_LOCK
+#    define DRIVER_UNLOCK
+#  endif
+#else
+#  define cpuid 0
+#  define DRIVER_LOCK_INIT
+#  define DRIVER_LOCK \
+       save_flags(cpu_flags); \
+       cli();
+#  define DRIVER_UNLOCK \
+       restore_flags(cpu_flags);
+#  define le32_to_cpu(x) (x)
+#  define cpu_to_le32(x) (x)
 #endif
 
 /*
@@ -239,7 +312,7 @@
 #ifdef CONFIG_AIC7XXX_RESET_DELAY
 #define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
 #else
-#define AIC7XXX_RESET_DELAY 15
+#define AIC7XXX_RESET_DELAY 5
 #endif
 
 /*
@@ -253,32 +326,18 @@
 #endif
 
 /*
- * Enable SCB paging.
- */
-#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
-#define AIC7XXX_PAGE_ENABLE
-#endif
-
-/*
- * Uncomment the following to enable use of the external bank
- * of 255 SCBs.  For 3985 adapters, this will also enable sharing
- * of the SCB array across all three controllers.
- */
-#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
-#define AIC7XXX_USE_EXT_SCBRAM
-#endif
-
-/*
- * For debugging the abort/reset code.
- */
-#define AIC7XXX_DEBUG_ABORT
-
-/*
- * For general debug messages
- */
-#define AIC7XXX_DEBUG
-
-/*
+ * NOTE: Uncommenting the define below no longer has any effect, the
+ *       tagged queue value array is always active now.  I've added
+ *       a setup option to set this particular array and I'm hoping
+ *       insmod will be smart enough to set it properly as well.  It's
+ *       by use of this array that a person can disable tagged queueing.
+ *       The DEFAULT_TAG_COMMANDS define has been changed to disable
+ *       tagged queueing by default, so if your devices can handle tagged
+ *       queueing you will need to add a line to their lilo.conf file like:
+ *       append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ *       which will result in the first four devices on the first two
+ *       controllers being set to a tagged queue depth of 32.
+ *
  * Set this for defining the number of tagged commands on a device
  * by device, and controller by controller basis.  The first set
  * of tagged commands will be used for the first detected aic7xxx
@@ -293,37 +352,36 @@
  * 
  * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
  * own algorithm to determine the commands/LUN.  If SCB paging is
- * enabled, the commands/LUN is 8.  When SCB paging is not enabled,
- * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
- * and 4 commands/LUN for adapters with 3 or 4 SCBs.
- *
+ * enabled, which is always now, the default is 8 commands per lun
+ * that indicates it supports tagged queueing.  All non-tagged devices
+ * use an internal queue depth of 3, with no more than one of those
+ * three commands active at one time.
  */
 /* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
 
-#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
 typedef struct
 {
-  unsigned char tag_commands[16];   /* Allow for wide/twin channel adapters. */
+  unsigned char tag_commands[16];   /* Allow for wide/twin adapters. */
 } adapter_tag_info_t;
 
 /*
- * Make a define that will tell the driver to use it's own algorithm
- * for determining commands/LUN (see Determining commands per LUN
- * above).
+ * Make a define that will tell the driver not to use tagged queueing
+ * by default.
  */
-#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
+                              255, 255, 255, 255, 255, 255, 255, 255}
 
 /*
  * Modify this as you see fit for your system.  By setting tag_commands
  * to 0, the driver will use it's own algorithm for determining the
- * number of commands to use (see above).  When -1, the driver will
+ * number of commands to use (see above).  When 255, the driver will
  * not enable tagged queueing for that particular device.  When positive
- * (> 0) the values in the array are used for the queue_depth.  Note
- * that the maximum value for an entry is 127.
+ * (> 0) and (< 255) the values in the array are used for the queue_depth.
+ * Note that the maximum value for an entry is 254, but you're insane if
+ * you try to use that many commands on one device.
  *
- * In this example, the first line will enable tagged queueing for all
- * the devices on the first probed aic7xxx adapter and tells the driver
- * to use it's own algorithm for determining commands/LUN.
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
  *
  * The second line enables tagged queueing with 4 commands/LUN for IDs
  * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
@@ -336,107 +394,42 @@
  * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
  * IDs 2, 5-7, and 9-15.
  */
+
+/*
 adapter_tag_info_t aic7xxx_tag_info[] =
 {
   {DEFAULT_TAG_COMMANDS},
-  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
   {DEFAULT_TAG_COMMANDS},
-  {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+  {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
 };
-#endif
-
-/*
- * Don't define this unless you have problems with the driver
- * interrupt handler.  The old method would register the drivers
- * interrupt handler as a "fast" type interrupt handler that would
- * lock out other interrupts.  Since this driver can spend a lot
- * of time in the interrupt handler, this is _not_ a good idea.
- * It also conflicts with some of the more common ethernet drivers
- * that don't use fast interrupts.  Currently, Linux does not allow
- * IRQ sharing unless both drivers can agree on the type of interrupt
- * handler.
- */
-/* #define AIC7XXX_OLD_ISR_TYPE */
-
-
-/*
- * Controller type and options
- */
-typedef enum {
-  AIC_NONE,
-  AIC_7770,	/* EISA aic7770 on motherboard */
-  AIC_7771,	/* EISA aic7771 on 274x */
-  AIC_284x,	/* VLB  aic7770 on 284x, BIOS disabled */
-  AIC_7850,	/* PCI  aic7850 */
-  AIC_7855,	/* PCI  aic7855 */
-  AIC_7860,	/* PCI  aic7860 (7850 Ultra) */
-  AIC_7861,     /* PCI  aic7861 on 2940AU */
-  AIC_7870,	/* PCI  aic7870 on motherboard */
-  AIC_7871,	/* PCI  aic7871 on 294x */
-  AIC_7872,	/* PCI  aic7872 on 3940 */
-  AIC_7873,	/* PCI  aic7873 on 3985 */
-  AIC_7874,	/* PCI  aic7874 on 294x Differential */
-  AIC_7880,	/* PCI  aic7880 on motherboard */
-  AIC_7881,	/* PCI  aic7881 on 294x Ultra */
-  AIC_7882,	/* PCI  aic7882 on 3940 Ultra */
-  AIC_7883,	/* PCI  aic7883 on 3985 Ultra */
-  AIC_7884	/* PCI  aic7884 on 294x Ultra Differential */
-} aha_chip_type;
-
-typedef enum {
-  AIC_777x,	/* AIC-7770 based */
-  AIC_785x,	/* AIC-7850 based (3 SCBs)*/
-  AIC_786x,	/* AIC-7860 based (7850 ultra) */
-  AIC_787x,	/* AIC-7870 based */
-  AIC_788x	/* AIC-7880 based (ultra) */
-} aha_chip_class_type;
-
-typedef enum {
-  AIC_SINGLE,  /* Single Channel */
-  AIC_TWIN,    /* Twin Channel */
-  AIC_WIDE     /* Wide Channel */
-} aha_bus_type;
-
-typedef enum {
-  AIC_UNKNOWN,
-  AIC_ENABLED,
-  AIC_DISABLED
-} aha_status_type;
-
-typedef enum {
-  LIST_HEAD,
-  LIST_SECOND
-} insert_type;
-
-typedef enum {
-  ABORT_RESET_INACTIVE,
-  ABORT_RESET_PENDING,
-  ABORT_RESET_SUCCESS
-} aha_abort_reset_type;
+*/
 
 /*
  * Define an array of board names that can be indexed by aha_type.
  * Don't forget to change this when changing the types!
  */
 static const char *board_names[] = {
-  "AIC-7xxx Unknown",		                        /* AIC_NONE */
-  "Adaptec AIC-7770 SCSI host adapter",			/* AIC_7770 */
-  "Adaptec AHA-274X SCSI host adapter",			/* AIC_7771 */
-  "Adaptec AHA-284X SCSI host adapter",			/* AIC_284x */
-  "Adaptec AIC-7850 SCSI host adapter",			/* AIC_7850 */
-  "Adaptec AIC-7855 SCSI host adapter",			/* AIC_7855 */
-  "Adaptec AIC-7860 Ultra SCSI host adapter",		/* AIC_7860 */
-  "Adaptec AHA-2940A Ultra SCSI host adapter",		/* AIC_7861 */
-  "Adaptec AIC-7870 SCSI host adapter",			/* AIC_7870 */
-  "Adaptec AHA-294X SCSI host adapter",			/* AIC_7871 */
-  "Adaptec AHA-394X SCSI host adapter",			/* AIC_7872 */
-  "Adaptec AHA-398X SCSI host adapter",			/* AIC_7873 */
-  "Adaptec AHA-2944 SCSI host adapter",	                /* AIC_7874 */
-  "Adaptec AIC-7880 Ultra SCSI host adapter",		/* AIC_7880 */
-  "Adaptec AHA-294X Ultra SCSI host adapter",		/* AIC_7881 */
-  "Adaptec AHA-394X Ultra SCSI host adapter",		/* AIC_7882 */
-  "Adaptec AHA-398X Ultra SCSI host adapter",		/* AIC_7883 */
-  "Adaptec AHA-2944 Ultra SCSI host adapter"	        /* AIC_7884 */
+  "AIC-7xxx Unknown",                                   /* AIC_NONE */
+  "Adaptec AIC-7810 Hardware RAID Controller",          /* AIC_7810 */
+  "Adaptec AIC-7770 SCSI host adapter",                 /* AIC_7770 */
+  "Adaptec AHA-274X SCSI host adapter",                 /* AIC_7771 */
+  "Adaptec AHA-284X SCSI host adapter",                 /* AIC_284x */
+  "Adaptec AIC-7850 SCSI host adapter",                 /* AIC_7850 */
+  "Adaptec AIC-7855 SCSI host adapter",                 /* AIC_7855 */
+  "Adaptec AIC-7860 Ultra SCSI host adapter",           /* AIC_7860 */
+  "Adaptec AHA-2940A Ultra SCSI host adapter",          /* AIC_7861 */
+  "Adaptec AIC-7870 SCSI host adapter",                 /* AIC_7870 */
+  "Adaptec AHA-294X SCSI host adapter",                 /* AIC_7871 */
+  "Adaptec AHA-394X SCSI host adapter",                 /* AIC_7872 */
+  "Adaptec AHA-398X SCSI host adapter",                 /* AIC_7873 */
+  "Adaptec AHA-2944 SCSI host adapter",                 /* AIC_7874 */
+  "Adaptec AIC-7880 Ultra SCSI host adapter",           /* AIC_7880 */
+  "Adaptec AHA-294X Ultra SCSI host adapter",           /* AIC_7881 */
+  "Adaptec AHA-394X Ultra SCSI host adapter",           /* AIC_7882 */
+  "Adaptec AHA-398X Ultra SCSI host adapter",           /* AIC_7883 */
+  "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
+  "Adaptec AIC-7895 Ultra SCSI host adapter"            /* AIC_7895 */
 };
 
 /*
@@ -461,58 +454,58 @@
 #define DID_RETRY_COMMAND DID_ERROR
 
 #define HSCSIID        0x07
-#define HWSCSIID       0x0F
 #define SCSI_RESET     0x040
 
 /*
  * EISA/VL-bus stuff
  */
-#define MINSLOT		1
-#define MAXSLOT		15
-#define SLOTBASE(x)	((x) << 12)
+#define MINSLOT                1
+#define MAXSLOT                15
+#define SLOTBASE(x)        ((x) << 12)
 #define BASE_TO_SLOT(x) ((x) >> 12)
 
 /*
  * Standard EISA Host ID regs  (Offset from slot base)
  */
-#define HID0		0x80   /* 0,1: msb of ID2, 2-7: ID1      */
-#define HID1		0x81   /* 0-4: ID3, 5-7: LSB ID2         */
-#define HID2		0x82   /* product                        */
-#define HID3		0x83   /* firmware revision              */
+#define HID0                0x80   /* 0,1: msb of ID2, 2-7: ID1      */
+#define HID1                0x81   /* 0-4: ID3, 5-7: LSB ID2         */
+#define HID2                0x82   /* product                        */
+#define HID3                0x83   /* firmware revision              */
 
 /*
  * AIC-7770 I/O range to reserve for a card
  */
-#define MINREG		0xC00
-#define MAXREG		0xCBF
+#define MINREG                0xC00
+#define MAXREG                0xCBF
 
-#define INTDEF		0x5C		/* Interrupt Definition Register */
+#define INTDEF                0x5C      /* Interrupt Definition Register */
 
 /*
  * AIC-78X0 PCI registers
  */
-#define	CLASS_PROGIF_REVID	0x08
-#define		DEVREVID	0x000000FFul
-#define		PROGINFC	0x0000FF00ul
-#define		SUBCLASS	0x00FF0000ul
-#define		BASECLASS	0xFF000000ul
-
-#define	CSIZE_LATTIME		0x0C
-#define		CACHESIZE	0x0000003Ful	/* only 5 bits */
-#define		LATTIME		0x0000FF00ul
-
-#define	DEVCONFIG		0x40
-#define		MPORTMODE	0x00000400ul	/* aic7870 only */
-#define		RAMPSM		0x00000200ul	/* aic7870 only */
-#define		VOLSENSE	0x00000100ul
-#define		SCBRAMSEL	0x00000080ul
-#define		MRDCEN		0x00000040ul
-#define		EXTSCBTIME	0x00000020ul	/* aic7870 only */
-#define		EXTSCBPEN	0x00000010ul	/* aic7870 only */
-#define		BERREN		0x00000008ul
-#define		DACEN		0x00000004ul
-#define		STPWLEVEL	0x00000002ul
-#define		DIFACTNEGEN	0x00000001ul	/* aic7870 only */
+#define        CLASS_PROGIF_REVID        0x08
+#define                DEVREVID        0x000000FFul
+#define                PROGINFC        0x0000FF00ul
+#define                SUBCLASS        0x00FF0000ul
+#define                BASECLASS        0xFF000000ul
+
+#define        CSIZE_LATTIME                0x0C
+#define                CACHESIZE        0x0000003Ful        /* only 5 bits */
+#define                LATTIME                0x0000FF00ul
+
+#define        DEVCONFIG                0x40
+#define                SCBSIZE32        0x00010400ul        /* aic789X only */
+#define                MPORTMODE        0x00000400ul        /* aic7870 only */
+#define                RAMPSM           0x00000200ul        /* aic7870 only */
+#define                VOLSENSE         0x00000100ul
+#define                SCBRAMSEL        0x00000080ul
+#define                MRDCEN           0x00000040ul
+#define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
+#define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
+#define                BERREN           0x00000008ul
+#define                DACEN            0x00000004ul
+#define                STPWLEVEL        0x00000002ul
+#define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
 
 
 /*
@@ -536,69 +529,72 @@
 /*
  * SCSI ID Configuration Flags
  */
-#define CFXFER		0x0007		/* synchronous transfer rate */
-#define CFSYNCH		0x0008		/* enable synchronous transfer */
-#define CFDISC		0x0010		/* enable disconnection */
-#define CFWIDEB		0x0020		/* wide bus device (wide card) */
-/* UNUSED		0x00C0 */
-#define CFSTART		0x0100		/* send start unit SCSI command */
-#define CFINCBIOS	0x0200		/* include in BIOS scan */
-#define CFRNFOUND	0x0400		/* report even if not found */
-/* UNUSED		0xF800 */
-  unsigned short device_flags[16];	/* words 0-15 */
+#define CFXFER                0x0007      /* synchronous transfer rate */
+#define CFSYNCH               0x0008      /* enable synchronous transfer */
+#define CFDISC                0x0010      /* enable disconnection */
+#define CFWIDEB               0x0020      /* wide bus device (wide card) */
+#define CFSYNCHISULTRA        0x0040      /* CFSYNC is an ultra offset */
+/* UNUSED                0x0080 */
+#define CFSTART               0x0100      /* send start unit SCSI command */
+#define CFINCBIOS             0x0200      /* include in BIOS scan */
+#define CFRNFOUND             0x0400      /* report even if not found */
+#define CFMULTILUN            0x0800      /* probe mult luns in BIOS scan */
+/* UNUSED                0xF000 */
+  unsigned short device_flags[16];        /* words 0-15 */
 
 /*
  * BIOS Control Bits
  */
-#define CFSUPREM	0x0001		/* support all removable drives */
-#define CFSUPREMB	0x0002		/* support removable drives for boot only */
-#define CFBIOSEN	0x0004		/* BIOS enabled */
-/* UNUSED		0x0008 */
-#define CFSM2DRV	0x0010		/* support more than two drives */
-#define CF284XEXTEND	0x0020		/* extended translation (284x cards) */
-/* UNUSED		0x0040 */
-#define CFEXTEND	0x0080		/* extended translation enabled */
-/* UNUSED		0xFF00 */
-  unsigned short bios_control;		/* word 16 */
+#define CFSUPREM        0x0001  /* support all removable drives */
+#define CFSUPREMB       0x0002  /* support removable drives for boot only */
+#define CFBIOSEN        0x0004  /* BIOS enabled */
+/* UNUSED                0x0008 */
+#define CFSM2DRV        0x0010  /* support more than two drives */
+#define CF284XEXTEND    0x0020  /* extended translation (284x cards) */
+/* UNUSED                0x0040 */
+#define CFEXTEND        0x0080  /* extended translation enabled */
+/* UNUSED                0xFF00 */
+  unsigned short bios_control;  /* word 16 */
 
 /*
  * Host Adapter Control Bits
  */
-#define CFAUTOTERM      0x0001          /* Perform Auto termination */
-#define CFULTRAEN       0x0002          /* Ultra SCSI speed enable (Ultra cards) */
-#define CF284XSELTO     0x0003          /* Selection timeout (284x cards) */
-#define CF284XFIFO      0x000C          /* FIFO Threshold (284x cards) */
-#define CFSTERM         0x0004          /* SCSI low byte termination */
-#define CFWSTERM        0x0008          /* SCSI high byte termination (wide card) */
-#define CFSPARITY	0x0010		/* SCSI parity */
-#define CF284XSTERM	0x0020		/* SCSI low byte termination (284x cards) */
-#define CFRESETB	0x0040		/* reset SCSI bus at boot */
-/* UNUSED		0xFF80 */
-  unsigned short adapter_control;	/* word 17 */
+#define CFAUTOTERM      0x0001  /* Perform Auto termination */
+#define CFULTRAEN       0x0002  /* Ultra SCSI speed enable (Ultra cards) */
+#define CF284XSELTO     0x0003  /* Selection timeout (284x cards) */
+#define CF284XFIFO      0x000C  /* FIFO Threshold (284x cards) */
+#define CFSTERM         0x0004  /* SCSI low byte termination */
+#define CFWSTERM        0x0008  /* SCSI high byte termination (wide card) */
+#define CFSPARITY       0x0010  /* SCSI parity */
+#define CF284XSTERM     0x0020  /* SCSI low byte termination (284x cards) */
+#define CFRESETB        0x0040  /* reset SCSI bus at boot */
+#define CFBPRIMARY      0x0100  /* Channel B primary on 7895 chipsets */
+/* UNUSED                0xFE80 */
+  unsigned short adapter_control;        /* word 17 */
 
 /*
  * Bus Release, Host Adapter ID
  */
-#define CFSCSIID	0x000F		/* host adapter SCSI ID */
-/* UNUSED		0x00F0 */
-#define CFBRTIME	0xFF00		/* bus release time */
-  unsigned short brtime_id;		/* word 18 */
+#define CFSCSIID        0x000F                /* host adapter SCSI ID */
+/* UNUSED                0x00F0 */
+#define CFBRTIME        0xFF00                /* bus release time */
+  unsigned short brtime_id;                /* word 18 */
 
 /*
  * Maximum targets
  */
-#define CFMAXTARG	0x00FF	/* maximum targets */
-/* UNUSED		0xFF00 */
-  unsigned short max_targets;		/* word 19 */
+#define CFMAXTARG        0x00FF        /* maximum targets */
+/* UNUSED                0xFF00 */
+  unsigned short max_targets;                /* word 19 */
 
-  unsigned short res_1[11];		/* words 20-30 */
-  unsigned short checksum;		/* word 31 */
+  unsigned short res_1[11];                /* words 20-30 */
+  unsigned short checksum;                /* word 31 */
 };
 
-#define SELBUS_MASK		0x0a
-#define 	SELNARROW	0x00
-#define 	SELBUSB		0x08
-#define SINGLE_BUS		0x00
+#define SELBUS_MASK                0x0a
+#define         SELNARROW        0x00
+#define         SELBUSB                0x08
+#define SINGLE_BUS                0x00
 
 #define SCB_TARGET(scb)         \
        (((scb)->hscb->target_channel_lun & TID) >> 4)
@@ -613,60 +609,22 @@
  * condition in this location. This then will modify a DID_OK status
  * into an appropriate error for the higher-level SCSI code.
  */
-#define aic7xxx_error(cmd)	((cmd)->SCp.Status)
+#define aic7xxx_error(cmd)        ((cmd)->SCp.Status)
 
 /*
  * Keep track of the targets returned status.
  */
-#define aic7xxx_status(cmd)	((cmd)->SCp.sent_command)
+#define aic7xxx_status(cmd)        ((cmd)->SCp.sent_command)
 
 /*
  * The position of the SCSI commands scb within the scb array.
  */
-#define aic7xxx_position(cmd)	((cmd)->SCp.have_data_in)
+#define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
 
 /*
- * "Static" structures. Note that these are NOT initialized
- * to zero inside the kernel - we have to initialize them all
- * explicitly.
- *
- * We support multiple adapter cards per interrupt, but keep a
- * linked list of Scsi_Host structures for each IRQ.  On an interrupt,
- * use the IRQ as an index into aic7xxx_boards[] to locate the card
- * information.
- */
-static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
-
-/*
- * When we detect and register the card, it is possible to
- * have the card raise a spurious interrupt.  Because we need
- * to support multiple cards, we cannot tell which card caused
- * the spurious interrupt.  And, we might not even have added
- * the card info to the linked list at the time the spurious
- * interrupt gets raised.  This variable is suppose to keep track
- * of when we are registering a card and how many spurious
- * interrupts we have encountered.
- *
- *   0 - do not allow spurious interrupts.
- *   1 - allow 1 spurious interrupt
- *   2 - have 1 spurious interrupt, do not allow any more.
- *
- * I've made it an integer instead of a boolean in case we
- * want to allow more than one spurious interrupt for debugging
- * purposes.  Otherwise, it could just go from true to false to
- * true (or something like that).
- *
- * When the driver detects the cards, we'll set the count to 1
- * for each card detection and registration.  After the registration
- * of a card completes, we'll set the count back to 0.  So far, it
- * seems to be enough to allow a spurious interrupt only during
- * card registration; if a spurious interrupt is going to occur,
- * this is where it happens.
- *
- * We should be able to find a way to avoid getting the spurious
- * interrupt.  But until we do, we have to keep this ugly code.
+ * So we can keep track of our host structs
  */
-static int aic7xxx_spurious_count;
+static struct aic7xxx_host *first_aic7xxx = NULL;
 
 /*
  * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
@@ -681,14 +639,14 @@
 /*
  * Maximum number of SG segments these cards can support.
  */
-#define	AIC7XXX_MAX_SG 122
+#define        AIC7XXX_MAX_SG 128
 
 /*
  * The maximum number of SCBs we could have for ANY type
  * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
  * SEQUENCER CODE IF THIS IS MODIFIED!
  */
-#define AIC7XXX_MAXSCB	255
+#define AIC7XXX_MAXSCB        255
 
 
 struct aic7xxx_hwscb {
@@ -704,55 +662,118 @@
 /*16*/  unsigned int  data_count;
 /*20*/  unsigned int  SCSI_cmd_pointer;
 /*24*/  unsigned char SCSI_cmd_length;
-/*25*/	u_char tag;			/* Index into our kernel SCB array.
-					 * Also used as the tag for tagged I/O
-					 */
-#define SCB_PIO_TRANSFER_SIZE	26 	/* amount we need to upload/download
-					 * via PIO to initialize a transaction.
-					 */
-/*26*/  unsigned char next;             /* Used to thread SCBs awaiting selection
-                                         * or disconnected down in the sequencer.
-                                         */
+/*25*/  unsigned char tag;          /* Index into our kernel SCB array.
+                                     * Also used as the tag for tagged I/O
+                                     */
+#define SCB_PIO_TRANSFER_SIZE  26   /* amount we need to upload/download
+                                     * via PIO to initialize a transaction.
+                                     */
+/*26*/  unsigned char next;         /* Used to thread SCBs awaiting selection
+                                     * or disconnected down in the sequencer.
+                                     */
 /*27*/  unsigned char prev;
-/*28*/  unsigned int pad;               /*
-                                         * Unused by the kernel, but we require
-                                         * the padding so that the array of
-                                         * hardware SCBs is alligned on 32 byte
-                                         * boundaries so the sequencer can index
-                                         */
+/*28*/  unsigned int pad;           /*
+                                     * Unused by the kernel, but we require
+                                     * the padding so that the array of
+                                     * hardware SCBs is alligned on 32 byte
+                                     * boundaries so the sequencer can index
+                                     */
 };
 
 typedef enum {
-	SCB_FREE		= 0x0000,
-	SCB_ACTIVE		= 0x0001,
-	SCB_ABORTED		= 0x0002,
-	SCB_DEVICE_RESET	= 0x0004,
-	SCB_SENSE		= 0x0008,
-	SCB_TIMEDOUT		= 0x0010,
-	SCB_QUEUED_FOR_DONE	= 0x0020,
-	SCB_RECOVERY_SCB	= 0x0040,
-	SCB_WAITINGQ		= 0x0080,
-	SCB_ASSIGNEDQ		= 0x0100,
-	SCB_SENTORDEREDTAG	= 0x0200,
-	SCB_MSGOUT_SDTR		= 0x0400,
-	SCB_MSGOUT_WDTR		= 0x0800,
-	SCB_ABORT		= 0x1000,
-	SCB_QUEUED_ABORT	= 0x2000,
-	SCB_RESET		= 0x4000,
-	SCB_WAS_BUSY		= 0x8000
+        SCB_FREE                = 0x0000,
+        SCB_WDTR_16BIT          = 0x0001,
+        SCB_WAITINGQ            = 0x0002,
+        SCB_ACTIVE              = 0x0004,
+        SCB_SENSE               = 0x0008,
+        SCB_ABORT               = 0x0010,
+        SCB_DEVICE_RESET        = 0x0020,
+        SCB_RESET               = 0x0040,
+        SCB_RECOVERY_SCB        = 0x0080,
+        SCB_WAS_BUSY            = 0x0100,
+        SCB_MSGOUT_SDTR         = 0x0400,
+        SCB_MSGOUT_WDTR         = 0x0800,
+        SCB_MSGOUT_WDTR_8BIT    = 0x0800,
+        SCB_MSGOUT_WDTR_16BIT   = 0x0801,
+        SCB_MSGOUT_BITS         = SCB_MSGOUT_SDTR | SCB_MSGOUT_WDTR_16BIT,
+        SCB_QUEUED_ABORT        = 0x1000,
+        SCB_QUEUED_FOR_DONE     = 0x2000
 } scb_flag_type;
 
+typedef enum {
+        AHC_FNONE                 = 0x00000000,
+        AHC_PAGESCBS              = 0x00000001,
+        AHC_CHANNEL_B_PRIMARY     = 0x00000002,
+        AHC_USEDEFAULTS           = 0x00000004,
+        AHC_INDIRECT_PAGING       = 0x00000008,
+        AHC_CHNLB                 = 0x00000020,
+        AHC_CHNLC                 = 0x00000040,
+        AHC_EXTEND_TRANS_A        = 0x00000100,
+        AHC_EXTEND_TRANS_B        = 0x00000200,
+        AHC_TERM_ENB_A            = 0x00000400,
+        AHC_TERM_ENB_B            = 0x00000800,
+        AHC_HANDLING_REQINITS     = 0x00001000,
+        AHC_TARGETMODE            = 0x00002000,
+        AHC_NEWEEPROM_FMT         = 0x00004000,
+ /*
+  *  Here ends the FreeBSD defined flags and here begins the linux defined
+  *  flags.  NOTE: I did not preserve the old flag name during this change
+  *  specifically to force me to evaluate what flags were being used properly
+  *  and what flags weren't.  This way, I could clean up the flag usage on
+  *  a use by use basis.  Doug Ledford
+  */
+        AHC_A_SCANNED             = 0x00100000,
+        AHC_B_SCANNED             = 0x00200000,
+        AHC_MULTI_CHANNEL         = 0x00400000,
+        AHC_BIOS_ENABLED          = 0x00800000,
+        AHC_ABORT_PENDING         = 0x02000000,
+        AHC_RESET_PENDING         = 0x04000000,
+        AHC_IN_ISR                = 0x10000000,
+        AHC_IN_ABORT              = 0x20000000,
+        AHC_IN_RESET              = 0x40000000
+} ahc_flag_type;
+
+typedef enum {
+        AHC_NONE                  = 0x00000000,
+        AHC_ULTRA                 = 0x00000001,
+        AHC_WIDE                  = 0x00000002,
+        AHC_TWIN                  = 0x00000008,
+        AHC_AIC7770               = 0x00000010,
+        AHC_AIC7850               = 0x00000020,
+        AHC_AIC7860               = 0x00000021,
+        AHC_AIC7870               = 0x00000040,
+        AHC_AIC7880               = 0x00000041,
+        AHC_AIC7895               = 0x00000081,
+        AHC_AIC78x0               = 0x000000E0,
+        AHC_274                   = 0x00000110,
+        AHC_284                   = 0x00000210,
+        AHC_294AU                 = 0x00000421,
+        AHC_294                   = 0x00000440,
+        AHC_294U                  = 0x00000441,
+        AHC_394                   = 0x00000840,
+        AHC_394U                  = 0x00000841,
+        AHC_394AU                 = 0x00000881,
+        AHC_398                   = 0x00001040,
+        AHC_398U                  = 0x00001041,
+        AHC_39x                   = 0x00001880
+} ahc_type;
+
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
-	Scsi_Cmnd             *cmd;	      /* Scsi_Cmnd for this scb */
+        Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
         struct aic7xxx_scb    *q_next;        /* next scb in queue */
-	scb_flag_type          flags;         /* current state of scb */
-	struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        scb_flag_type          flags;         /* current state of scb */
+        struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        unsigned char          tag_action;
         unsigned char          sg_count;
-	unsigned char          sense_cmd[6];  /*
+        unsigned char          sense_cmd[6];  /*
                                                * Allocate 6 characters for
                                                * sense command.
                                                */
+        unsigned int           sg_length; /* We init this during buildscb so we
+                                           * don't have to calculate anything
+                                           * during underflow/overflow/stat code
+                                           */
 };
 
 /*
@@ -770,7 +791,7 @@
   { ILLHADDR,  "Illegal Host Access" },
   { ILLSADDR,  "Illegal Sequencer Address referenced" },
   { ILLOPCODE, "Illegal Opcode in sequencer program" },
-  { PARERR,    "Sequencer Ram Parity Error" }
+  { SQPARERR,  "Sequencer Ram Parity Error" }
 };
 
 static unsigned char
@@ -786,62 +807,110 @@
   unsigned char  maxhscbs;         /* hardware scbs */
   unsigned char  maxscbs;          /* max scbs including pageable scbs */
   struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
-  unsigned int   reserve[100];
 } scb_data_type;
 
+typedef struct {
+  unsigned char period;
+  unsigned char offset;
+} syncinfo_type;
+
 /*
- * Define a structure used for each host adapter, only one per IRQ.
+ * Define a structure used for each host adapter.  Note, in order to avoid
+ * problems with architectures I can't test on (because I don't have one,
+ * such as the Alpha based systems) which happen to give faults for
+ * non-aligned memory accesses, care was taken to align this structure
+ * in a way that gauranteed all accesses larger than 8 bits were aligned
+ * on the appropriate boundary.  It's also organized to try and be more
+ * cache line efficient.  Be careful when changing this lest you might hurt
+ * overall performance and bring down the wrath of the masses.
  */
 struct aic7xxx_host {
+  /*
+   *  This is the first 64 bytes in the host struct
+   */
+
   struct Scsi_Host        *host;             /* pointer to scsi host */
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
   int                      host_no;          /* SCSI host number */
-  int                      instance;         /* aic7xxx instance number */
-  int                      scsi_id;          /* host adapter SCSI ID */
-  int                      scsi_id_b;        /*   channel B for twin adapters */
-  int                      irq;              /* IRQ for this adapter */
-  int                      base;             /* card base address */
-  unsigned int             mbase;            /* I/O memory address */
+  unsigned long            base;             /* card base address */
   volatile unsigned char  *maddr;            /* memory mapped address */
-#define A_SCANNED               0x0001
-#define B_SCANNED               0x0002
-#define EXTENDED_TRANSLATION    0x0004
-#define FLAGS_CHANNEL_B_PRIMARY 0x0008
-#define MULTI_CHANNEL           0x0010
-#define ULTRA_ENABLED           0x0020
-#define PAGE_ENABLED            0x0040
-#define USE_DEFAULTS            0x0080
-#define BIOS_ENABLED            0x0100
-#define IN_ISR                  0x0200
-#define ABORT_PENDING           0x0400
-#define SHARED_SCBDATA          0x0800
-#define HAVE_SEEPROM            0x1000
-#define RESET_PENDING           0x2000
-#define IN_ABORT		0x4000
-  unsigned int             flags;
-  unsigned long		   last_reset;
-  unsigned long		   reset_start;
-  unsigned int             isr_count;        /* Interrupt count */
-  unsigned short           needsdtr_copy;    /* default config */
-  unsigned short           needsdtr;
-  unsigned short           sdtr_pending;
-  unsigned short           needwdtr_copy;    /* default config */
-  unsigned short           needwdtr;
-  unsigned short           wdtr_pending;
-  unsigned short           orderedtag;
-  unsigned short           discenable;	     /* Targets allowed to disconnect */
-  aha_chip_type            chip_type;        /* card type */
-  aha_chip_class_type      chip_class;
-  aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  unsigned char            chan_num;         /* for 39xx, channel number */
+  unsigned long            mbase;            /* I/O memory address */
+  volatile ahc_flag_type   flags;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+  spinlock_t               spin_lock;
+#endif
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+  ahc_type                 type;             /* card type */
+  unsigned long            last_reset;
+  unsigned long            isr_count;        /* Interrupt count */
+  unsigned long            spurious_int;
+  unsigned short           discenable;       /* Targets allowed to disconnect */
+  unsigned short           tagenable;        /* Targets using tagged I/O */
+  unsigned short           orderedtag;       /* Ordered Q tags allowed */
+  volatile unsigned char   activescbs;       /* active scbs */
+  unsigned char            max_activescbs;
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
-  unsigned char            qcntmask;
-  unsigned char            qfullcount;
-  unsigned char            cmdoutcnt;
-  unsigned char            curqincnt;
-  struct Scsi_Host        *next;             /* allow for multiple IRQs */
-  unsigned char            activescbs;       /* active scbs */
-  scb_queue_type           waiting_scbs;     /*
+  volatile unsigned char   qoutfifonext;
+  volatile unsigned char   qinfifonext;
+
+  /*
+   * MAX_TARGETS is currently == 16, so that makes these entries the next
+   * 64 bytes
+   */
+
+#define  DEVICE_PRESENT                 0x01
+#define  BUS_DEVICE_RESET_PENDING       0x02
+#define  DEVICE_TIMEOUT                 0x04
+#define  DEVICE_PRINT_SDTR              0x08
+#define  DEVICE_PRINT_WDTR              0x10
+#define  DEVICE_SUCCESS                 0x20
+#define  DEVICE_TAGGED_SUCCESS          0x40
+  volatile unsigned char   dev_flags[MAX_TARGETS];
+  volatile unsigned char   dev_active_cmds[MAX_TARGETS];
+  unsigned char            dev_temp_queue_depth[MAX_TARGETS];
+  unsigned char            dev_commands_sent[MAX_TARGETS];
+
+  /*
+   * The next 64.... 
+   */
+
+  long                     dev_last_reset[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            dev_mid_level_queue_depth[MAX_TARGETS];
+  unsigned char            dev_last_queue_full[MAX_TARGETS];
+  unsigned char            dev_last_queue_full_count[MAX_TARGETS];
+  unsigned char            dev_max_queue_depth[MAX_TARGETS];
+
+  /*
+   * The next 128....
+   */
+
+  volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
+
+  /*
+   *
+   */
+
+  struct timer_list        dev_timer[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            msg_buf[9];       /* The message for the target */
+  unsigned char            msg_type;
+#define MSG_TYPE_NONE              0x00
+#define MSG_TYPE_INITIATOR_MSGOUT  0x01
+#define MSG_TYPE_INITIATOR_MSGIN   0x02
+  unsigned char            msg_len;          /* Length of message */
+  unsigned char            msg_index;        /* Index into msg_buf array */
+  syncinfo_type            syncinfo[MAX_TARGETS];
+  volatile scb_queue_type  waiting_scbs;     /*
                                               * SCBs waiting for space in
                                               * the QINFIFO.
                                               */
@@ -851,23 +920,41 @@
     Scsi_Cmnd *head;
     Scsi_Cmnd *tail;
   } completeq;
-  struct aic7xxx_device_status {
-    unsigned char active_cmds;
-    unsigned char max_queue_depth;
-    unsigned char temp_queue_depth;
-    unsigned char last_queue_full;
-    unsigned char last_queue_full_count;
-    struct timer_list timer;
-    long last_reset;
-#define  DEVICE_SUCCESS                 0x01
-#define  BUS_DEVICE_RESET_PENDING       0x02
-#define  DEVICE_TIMEOUT                 0x04
-    int  flags;
-    int  commands_sent;
-    scb_queue_type delayed_scbs;
-    Scsi_Cmnd *scsi_cmnd0;
-    Scsi_Cmnd *scsi_cmnd1;
-  } device_status[16];
+
+
+  /*
+   * We put the less frequently used host structure items after the more
+   * frequently used items to try and ease the burden on the cache subsystem.
+   * These entries are not *commonly* accessed, whereas the preceding entries
+   * are accessed very often.  The only exceptions are the qinfifo, qoutfifo,
+   * and untagged_scbs array.  But, they are often accessed only once and each
+   * access into these arrays is likely to blow a cache line, so they are put
+   * down here so we can minimize the number of cache lines required to hold
+   * the preceeding entries.
+   */
+
+  volatile unsigned char   untagged_scbs[256];
+  volatile unsigned char   qoutfifo[256];
+  volatile unsigned char   qinfifo[256];
+  unsigned int             irq;              /* IRQ for this adapter */
+  unsigned short           needsdtr;
+  unsigned short           sdtr_pending;
+  unsigned short           needwdtr;
+  unsigned short           wdtr_pending;
+  int                      instance;         /* aic7xxx instance number */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  int                      scsi_id_b;        /* channel B for twin adapters */
+  unsigned int             bios_address;
+  int                      board_name_index;
+  unsigned long            reset_start;
+  unsigned short           needsdtr_copy;    /* default config */
+  unsigned short           needwdtr_copy;    /* default config */
+  unsigned short           ultraenb;         /* Ultra mode target list */
+  unsigned short           bios_control;     /* bios control - SEEPROM */
+  unsigned short           adapter_control;  /* adapter control - SEEPROM */
+  unsigned char            pci_bus;
+  unsigned char            pci_device_fn;
+
 #ifdef AIC7XXX_PROC_STATS
   /*
    * Statistics Kept:
@@ -879,6 +966,10 @@
    *    < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
    *
    * Total amounts read/written above 512 bytes (amts under ignored)
+   *
+   * NOTE: Enabling this feature is likely to cause a noticeable performance
+   * decrease as the accesses into the stats structures blows apart multiple
+   * cache lines and is CPU time consuming.
    */
   struct aic7xxx_xferstats {
     long xfers;                              /* total xfer count */
@@ -900,7 +991,7 @@
 static struct {
   short period;
   /* Rates in Ultra mode have bit 8 of sxfr set */
-#define		ULTRA_SXFR 0x100
+#define                ULTRA_SXFR 0x100
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
@@ -920,40 +1011,6 @@
 static int num_aic7xxx_syncrates =
     sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
-#ifdef CONFIG_PCI
-static int number_of_3940s = 0;
-static int number_of_3985s = 0;
-#endif /* CONFIG_PCI */
-
-#ifdef AIC7XXX_DEBUG
-
-#if 0
-static void
-debug_scb(struct aic7xxx_scb *scb)
-{
-  struct aic7xxx_hwscb *hscb = scb->hscb;
-
-  printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
-    scb,
-    hscb->control,
-    hscb->target_channel_lun,
-    hscb->SCSI_cmd_length,
-    hscb->SCSI_cmd_pointer );
-  printk("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
-    hscb->data_count,
-    hscb->data_pointer,
-    hscb->SG_segment_count,
-    hscb->SG_list_pointer);
-  printk("        sg_addr:%lx sg_len:%ld\n",
-    hscb->sg_list[0].address,
-    hscb->sg_list[0].length);
-}
-#endif
-
-#else
-#  define debug_scb(x)
-#endif AIC7XXX_DEBUG
-
 #define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
                         (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
                         ((scb->hscb)->target_channel_lun & 0x07)
@@ -962,49 +1019,26 @@
                         ((cmd->target) & 0x0f), \
                         ((cmd->lun) & 0x07)
 
-static inline int
-CHAN_TO_INT(char chan)
-{
-  switch(chan)
-  {
-    case ALL_CHANNELS:
-	return(-1);
-    case 'B':
-    case 'b':
-        return(1);
-    case 'A':
-    case 'a':
-        return(0);
-    default:
-        printk(KERN_WARNING "aic7xxx: Bad usage of char channel.\n");
-        return(0);
-  }
-}
-
-static inline char
-INT_TO_CHAN(int chan)
-{
-  switch(chan)
-  {
-    case -1:
-	return(ALL_CHANNELS);
-    case 1:
-        return('B');
-    case 0:
-        return('A');
-    default:
-        printk(KERN_WARNING "aic7xxx: Bad usage of int channel.\n");
-        return('A');
-  }
-}
+#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
 
+/*
+ * A nice little define to make doing our printks a little easier
+ */
 
-#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
 
 /*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
  *       cards in the system.  This should be fixed.
  */
+static int aic7xxx_7895_irq_hack = -1;       /* This enables a hack to fix
+                                              * IRQ settings on buggy 7895
+                                              * MB controller setups
+                                              *  -1 == Disable this hack
+                                              *   0 == Use the Channel A IRQ
+                                              *   1 == Use the Channel B IRQ
+                                              */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
 static int aic7xxx_irq_trigger = -1;         /*
@@ -1012,8 +1046,96 @@
                                               *  0 use edge triggered
                                               *  1 use level triggered
                                               */
-static int aic7xxx_enable_ultra = 0;         /* enable ultra SCSI speeds */
-static int aic7xxx_verbose = 0;	             /* verbose messages */
+static int aic7xxx_reverse_scan = 0;         /*
+                                              * Set this to anything but 0
+                                              * to make the probe code
+                                              * reverse the order of PCI
+                                              * devices
+                                              */
+static int aic7xxx_override_term = 0;        /*
+                                              * Set this to non-0 to make the
+                                              * driver override any BIOS
+                                              * configured termination
+                                              * settings based upon the
+                                              * results of the cable detect
+                                              * logic.  This only applies
+                                              * to cards that have cable
+                                              * detection logic and a SEEPROM
+                                              */
+static int aic7xxx_panic_on_abort = 0;       /*
+                                              * Set this to non-0 in order
+                                              * to force the driver to panic
+                                              * the kernel and print out
+                                              * debugging info on an abort
+                                              * or reset call into the
+                                              * driver.
+                                              */
+
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char * aic7xxx = NULL;
+
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+
+#endif
+
+/*
+ * See the comments earlier in the file for what this item is all about
+ * If you have more than 4 controllers, you will need to increase the
+ * the number of items in the array below.  Additionally, if you don't
+ * want to have lilo pass a humongous config line to the aic7xxx driver,
+ * then you can get in and manually adjust these instead of leaving them
+ * at the default.  Pay attention to the comments earlier in this file
+ * concerning this array if you are going to hand modify these values.
+ */
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+#define VERBOSE_NORMAL         0x0000
+#define VERBOSE_NEGOTIATION    0x0001
+#define VERBOSE_SEQINT         0x0002
+#define VERBOSE_SCSIINT        0x0004
+#define VERBOSE_PROBE          0x0008
+#define VERBOSE_PROBE2         0x0010
+#define VERBOSE_QUEUE          0x0020
+#define VERBOSE_MINOR_ERROR    0x0040
+#define VERBOSE_QUEUE_FULL     0x0080
+#define VERBOSE_ABORT          0x0f00
+#define VERBOSE_ABORT_MID      0x0100
+#define VERBOSE_ABORT_FIND     0x0200
+#define VERBOSE_ABORT_PROCESS  0x0400
+#define VERBOSE_ABORT_RETURN   0x0800
+#define VERBOSE_RESET          0xf000
+#define VERBOSE_RESET_MID      0x1000
+#define VERBOSE_RESET_FIND     0x2000
+#define VERBOSE_RESET_PROCESS  0x4000
+#define VERBOSE_RESET_RETURN   0x8000
+static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
+           VERBOSE_PROBE;                     /* verbose messages */
 
 
 /****************************************************************************
@@ -1023,52 +1145,44 @@
  *
  ***************************************************************************/
 
+
 static inline unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
-  if (p->maddr != NULL)
-    return (p->maddr[port]);
+  unsigned char x;
+  if(p->maddr)
+    x = p->maddr[port];
   else
-    return (inb(p->base + port));
+    x = inb(p->base + port);
+  mb();
+  return(x);
 }
 
 static inline void
 aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
     p->maddr[port] = val;
   else
     outb(val, p->base + port);
+  mb();
 }
 
 static inline void
 aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
   {
-#ifdef __alpha__
     int i;
 
     for (i=0; i < size; i++)
     {
       p->maddr[port] = valp[i];
     }
-#else
-    __asm __volatile("
-      cld;
-    1:  lodsb;
-      movb %%al,(%0);
-      loop 1b"      :
-              :
-      "r" (p->maddr + port),
-      "S" (valp), "c" (size)  :
-      "%esi", "%ecx", "%eax");
-#endif
   }
   else
-  {
     outsb(p->base + port, valp, size);
-  }
+  mb();
 }
 
 /*+F*************************************************************************
@@ -1085,6 +1199,7 @@
 {
   int   i, n;
   char *p;
+  char *end;
 
   static struct {
     const char *name;
@@ -1093,25 +1208,112 @@
     { "extended",    &aic7xxx_extended },
     { "no_reset",    &aic7xxx_no_reset },
     { "irq_trigger", &aic7xxx_irq_trigger },
-    { "ultra",       &aic7xxx_enable_ultra },
     { "verbose",     &aic7xxx_verbose },
-    { NULL,          NULL }
+    { "reverse_scan",&aic7xxx_reverse_scan },
+    { "7895_irq_hack", &aic7xxx_7895_irq_hack },
+    { "override_term", &aic7xxx_override_term },
+    { "panic_on_abort", &aic7xxx_panic_on_abort },
+    { "tag_info",    NULL }
   };
 
-  for (p = strtok(s, ","); p; p = strtok(NULL, ","))
+  end = strchr(s, '\0');
+
+  for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
   {
-    for (i = 0; options[i].name; i++)
+    for (i = 0; i < NUMBER(options); i++)
     {
       n = strlen(options[i].name);
       if (!strncmp(options[i].name, p, n))
       {
-        if (p[n] == ':')
+        if (!strncmp(p, "tag_info", n))
+        {
+          if (p[n] == ':')
+          {
+            char *base;
+            char *tok, *tok_end, *tok_end2;
+            char tok_list[] = { '.', ',', '{', '}', '\0' };
+            int i, instance = -1, device = -1;
+            unsigned char done = FALSE;
+
+            base = p;
+            tok = base + n + 1;  /* Forward us just past the ':' */
+            tok_end = strchr(tok, '\0');
+            if (tok_end < end)
+              *tok_end = ',';
+            while(!done)
+            {
+              switch(*tok)
+              {
+                case '{':
+                  if (instance == -1)
+                    instance = 0;
+                  else if (device == -1)
+                    device = 0;
+                  tok++;
+                  break;
+                case '}':
+                  if (device != -1)
+                    device = -1;
+                  else if (instance != -1)
+                    instance = -1;
+                  tok++;
+                  break;
+                case ',':
+                case '.':
+                  if (instance == -1)
+                    done = TRUE;
+                  else if (device >= 0)
+                    device++;
+                  else if (instance >= 0)
+                    instance++;
+                  if ( (device >= MAX_TARGETS) || 
+                       (instance >= NUMBER(aic7xxx_tag_info)) )
+                    done = TRUE;
+                  tok++;
+                  if (!done)
+                  {
+                    base = tok;
+                  }
+                  break;
+                case '\0':
+                  done = TRUE;
+                  break;
+                default:
+                  done = TRUE;
+                  tok_end = strchr(tok, '\0');
+                  for(i=0; tok_list[i]; i++)
+                  {
+                    tok_end2 = strchr(tok, tok_list[i]);
+                    if ( (tok_end2) && (tok_end2 < tok_end) )
+                    {
+                      tok_end = tok_end2;
+                      done = FALSE;
+                    }
+                  }
+                  if ( (instance >= 0) && (device >= 0) &&
+                       (instance < NUMBER(aic7xxx_tag_info)) &&
+                       (device < MAX_TARGETS) )
+                    aic7xxx_tag_info[instance].tag_commands[device] =
+                      simple_strtoul(tok, NULL, 0) & 0xff;
+                  tok = tok_end;
+                  break;
+              }
+            }
+            while((p != base) && (p != NULL))
+              p = strtok(NULL, ",.");
+          }
+        }
+        else if (p[n] == ':')
         {
           *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
         }
+        else if (!strncmp(p, "verbose", n))
+        {
+          *(options[i].flag) = 0xff69;
+        }
         else
         {
-          *(options[i].flag) += 1;
+          *(options[i].flag) = ~(*(options[i].flag));
         }
       }
     }
@@ -1130,8 +1332,8 @@
 static inline void
 pause_sequencer(struct aic7xxx_host *p)
 {
-  outb(p->pause, p->base + HCNTRL);
-  while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+  aic_outb(p, p->pause, HCNTRL);
+  while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
   {
     ;
   }
@@ -1149,9 +1351,10 @@
 unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
 {
   if (unpause_always ||
-      ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
+      ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
+        !(p->flags & AHC_HANDLING_REQINITS) ) )
   {
-    outb(p->unpause, p->base + HCNTRL);
+    aic_outb(p, p->unpause, HCNTRL);
   }
 }
 
@@ -1167,17 +1370,16 @@
 restart_sequencer(struct aic7xxx_host *p)
 {
   /* Set the sequencer address to 0. */
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   /*
    * Reset and unpause the sequencer.  The reset is suppose to
-   * start the sequencer running, but we do an unpause to make
-   * sure.
+   * start the sequencer running, so we immediately do a pause_sequencer
+   * since some of our code expects the sequencer paused after a restart
    */
-  outb(SEQRESET | FASTMODE, p->base + SEQCTL);
-
-  unpause_sequencer(p, /*unpause_always*/ TRUE);
+  aic_outb(p, SEQRESET | FASTMODE, SEQCTL);
+  pause_sequencer(p);
 }
 
 
@@ -1229,11 +1431,12 @@
 aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
 {
   unsigned char opcode;
-  struct ins_format3 *instr;
+  struct ins_format3 instr;
+  unsigned char dconsts[4] = { 0, 0, 0, 0 };
 
-  instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+  instr = *(struct ins_format3 *) &seqprog[instrptr * 4];
   /* Pull the opcode */
-  opcode = instr->opcode_addr >> 1;
+  opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1;
   switch (opcode)
   {
     case AIC_OP_JMP:
@@ -1246,15 +1449,13 @@
     case AIC_OP_JZ:
     {
       int address_offset;
-      struct ins_format3 new_instr;
       unsigned int address;
       struct patch *patch;
       int i;
 
       address_offset = 0;
-      new_instr = *instr;  /* Strucure copy */
-      address = new_instr.address;
-      address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+      address = instr.address;
+      address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8;
       for (i = 0; i < NUMBER(patches); i++)
       {
         patch = &patches[i];
@@ -1268,20 +1469,23 @@
         }
       }
       address -= address_offset;
-      new_instr.address = address &0xFF;
-      new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
-      new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
-      outsb(p->base + SEQRAM, &new_instr.immediate, 4);
-      break;
+      instr.address = address & 0xFF;
+      instr.opcode_addr &= ~ADDR_HIGH_BIT;
+      instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
     }
-
+       /*  Fall through  */
     case AIC_OP_OR:
     case AIC_OP_AND:
     case AIC_OP_XOR:
     case AIC_OP_ADD:
     case AIC_OP_ADC:
+      if (instr.opcode_addr & DOWNLOAD_CONST_IMMEDIATE)
+      {
+        instr.immediate = dconsts[instr.immediate];
+      }
+      instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE;
     case AIC_OP_ROL:
-      outsb(p->base + SEQRAM, &instr->immediate, 4);
+      aic_outsb(p, SEQRAM, &instr.immediate, 4);
       break;
 
     default:
@@ -1306,23 +1510,60 @@
   int i;
   int downloaded;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-    printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+    printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
   }
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk("\n");
   options = 1;  /* Code for all options. */
   downloaded = 0;
-  if ((p->flags & ULTRA_ENABLED) != 0)
+  if (p->type & AHC_ULTRA)
+  {
     options |= ULTRA;
-  if (p->bus_type == AIC_TWIN)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option ULTRA\n",
+        p->host_no);
+  }
+  if (p->type & AHC_TWIN)
+  {
     options |= TWIN_CHANNEL;
-  if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option "
+        "TWIN_CHANNEL\n", p->host_no);
+  }
+  if (p->type & AHC_WIDE)
+  {
+    options |= WIDE;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option WIDE\n",
+        p->host_no);
+  }
+  /* if (p->scb_data->maxscbs > p->scb_data->maxhscbs)  this should always
+                                                        be true, don't test,
+                                                        just do.            */
+  {
     options |= SCB_PAGING;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option SCB_PAGING\n",
+        p->host_no);
+  }
+  /* We don't actually support target mode yet, so leave this out 
+  if (p->flags & AHC_TARGETMODE)
+    options |= TARGET_MODE; */
+
+  if ( (options & ~(ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01)) )
+  {
+    printk(KERN_INFO "(scsi%d) Unknown bits set in the options field, "
+      "correcting.\n", p->host_no);
+    options &= ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01;
+  }
+
 
   cur_patch = patches;
-  outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, PERRORDIS | LOADRAM, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   for (i = 0; i < sizeof(seqprog) / 4;  i++)
   {
@@ -1336,13 +1577,16 @@
     downloaded++;
   }
 
-  outb(FASTMODE, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk(KERN_INFO "(scsi%d) Download complete,", p->host_no);
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-     printk(" %d instructions downloaded\n", downloaded);
+    printk(" %d instructions downloaded\n", downloaded);
   }
 }
 
@@ -1358,7 +1602,7 @@
 static void
 aic7xxx_delay(int seconds)
 {
-  int i;
+  unsigned int i;
 
   /*                        
    * Call udelay() for 1 millisecond inside a loop for  
@@ -1372,131 +1616,57 @@
 
 /*+F*************************************************************************
  * Function:
- *   rcs_version
+ *   aic7xxx_info
  *
  * Description:
- *   Return a string containing just the RCS version number from either
- *   an Id or Revision RCS clause.
+ *   Return a string describing the driver.
  *-F*************************************************************************/
 const char *
-rcs_version(const char *version_info)
+aic7xxx_info(struct Scsi_Host *dooh)
 {
-  static char buf[10];
-  char *bp, *ep;
-
-  bp = NULL;
-  strcpy(buf, "????");
-  if (!strncmp(version_info, "$Id: ", 5))
-  {
-    if ((bp = strchr(version_info, ' ')) != NULL)
-    {
-      bp++;
-      if ((bp = strchr(bp, ' ')) != NULL)
-      {
-	bp++;
-      }
-    }
-  }
-  else
-  {
-    if (!strncmp(version_info, "$Revision: ", 11))
-    {
-      if ((bp = strchr(version_info, ' ')) != NULL)
-      {
-	bp++;
-      }
-    }
-  }
-
-  if (bp != NULL)
-  {
-    if ((ep = strchr(bp, ' ')) != NULL)
-    {
-      register int len = ep - bp;
+  static char buffer[256];
+  char *bp;
+  struct aic7xxx_host *p;
 
-      strncpy(buf, bp, len);
-      buf[len] = '\0';
-    }
-  }
+  bp = &buffer[0];
+  p = (struct aic7xxx_host *)dooh->hostdata;
+  memset(bp, 0, sizeof(buffer));
+  strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+  strcat(bp, AIC7XXX_C_VERSION);
+  strcat(bp, "/");
+  strcat(bp, AIC7XXX_H_VERSION);
+  strcat(bp, "\n");
+  strcat(bp, "       <");
+  strcat(bp, board_names[p->board_name_index]);
+  strcat(bp, ">");
 
-  return buf;
+  return(bp);
 }
 
+
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_info
+ *   aic7xxx_scsirate
  *
  * Description:
- *   Return a string describing the driver.
+ *   Look up the valid period to SCSIRATE conversion in our table
  *-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *notused)
+static unsigned char
+aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
+    unsigned char *period, unsigned char *offset, int target, int channel,
+    int set)
 {
-  static char buffer[128];
+  int i = num_aic7xxx_syncrates;
+  unsigned char response_period;
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned char lun;
 
-  strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
-  strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
-  strcat(buffer, "/");
-  strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
-#if 0
-  strcat(buffer, "/");
-  strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
-#endif
+  tindex = target | (channel << 3);
+  target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
 
-  return buffer;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_length
- *
- * Description:
- *   How much data should be transferred for this SCSI command?  Assume
- *   all segments are to be transferred except for the last sg_last
- *   segments.  This will allow us to compute underflow easily.  To
- *   calculate the total length of the command, use sg_last = 0.  To
- *   calculate the length of all but the last 2 SG segments, use
- *   sg_last = 2.
- *-F*************************************************************************/
-static unsigned
-aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
-{
-  int i, segments;
-  unsigned length;
-  struct scatterlist *sg;
-
-  segments = cmd->use_sg - sg_last;
-  sg = (struct scatterlist *) cmd->request_buffer;
-
-  if (cmd->use_sg)
-  {
-    for (i = length = 0; i < segments; i++)
-    {
-      length += sg[i].length;
-    }
-  }
-  else
-  {
-    length = cmd->request_bufflen;
-  }
-
-  return (length);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_scsirate
- *
- * Description:
- *   Look up the valid period to SCSIRATE conversion in our table
- *-F*************************************************************************/
-static void
-aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-    unsigned char *period, unsigned char *offset, int target, char channel)
-{
-  int i = num_aic7xxx_syncrates;
-  unsigned long ultra_enb_addr;
-  unsigned char ultra_enb, sxfrctl0;
+  response_period = *period;
 
   /*
    * If the offset is 0, then the device is requesting asynchronous
@@ -1512,7 +1682,7 @@
          * Watch out for Ultra speeds when ultra is not enabled and
          * vice-versa.
          */
-        if (!(p->flags & ULTRA_ENABLED) &&
+        if (!(p->type & AHC_ULTRA) &&
             (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
         {
           /*
@@ -1525,11 +1695,31 @@
         *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
         *period = aic7xxx_syncrates[i].period;
 
-        if (aic7xxx_verbose)
+        /*
+         * When responding to a target that requests
+         * sync, that rate may fall between two rates
+         * that we can output, but still be a rate
+         * that we can receive.  Because of this,
+         * we may want to respond to the target with
+         * the same rate that it sent to us even
+         * if the period we use to send data to it
+         * is lower.  Only lower the response period
+         * if we must.
+         */
+        if ((i == 0) ||
+           ((aic7xxx_syncrates[i-1].rate & ULTRA_SXFR) != 0
+             && (p->type & AHC_ULTRA) == 0))
+        {
+          response_period = *period;
+        }
+
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
         {
-          printk("(scsi%d:%d:%d:%d) Synchronous at %sMHz, "
-                 "offset %d.\n", p->host_no, CHAN_TO_INT(channel), target, 0,
+          printk(INFO_LEAD "Synchronous at %sMHz, "
+                 "offset %d.\n", p->host_no, channel, target, lun,
                  aic7xxx_syncrates[i].english, *offset);
+          p->dev_flags[tindex] &= ~ DEVICE_PRINT_SDTR;
         }
         break;
       }
@@ -1544,35 +1734,43 @@
     *scsirate = 0;
     *period = 0;
     *offset = 0;
-    if (aic7xxx_verbose)
-    {
-      printk("(scsi%d:%d:%d:%d) Using asynchronous transfers.\n",
-             p->host_no, CHAN_TO_INT(channel), target, 0);
+    response_period = 0;
+    if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+         (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+    {
+      printk(INFO_LEAD "Using asynchronous transfers.\n",
+             p->host_no, channel, target, lun);
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
     }
   }
 
   /*
    * Ensure Ultra mode is set properly for this target.
    */
-  ultra_enb_addr = ULTRA_ENB;
-  if ((channel == 'B') || (target > 7))
+  if ( (*scsirate != 0) && 
+       (aic7xxx_syncrates[i].rate & ULTRA_SXFR) )
   {
-    ultra_enb_addr++;
+    p->ultraenb |= target_mask;
   }
-  ultra_enb = inb(p->base + ultra_enb_addr);
-  sxfrctl0 = inb(p->base + SXFRCTL0);
-  if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+  else
   {
-    ultra_enb |= 0x01 << (target & 0x07);
-    sxfrctl0 |= FAST20;
+    p->ultraenb &= ~target_mask;
   }
-  else
+  if (set)
   {
-    ultra_enb &= ~(0x01 << (target & 0x07));
+    unsigned char sxfrctl0;
+
+    sxfrctl0 = aic_inb(p, SXFRCTL0);
     sxfrctl0 &= ~FAST20;
+    if (p->ultraenb & target_mask)
+    {
+      sxfrctl0 |= FAST20;
+    }
+    aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+    aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1);
+    aic_outb(p, sxfrctl0, SXFRCTL0);
   }
-  outb(ultra_enb, p->base + ultra_enb_addr);
-  outb(sxfrctl0, p->base + SXFRCTL0);
+  return(response_period);
 }
 
 /*+F*************************************************************************
@@ -1584,7 +1782,7 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_init(scb_queue_type *queue)
+scbq_init(volatile scb_queue_type *queue)
 {
   queue->head = NULL;
   queue->tail = NULL;
@@ -1599,16 +1797,18 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
   scb->q_next = queue->head;
   queue->head = scb;
   if (queue->tail == NULL)       /* If list was empty, update tail. */
     queue->tail = queue->head;
-  restore_flags(processor_flags);
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -1619,17 +1819,22 @@
  *   Remove an SCB from the head of the list.
  *
  *-F*************************************************************************/
-static inline void
-scbq_remove_head(scb_queue_type *queue)
+static __inline struct aic7xxx_scb *
+scbq_remove_head(volatile scb_queue_type *queue)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
+  struct aic7xxx_scb * scbp;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
+  scbp = queue->head;
   if (queue->head != NULL)
     queue->head = queue->head->q_next;
   if (queue->head == NULL)       /* If list is now empty, update tail. */
     queue->tail = NULL;
-  restore_flags(processor_flags);
+  DRIVER_UNLOCK
+  return(scbp);
 }
 
 /*+F*************************************************************************
@@ -1641,11 +1846,13 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
   if (queue->head == scb)
   {
     /* At beginning of queue, remove from head. */
@@ -1674,7 +1881,7 @@
       }
     }
   }
-  restore_flags(processor_flags);
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -1686,19 +1893,20 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
   scb->q_next = NULL;
   if (queue->tail != NULL)       /* Add the scb at the end of the list. */
     queue->tail->q_next = scb;
-
   queue->tail = scb;             /* Update the tail. */
   if (queue->head == NULL)       /* If list was empty, update head. */
     queue->head = queue->tail;
-  restore_flags(processor_flags);
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -1712,11 +1920,11 @@
  *   to be reset and all devices on that channel must be aborted.
  *-F*************************************************************************/
 static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
-    int lun, unsigned char tag)
+aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    int target, int channel, int lun, unsigned char tag)
 {
   int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
-  char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
   int slun = scb->hscb->target_channel_lun & 0x07;
   int match;
 
@@ -1728,22 +1936,12 @@
   if (match != 0)
     match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
 
-  if (aic7xxx_verbose > 4)
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
   {
-    if (match)
-    {
-      printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) matches search criteria"
-        " (scsi%d:%d:%d:%d:tag%d)\n", scb->cmd->device->host->host_no,
-        CTL_OF_SCB(scb), scb->hscb->tag, scb->cmd->device->host->host_no,
-        CHAN_TO_INT(channel), target, lun, tag);
-    }
-    else
-    {
-      printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) doesn't match search criteria"
-        " (scsi%d:%d:%d:%d:tag%d)\n", scb->cmd->device->host->host_no,
-        CTL_OF_SCB(scb), scb->hscb->tag, scb->cmd->device->host->host_no,
-        CHAN_TO_INT(channel), target, lun, tag);
-    }
+    printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
+      " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
+      scb->hscb->tag, (match) ? "matches" : "doesn't match",
+      p->host_no, channel, target, lun, tag);
   }
 
   return (match);
@@ -1763,10 +1961,11 @@
    * Invalidate the tag so that aic7xxx_find_scb doesn't think
    * it's active
    */
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+  aic_outb(p, 0, SCB_CONTROL);
 
-  outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
-  outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+  aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
+  aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
 }
 
 /*+F*************************************************************************
@@ -1783,29 +1982,25 @@
   unsigned char next;
   unsigned char prev;
 
-  outb(scbptr, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-  prev = inb(p->base + SCB_PREV);
-
-  outb(0, p->base + SCB_CONTROL);
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
-
+  aic_outb(p, scbptr, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+  prev = aic_inb(p, SCB_PREV);
   aic7xxx_add_curscb_to_free_list(p);
 
   if (prev != SCB_LIST_NULL)
   {
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   else
   {
-    outb(next, p->base + DISCONNECTED_SCBH);
+    aic_outb(p, next, DISCONNECTED_SCBH);
   }
 
   if (next != SCB_LIST_NULL)
   {
-    outb(next, p->base + SCBPTR);
-    outb(prev, p->base + SCB_PREV);
+    aic_outb(p, next, SCBPTR);
+    aic_outb(p, prev, SCB_PREV);
   }
   return next;
 }
@@ -1817,23 +2012,10 @@
  * Description:
  *   Set the specified target busy.
  *-F*************************************************************************/
-static void
-aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, unsigned char scbid)
+static __inline void
+aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  unsigned char active_scb;
-  unsigned char info_scb;
-  unsigned int  scb_offset;
-
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
-
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  outb(scbid, p->base + scb_offset);
-  outb(active_scb, p->base + SCBPTR);
+  p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
 }
 
 /*+F*************************************************************************
@@ -1844,28 +2026,17 @@
  *   Returns the index of the busy target, and optionally sets the
  *   target inactive.
  *-F*************************************************************************/
-static unsigned char
-aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, int unbusy)
+static __inline unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
+    int unbusy)
 {
-  unsigned char active_scb;
-  unsigned char info_scb;
   unsigned char busy_scbid;
-  unsigned int  scb_offset;
 
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
-
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  busy_scbid = inb(p->base + scb_offset);
+  busy_scbid = p->untagged_scbs[tcl];
   if (unbusy)
   {
-    outb(SCB_LIST_NULL, p->base + scb_offset);
+    p->untagged_scbs[tcl] = SCB_LIST_NULL;
   }
-  outb(active_scb, p->base + SCBPTR);
   return (busy_scbid);
 }
 
@@ -1885,17 +2056,17 @@
   unsigned char saved_scbptr;
   unsigned char curindex;
 
-  saved_scbptr = inb(p->base + SCBPTR);
+  saved_scbptr = aic_inb(p, SCBPTR);
   curindex = 0;
   for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
   {
-    outb(curindex, p->base + SCBPTR);
-    if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+    aic_outb(p, curindex, SCBPTR);
+    if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
     {
       break;
     }
   }
-  outb(saved_scbptr, p->base + SCBPTR);
+  aic_outb(p, saved_scbptr, SCBPTR);
   if (curindex >= p->scb_data->maxhscbs)
   {
     curindex = SCB_LIST_NULL;
@@ -1912,43 +2083,83 @@
  *   Get an SCB from the free list or by allocating a new one.
  *-F*************************************************************************/
 static struct aic7xxx_scb *
-aic7xxx_allocate_scb(struct aic7xxx_host *p)
+aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
 {
   struct aic7xxx_scb   *scbp = NULL;
-  struct aic7xxx_hwscb *hscbp = NULL;
+  int scb_size = sizeof(struct aic7xxx_scb) +
+                 sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+  int i;
+  unsigned long scb_count = 0;
+  struct hw_scatterlist *hsgp;
+  struct aic7xxx_scb *scb_ap;
+
 
-  scbp = p->scb_data->free_scbs.head;
-  if (scbp != NULL)
+  if (force_alloc == FALSE)
   {
-    scbq_remove_head(&p->scb_data->free_scbs);
+    scbp = scbq_remove_head(&p->scb_data->free_scbs);
+    if (scbp != NULL)
+      return(scbp);
   }
-  else
+  /*
+   * Either there wasn't an SCB or this is a strictly allocation call
+   */
+
+  if (p->scb_data->numscbs < p->scb_data->maxscbs)
   {
-    if (p->scb_data->numscbs < p->scb_data->maxscbs)
+
+    /*
+     * Optimize for 30 scbs at a time, but allow a final allocation of
+     * fewer than 30 scbs.  Except on 64 bit platforms, we optimize for
+     * 29 SCBs at a time because a pointer is 4 bytes larger and we don't
+     * want to overrun this suppossedly 32K allocation to 64K and waste
+     * tons of space.
+     */
+    if( sizeof(void *) == sizeof(int) )
+      scb_count = MIN(30, p->scb_data->maxscbs - p->scb_data->numscbs);
+    else
+      scb_count = MIN(29, p->scb_data->maxscbs - p->scb_data->numscbs);
+    
+    scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
+    if (scb_ap != NULL)
     {
-      int scb_index = p->scb_data->numscbs;
-      int scb_size = sizeof(struct aic7xxx_scb) +
-                     sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
-
-      scbp = kmalloc(scb_size, GFP_ATOMIC);
-      if (scbp != NULL)
-      {
-        memset(scbp, 0, sizeof(struct aic7xxx_scb));
-        hscbp = &p->scb_data->hscbs[scb_index];
-        scbp->hscb = hscbp;
-        scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
-        memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
-        hscbp->tag = scb_index;
-        p->scb_data->numscbs++;
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
+      {
+        if (p->scb_data->numscbs == 0)
+          printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+        else
+          printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+      }
+      memset(scb_ap, 0, scb_count * scb_size);
+      hsgp = (struct hw_scatterlist *) &scb_ap[scb_count];
+      for (i=0; i < scb_count; i++)
+      {
+        scbp = &scb_ap[i];
+        scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+        scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+        memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+        scbp->hscb->tag = p->scb_data->numscbs;
         /*
          * Place in the scb array; never is removed
          */
-        p->scb_data->scb_array[scb_index] = scbp;
+        p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+        scbq_insert_head(&p->scb_data->free_scbs, scbp);
       }
     }
+    else
+    {
+      return(NULL);
+    }
+  }
+  if (force_alloc == TRUE)
+  {
+    return((struct aic7xxx_scb *)scb_count);
+  }
+  else
+  {
+    return(scbq_remove_head(&p->scb_data->free_scbs));
   }
-
-  return (scbp);
 }
 
 /*+F*************************************************************************
@@ -1963,12 +2174,8 @@
 static inline void
 aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  unsigned int flags;
-  save_flags(flags);
-  cli();
   cmd->host_scribble = (char *)p->completeq.head;
   p->completeq.head = cmd;
-  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1982,20 +2189,29 @@
 aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
-  unsigned int processor_flags;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned int cpu_flags = 0;
   
-  save_flags(processor_flags);
-  cli();
+  DRIVER_LOCK
   while (p->completeq.head != NULL)
   {
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    restore_flags(processor_flags);
+    sti();
     cmd->scsi_done(cmd);
     cli();
   }
-  restore_flags(processor_flags);
+  DRIVER_UNLOCK
+#else
+  while (p->completeq.head != NULL)
+  {
+    cmd = p->completeq.head;
+    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+    cmd->host_scribble = NULL;
+    cmd->scsi_done(cmd);
+  }
+#endif
 }
 
 /*+F*************************************************************************
@@ -2008,14 +2224,15 @@
 static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_hwscb *hscb;
-
-  hscb = scb->hscb;
 
   scb->flags = SCB_FREE;
   scb->cmd = NULL;
-  hscb->control = 0;
-  hscb->target_status = 0;
+  scb->sg_count = 0;
+  scb->sg_length = 0;
+  scb->tag_action = 0;
+  scb->hscb->control = 0;
+  scb->hscb->target_status = 0;
+  scb->hscb->target_channel_lun = SCB_LIST_NULL;
 
   scbq_insert_head(&p->scb_data->free_scbs, scb);
 }
@@ -2037,24 +2254,24 @@
 
   if (scb->flags & SCB_RECOVERY_SCB)
   {
-    p->flags &= ~ABORT_PENDING;
+    p->flags &= ~AHC_ABORT_PENDING;
   }
   if (scb->flags & SCB_RESET)
   {
       cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
-	(cmd->result & 0xffff);
+        (cmd->result & 0xffff);
   }
   else if (scb->flags & SCB_ABORT)
   {
       cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
-	(cmd->result & 0xffff);
+        (cmd->result & 0xffff);
   }
   if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
 
-    mask = 0x01 << TARGET_INDEX(scb->cmd);
+    mask = 0x01 << tindex;
  
     /*
      * Check to see if we get an invalid message or a message error
@@ -2072,6 +2289,17 @@
       p->wdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Wide Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
+        }
         p->needwdtr &= ~mask;
         p->needwdtr_copy &= ~mask;
       }
@@ -2081,54 +2309,79 @@
       p->sdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Sync Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+        }
         p->needsdtr &= ~mask;
         p->needsdtr_copy &= ~mask;
       }
     }
   }
-  queue_depth = (p->device_status[tindex].timer.expires) ?
-		 p->device_status[tindex].temp_queue_depth :
-		 p->device_status[tindex].max_queue_depth;
-  scbp = p->device_status[tindex].delayed_scbs.head;
-  if ( (scbp != NULL) && 
-       (queue_depth > p->device_status[tindex].active_cmds) )
-  {
-    scbq_remove_head(&p->device_status[tindex].delayed_scbs);
-    scbq_insert_tail(&p->waiting_scbs, scbp);
-    scbp = p->device_status[tindex].delayed_scbs.head;
-    if ( (scbp != NULL) && 
-         (queue_depth > (p->device_status[tindex].active_cmds + 1)) )
-    {
-      scbq_remove_head(&p->device_status[tindex].delayed_scbs);
-      scbq_insert_tail(&p->waiting_scbs, scbp);
-    }
-  }
-  if ( (p->device_status[tindex].timer.expires) &&
-      ((p->device_status[tindex].active_cmds == 1) ||
-       (p->device_status[tindex].max_queue_depth ==
-	p->device_status[tindex].temp_queue_depth)) )
-  {
-    del_timer(&p->device_status[tindex].timer);
-    p->device_status[tindex].timer.expires = 0;
-    p->device_status[tindex].temp_queue_depth = 
-          p->device_status[tindex].max_queue_depth;
+  queue_depth = p->dev_temp_queue_depth[tindex];
+  if (queue_depth >= p->dev_active_cmds[tindex])
+  {
+    scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+    if (scbp)
+    {
+      if (queue_depth == 1)
+      {
+        /*
+         * Give extra preference to untagged devices, such as CD-R devices
+         * This makes it more likely that a drive *won't* stuff up while
+         * waiting on data at a critical time, such as CD-R writing and
+         * audio CD ripping operations.  Should also benefit tape drives.
+         */
+        scbq_insert_head(&p->waiting_scbs, scbp);
+      }
+      else
+      {
+        scbq_insert_tail(&p->waiting_scbs, scbp);
+      }
+    }
+    if ( (queue_depth > p->dev_active_cmds[tindex]) && scbp)
+    {
+      scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+      if (scbp)
+        scbq_insert_tail(&p->waiting_scbs, scbp);
+    }
+  }
+  p->dev_active_cmds[tindex]--;
+  p->activescbs--;
+
+  /*
+   * If this was an untagged I/O, unbusy the target so the sequencer won't
+   * mistake things later
+   */
+  if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
+      scb->hscb->tag)
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
   }
-  p->device_status[tindex].active_cmds--;
-  aic7xxx_free_scb(p, scb);
-  aic7xxx_queue_cmd_complete(p, cmd);
 
 #ifdef AIC7XXX_PROC_STATS
-  if ( (cmd->cmnd[0] != TEST_UNIT_READY) &&
-       (cmd->cmnd[0] != INQUIRY) )
   {
     int actual;
 
     /*
      * XXX: we should actually know how much actually transferred
      * XXX: for each command, but apparently that's too difficult.
+     * 
+     * We set a lower limit of 512 bytes on the transfer length.  We
+     * ignore anything less than this because we don't have a real
+     * reason to count it.  Read/Writes to tapes are usually about 20K
+     * and disks are a minimum of 512 bytes unless you want to count
+     * non-read/write commands (such as TEST_UNIT_READY) which we don't
      */
-    actual = aic7xxx_length(cmd, 0);
-    if ((actual > 0) && (((cmd->result >> 16) & 0xf) == DID_OK))
+    actual = scb->sg_length;
+    if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
     {
       struct aic7xxx_xferstats *sp;
       long *ptr;
@@ -2137,7 +2390,14 @@
       sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
       sp->xfers++;
 
-      if (cmd->request.cmd == WRITE)
+      /*
+       * For block devices, cmd->request.cmd is always == either READ or
+       * WRITE.  For character devices, this isn't always set properly, so
+       * we check data_cmnd[0].  This catches the conditions for st.c, but
+       * I'm still not sure if request.cmd is valid for sg devices.
+       */
+      if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
+           (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
       {
         sp->w_total++;
         sp->w_total512 += (actual >> 9);
@@ -2164,6 +2424,10 @@
     }
   }
 #endif /* AIC7XXX_PROC_STATS */
+
+  aic7xxx_free_scb(p, scb);
+  aic7xxx_queue_cmd_complete(p, cmd);
+
 }
 
 /*+F*************************************************************************
@@ -2186,17 +2450,17 @@
     scb = p->scb_data->scb_array[i];
     if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
-      if (aic7xxx_verbose > 3)
-        printk("(scsi%d:%d:%d:%d) Aborting scb %d\n",
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Aborting scb %d\n",
              p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
       found++;
       aic7xxx_done(p, scb);
     }
   }
-  if (aic7xxx_verbose > 1)
+  if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
   {
-    printk(KERN_WARNING "(scsi%d:-1:-1:-1) %d commands found and queued for "
-	"completion.\n", p->host_no, found);
+    printk(INFO_LEAD "%d commands found and queued for "
+        "completion.\n", p->host_no, -1, -1, -1, found);
   }
   if (complete)
   {
@@ -2221,15 +2485,9 @@
   /*
    * Select the SCB we want to abort and pull the next pointer out of it.
    */
-  curscb = inb(p->base + SCBPTR);
-  outb(scbpos, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-
-  /*
-   * Clear the necessary fields
-   */
-  outb(0, p->base + SCB_CONTROL);
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+  curscb = aic_inb(p, SCBPTR);
+  aic_outb(p, scbpos, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
 
   aic7xxx_add_curscb_to_free_list(p);
 
@@ -2241,24 +2499,21 @@
     /*
      * First in the list
      */
-    outb(next, p->base + WAITING_SCBH);
+    aic_outb(p, next, WAITING_SCBH);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
    * system that the command has been aborted.
    */
-  outb(curscb, p->base + SCBPTR);
-  scb->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-  scb->flags &= ~SCB_ACTIVE;
-
+  aic_outb(p, curscb, SCBPTR);
   return (next);
 }
 
@@ -2271,67 +2526,116 @@
  *   requeue.  Returns the number of matching SCBs.
  *-F*************************************************************************/
 static int
-aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
-    int lun, unsigned char tag, int flags, int requeue, scb_queue_type *queue)
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
+    int lun, unsigned char tag, int flags, int requeue,
+    volatile scb_queue_type *queue)
 {
-  unsigned char saved_queue[AIC7XXX_MAXSCB];
-  int      queued = inb(p->base + QINCNT) & p->qcntmask;
-  int      i;
   int      found;
+  unsigned char qinpos, qintail;
   struct aic7xxx_scb *scbp;
-  scb_queue_type removed_scbs;
 
   found = 0;
-  scbq_init (&removed_scbs);
-  for (i = 0; i < (queued - found); i++)
+  qinpos = aic_inb(p, QINPOS);
+  qintail = p->qinfifonext;
+
+  p->qinfifonext = qinpos;
+
+  while (qinpos != qintail)
   {
-    saved_queue[i] = inb(p->base + QINFIFO);
-    scbp = p->scb_data->scb_array[saved_queue[i]];
-    if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
+    if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
     {
        /*
         * We found an scb that needs to be removed.
         */
-       if (requeue)
+       if (requeue && (queue != NULL))
+       {
+         if (scbp->flags & SCB_WAITINGQ)
+         {
+           scbq_remove(queue, scbp);
+           scbq_remove(&p->waiting_scbs, scbp);
+           scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
+           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+           p->activescbs++;
+         }
+         scbq_insert_tail(queue, scbp);
+         p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+         p->activescbs--;
+         scbp->flags |= SCB_WAITINGQ;
+         if ( !(scbp->tag_action & TAG_ENB) )
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       else if (requeue)
        {
-         scbq_insert_head(&removed_scbs, scbp);
+         p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
        }
        else
        {
+        /*
+         * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
+         * flags we were called with, presumeably so aic7xxx_run_done_queue
+         * can find this scb
+         */
          scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
+         if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+                                       FALSE) == scbp->hscb->tag)
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
        }
-       i--;
        found++;
     }
-  }
-  /* Now put the saved scbs back. */
-  for (queued = 0; queued < i; queued++)
-    outb(saved_queue[queued], p->base + QINFIFO);
-
-  if (requeue)
-  {
-    scbp = removed_scbs.head;
-    while (scbp != NULL)
+    else
     {
-      scbq_remove_head(&removed_scbs);
-      /*
-       * XXX - Shouldn't we be adding this to the free list?
-       */
-      if ( !(scbp->flags & SCB_WAITINGQ) )
-      {    /*  OK...we aren't already on a queue, so put us on there  */
-        p->device_status[TARGET_INDEX(scbp->cmd)].active_cmds--;
-        scbq_insert_head(queue, scbp);
-        scbp->flags |= SCB_WAITINGQ;
-      }
-      scbp = removed_scbs.head;
+      p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
     }
   }
+  /*
+   * Now that we've done the work, clear out any left over commands in the
+   * qinfifo and update the KERNEL_QINPOS down on the card.
+   *
+   *  NOTE: This routine expect the sequencer to already be paused when
+   *        it is run....make sure it's that way!
+   */
+  qinpos = p->qinfifonext;
+  while(qinpos != qintail)
+  {
+    p->qinfifo[qinpos++] = SCB_LIST_NULL;
+  }
+  aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
 
   return (found);
 }
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_scb_on_qoutfifo
+ *
+ * Description:
+ *   Is the scb that was passed to us currently on the qoutfifo?
+ *-F*************************************************************************/
+static int
+aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i=0;
+
+  while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
+  {
+    if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
+      return TRUE;
+    else
+      i++;
+  }
+  return FALSE;
+}
+
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_reset_device
  *
  * Description:
@@ -2346,27 +2650,26 @@
  *   them.
  *-F*************************************************************************/
 static void
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
                      int lun, unsigned char tag)
 {
   struct aic7xxx_scb *scbp;
-  unsigned char active_scb;
+  unsigned char active_scb, tcl;
   int i = 0, j, init_lists = FALSE;
 
   /*
    * Restore this when we're done
    */
-  active_scb = inb(p->base + SCBPTR);
+  active_scb = aic_inb(p, SCBPTR);
 
-  if (aic7xxx_verbose > 2)
-    printk("(scsi%d:%d:%d:%d) Reset device, active_scb %d\n",
-         p->host_no, CHAN_TO_INT(channel), target, lun, active_scb);
+  if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+    printk(INFO_LEAD "Reset device, active_scb %d\n",
+         p->host_no, channel, target, lun, active_scb);
   /*
    * Deal with the busy target and linked next issues.
    */
   {
     int min_target, max_target;
-    unsigned char busy_scbid;
     struct aic7xxx_scb *scbp, *prev_scbp;
 
     /* Make all targets 'relative' to bus A. */
@@ -2374,86 +2677,123 @@
     {
       switch (channel)
       {
-        case 'A':
-  	  min_target = 0;
-  	  max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-  	  break;
-        case 'B':
-  	  min_target = 8;
-  	  max_target = 15;
-  	  break;
+        case 0:
+                 min_target = 0;
+                 max_target = (p->type & AHC_WIDE) ? 15 : 7;
+                 break;
+        case 1:
+                 min_target = 8;
+                 max_target = 15;
+                 break;
         case ALL_CHANNELS:
         default:
-  	  min_target = 0;
-  	  max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-  	  break;
+                 min_target = 0;
+                 max_target = (p->type & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
+                 break;
       }
     }
     else
     { 
-      min_target = target + ((channel == 'B') ? 8 : 0);
+      min_target = target | (channel << 3);
       max_target = min_target;
     }
 
 
     for (i = min_target; i <= max_target; i++)
     {
-      if (aic7xxx_verbose > 2)
-	printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning up status information "
-	  "and delayed_scbs.\n", p->host_no, CHAN_TO_INT(channel), i, lun);
-      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/ TRUE);
-      p->device_status[i].flags &= ~BUS_DEVICE_RESET_PENDING;
-      p->device_status[i].last_reset = jiffies;
-      p->device_status[i].last_queue_full_count = 0;
-      p->device_status[i].last_queue_full = 0;
-      p->device_status[i].temp_queue_depth =
-        p->device_status[i].max_queue_depth;
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Cleaning up status information "
+          "and delayed_scbs.\n", p->host_no, channel, i, lun);
+      if ( !(p->dev_flags[i] & DEVICE_TAGGED_SUCCESS) &&
+            (p->dev_active_cmds[i]) &&
+            (p->tagenable & (0x01 << i)) )
+      {
+        printk(INFO_LEAD "Device appears to be choking on tagged commands.\n",
+          p->host_no, channel, i, lun);
+        printk(INFO_LEAD "Will use untagged I/O instead.\n", p->host_no,
+          channel, i, lun);
+        p->dev_max_queue_depth[i] = 1;
+        p->dev_temp_queue_depth[i] = 1;
+        p->tagenable &= ~(0x01 << i);
+        p->orderedtag &= ~(0x01 << i);
+      }
+      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+      if ( tag == SCB_LIST_NULL )
+      {
+        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+        p->dev_last_reset[i] = jiffies;
+        p->dev_last_queue_full_count[i] = 0;
+        p->dev_last_queue_full[i] = 0;
+        p->dev_temp_queue_depth[i] =
+          p->dev_max_queue_depth[i];
+  /*
+   * In case this isn't a full bus reset, we want to add a 4 second timer in
+   * here so that we can delay all re-sent commands for this device for the
+   * 4 seconds and then have our timer routine pick them back up.
+   */
+        if(p->dev_timer[i].expires)
+        {
+          del_timer(&p->dev_timer[i]);
+        }
+        p->dev_timer[i].expires = jiffies + (4 * HZ);
+        add_timer(&p->dev_timer[i]);
+      }
+      for(j=0; j<MAX_LUNS; j++)
+      {
+        if (channel == 1)
+          tcl = ((i << 4) & 0x70) | (channel << 3) | j;
+        else
+          tcl = (i << 4) | (channel << 3) | j;
+        if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+             (tag == SCB_LIST_NULL) )
+          aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+      }
       j = 0; 
       prev_scbp = NULL; 
-      scbp = p->device_status[i].delayed_scbs.head;
+      scbp = p->delayed_scbs[i].head;
       while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
       {
         prev_scbp = scbp;
         scbp = scbp->q_next;
         if ( prev_scbp == scbp )
         {
-	  if (aic7xxx_verbose)
-	    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Yikes!! scb->q_next == scb "
-	      "in the delayed_scbs queue!\n", p->host_no, CHAN_TO_INT(channel),
-              i, lun);
-	  scbp = NULL;
-	  prev_scbp->q_next = NULL;
-	  p->device_status[i].delayed_scbs.tail = prev_scbp;
-        }
-        if (aic7xxx_match_scb(prev_scbp, target, channel, lun, tag))
-        {
-	  scbq_remove(&p->device_status[i].delayed_scbs, prev_scbp);
-	  if ( prev_scbp->flags & SCB_WAITINGQ )
-	    p->device_status[i].active_cmds++;
-	  prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-	  prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+            printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+              "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
+          scbp = NULL;
+          prev_scbp->q_next = NULL;
+          p->delayed_scbs[i].tail = prev_scbp;
+        }
+        if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+        {
+          scbq_remove(&p->delayed_scbs[i], prev_scbp);
+          if (prev_scbp->flags & SCB_WAITINGQ)
+          {
+            p->dev_active_cmds[i]++;
+            p->activescbs++;
+          }
+          prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
         }
       }
       if ( j > p->scb_data->numscbs )
       {
-        if (aic7xxx_verbose)
-	  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Yikes!! There's a loop in the "
-	    "delayed_scbs queue!\n", p->host_no, CHAN_TO_INT(channel),
-            i, lun);
-        scbq_init(&p->device_status[i].delayed_scbs);
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! There's a loop in the "
+            "delayed_scbs queue!\n", p->host_no, channel, i, lun);
+        scbq_init(&p->delayed_scbs[i]);
       }
-      if ( (p->device_status[i].delayed_scbs.head == NULL) &&
-           (p->device_status[i].timer.expires) )
+      if ( (p->delayed_scbs[i].head == NULL) &&
+           (p->dev_timer[i].expires) )
       {
-        del_timer(&p->device_status[i].timer);
-        p->device_status[i].timer.expires = 0;
+        del_timer(&p->dev_timer[i]);
+        p->dev_timer[i].expires = 0;
       }
     }
   }
 
-  if (aic7xxx_verbose > 2)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning QINFIFO.\n", p->host_no,
-	CHAN_TO_INT(channel), target, lun );
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
   aic7xxx_search_qinfifo(p, target, channel, lun, tag,
       SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
 
@@ -2461,9 +2801,9 @@
  *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
  *  ABORT/RESET commands.
  */
-  if (aic7xxx_verbose > 2)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning waiting_scbs.\n",
-	p->host_no, CHAN_TO_INT(channel), target, lun );
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
+      target, lun );
   {
     struct aic7xxx_scb *scbp, *prev_scbp;
 
@@ -2476,27 +2816,30 @@
       scbp = scbp->q_next;
       if ( prev_scbp == scbp )
       {
-	if (aic7xxx_verbose)
-	  printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!! scb->q_next == scb "
-	    "in the waiting_scbs queue!\n", p->host_no);
-	scbp = NULL;
-	prev_scbp->q_next = NULL;
-	p->waiting_scbs.tail = prev_scbp;
-      }
-      if (aic7xxx_match_scb(prev_scbp, target, channel, lun, tag))
-      {
-	scbq_remove(&p->waiting_scbs, prev_scbp);
-	if ( prev_scbp->flags & SCB_WAITINGQ )
-	  p->device_status[TARGET_INDEX(prev_scbp->cmd)].active_cmds++;
-	prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-	prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+            "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
+        scbp = NULL;
+        prev_scbp->q_next = NULL;
+        p->waiting_scbs.tail = prev_scbp;
+      }
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+      {
+        scbq_remove(&p->waiting_scbs, prev_scbp);
+        if (prev_scbp->flags & SCB_WAITINGQ)
+        {
+          p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
+          p->activescbs++;
+        }
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
     if ( j > p->scb_data->numscbs )
     {
-      if (aic7xxx_verbose)
-	printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!! There's a loop in the "
-	  "waiting_scbs queue!\n", p->host_no);
+      if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+        printk(WARN_LEAD "Yikes!! There's a loop in the "
+          "waiting_scbs queue!\n", p->host_no, channel, target, lun);
       scbq_init(&p->waiting_scbs);
     }
   }
@@ -2505,50 +2848,67 @@
   /*
    * Search waiting for selection list.
    */
-  if (aic7xxx_verbose > 2)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning waiting for selection "
-	"list.\n", p->host_no, CHAN_TO_INT(channel), target, lun);
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting for selection "
+      "list.\n", p->host_no, channel, target, lun);
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
+    next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
     j = 0;
     while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
       if (scb_index >= p->scb_data->numscbs)
       {
-	if (aic7xxx_verbose)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Waiting List inconsistency; "
-		"SCB index=%d, numscbs=%d\n", p->host_no,
-                CHAN_TO_INT(channel), target, lun, scb_index,
-                p->scb_data->numscbs);
-	next = inb(p->base + SCB_NEXT);
-	aic7xxx_add_curscb_to_free_list(p);
+       /*
+        * No aic7xxx_verbose check here.....we want to see this since it
+        * means either the kernel driver or the sequencer screwed things up
+        */
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic_inb(p, SCB_NEXT);
+        aic7xxx_add_curscb_to_free_list(p);
       }
       else
       {
         scbp = p->scb_data->scb_array[scb_index];
-        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
           next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
-	  scbp->flags &= ~SCB_ACTIVE;
-	  scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (scbp->flags & SCB_WAITINGQ)
+          {
+            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+            p->activescbs++;
+          }
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (prev == SCB_LIST_NULL)
+          {
+            /*
+             * This is either the first scb on the waiting list, or we
+             * have already yanked the first and haven't left any behind.
+             * Either way, we need to turn off the selection hardware if
+             * it isn't already off.
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+            aic_outb(p, CLRSELTIMEO, CLRSINT1);
+          }
         }
         else
         {
           prev = next;
-          next = inb(p->base + SCB_NEXT);
+          next = aic_inb(p, SCB_NEXT);
         }
       }
     }
     if ( j > p->scb_data->maxhscbs )
     {
-      if (aic7xxx_verbose)
-	printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
-	  "waiting for selection list!\n", p->host_no);
+      printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
+        "selection list!\n", p->host_no, channel, target, lun);
       init_lists = TRUE;
     }
   }
@@ -2557,46 +2917,52 @@
    * Go through disconnected list and remove any entries we have queued
    * for completion, zeroing their control byte too.
    */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning disconnected scbs "
+      "list.\n", p->host_no, channel, target, lun);
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + DISCONNECTED_SCBH);
+    next = aic_inb(p, DISCONNECTED_SCBH);
     prev = SCB_LIST_NULL;
     j = 0;
     while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
       if (scb_index > p->scb_data->numscbs)
       {
-	if (aic7xxx_verbose)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Waiting List inconsistency; "
-		"SCB index=%d, numscbs=%d\n", p->host_no,
-                CHAN_TO_INT(channel), target, lun, scb_index,
-                p->scb_data->numscbs);
-	next = aic7xxx_rem_scb_from_disc_list(p, next);
+        printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic7xxx_rem_scb_from_disc_list(p, next);
       }
       else
       {
         scbp = p->scb_data->scb_array[scb_index];
-        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
           next = aic7xxx_rem_scb_from_disc_list(p, next);
-	  scbp->flags = SCB_RESET | SCB_QUEUED_FOR_DONE;
-	  scbp->hscb->control = 0;
+          if (scbp->flags & SCB_WAITINGQ)
+          {
+            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+            p->activescbs++;
+          }
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbp->hscb->control = 0;
         }
         else
         {
           prev = next;
-          next = inb(p->base + SCB_NEXT);
+          next = aic_inb(p, SCB_NEXT);
         }
       }
     }
     if ( j > p->scb_data->maxhscbs )
     {
-      if (aic7xxx_verbose)
-	printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
-	  "disconnected list!\n", p->host_no);
+      printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
+        p->host_no, channel, target, lun);
       init_lists = TRUE;
     }
   }
@@ -2609,19 +2975,28 @@
     unsigned char next;
 
     j = 0;
-    next = inb(p->base + FREE_SCBH);
+    next = aic_inb(p, FREE_SCBH);
     while ( (next != SCB_LIST_NULL) && (j++ < p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);
-      outb(0, p->base + SCB_CONTROL);
-      next = inb(p->base + SCB_NEXT);
+      aic_outb(p, next, SCBPTR);
+      if ( aic_inb(p, SCB_TAG) < p->scb_data->numscbs )
+      {
+        printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
+          target, lun);
+        init_lists = TRUE;
+        next = SCB_LIST_NULL;
+      }
+      else
+      {
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        next = aic_inb(p, SCB_NEXT);
+      }
     }
     if ( j > p->scb_data->maxhscbs )
     {
-      if (aic7xxx_verbose)
-	printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
-	  "free list!\n", p->host_no);
+      printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
+        p->host_no, channel, target, lun);
       init_lists = TRUE;
     }
   }
@@ -2632,34 +3007,33 @@
    */
   if (init_lists)
   {
-    outb(SCB_LIST_NULL, p->base + FREE_SCBH);
-    outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
-    outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+    aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
+    aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+    aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
   }
   for (i = p->scb_data->maxhscbs; i >= 0; --i)
   {
     unsigned char scbid;
 
+    aic_outb(p, i, SCBPTR);
     if (init_lists)
     {
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);
-      outb(SCB_LIST_NULL, p->base + SCB_NEXT);
-      outb(SCB_LIST_NULL, p->base + SCB_PREV);
-      outb(SCB_LIST_NULL, p->base + SCB_LINKED_NEXT);
-      outb(0, p->base + SCB_CONTROL);
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+      aic_outb(p, SCB_LIST_NULL, SCB_PREV);
+      aic_outb(p, 0, SCB_CONTROL);
       aic7xxx_add_curscb_to_free_list(p);
     }
     else
     {
-      outb(i, p->base + SCBPTR);
-      scbid = inb(p->base + SCB_TAG);
+      scbid = aic_inb(p, SCB_TAG);
       if (scbid < p->scb_data->numscbs)
       {
         scbp = p->scb_data->scb_array[scbid];
-        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
-	  outb(0, p->base + SCB_CONTROL);
-	  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+          aic_outb(p, 0, SCB_CONTROL);
+          aic_outb(p, SCB_LIST_NULL, SCB_TAG);
           aic7xxx_add_curscb_to_free_list(p);
         }
       }
@@ -2670,28 +3044,32 @@
    * Go through the entire SCB array now and look for commands for
    * for this target that are stillactive.  These are other (most likely
    * tagged) commands that were disconnected when the reset occurred.
+   * Any commands we find here we know this about, it wasn't on any queue,
+   * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
+   * lists, so it really must have been a paged out SCB.  In that case,
+   * we shouldn't need to bother with updating any counters, just mark
+   * the correct flags and go on.
    */
   for (i = 0; i < p->scb_data->numscbs; i++)
   {
     scbp = p->scb_data->scb_array[i];
-    if (((scbp->flags & SCB_ACTIVE) != 0) &&
-        aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    if ((scbp->flags & SCB_ACTIVE) &&
+        aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
+        !aic7xxx_scb_on_qoutfifo(p, scbp))
     {
-      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-      scbp->flags &= ~SCB_ACTIVE;
-
-      if ((scbp->flags & SCB_WAITINGQ) != 0)
+      if (scbp->flags & SCB_WAITINGQ)
       {
         scbq_remove(&p->waiting_scbs, scbp);
-        scbq_remove(&p->device_status[TARGET_INDEX(scbp->cmd)].delayed_scbs,
-	  scbp);
-        scbp->flags &= ~SCB_WAITINGQ;
-	p->device_status[TARGET_INDEX(scbp->cmd)].active_cmds++;
+        scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
+        p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+        p->activescbs++;
       }
+      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
     }
   }
 
-  outb(active_scb, p->base + SCBPTR);
+  aic_outb(p, active_scb, SCBPTR);
 }
 
 
@@ -2706,10 +3084,10 @@
 aic7xxx_clear_intstat(struct aic7xxx_host *p)
 {
   /* Clear any interrupt conditions this may have caused. */
-  outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
-  outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
-       CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
-  outb(CLRSCSIINT, p->base + CLRINT);
+  aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
+  aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, CLRSINT1);
+  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT, CLRINT);
 }
 
 /*+F*************************************************************************
@@ -2725,21 +3103,21 @@
   unsigned char scsiseq;
 
   /* Disable reset interrupts. */
-  outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
 
   /* Turn on the bus reset. */
-  scsiseq = inb(p->base + SCSISEQ);
-  outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+  scsiseq = aic_inb(p, SCSISEQ);
+  aic_outb(p, scsiseq | SCSIRSTO, SCSISEQ);
 
   udelay(1000);
 
   /* Turn off the bus reset. */
-  outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+  aic_outb(p, scsiseq & ~SCSIRSTO, SCSISEQ);
 
   aic7xxx_clear_intstat(p);
 
   /* Re-enable reset interrupts. */
-  outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
 
   udelay(1000);
 }
@@ -2752,19 +3130,18 @@
  *   Reset the channel.
  *-F*************************************************************************/
 static void
-aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
+aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
 {
   unsigned long offset, offset_max;
   unsigned char sblkctl;
-  char cur_channel;
+  int cur_channel;
 
-  if (aic7xxx_verbose > 1)
-    printk(KERN_WARNING "(scsi%d:%d:-1:-1) Reset channel called, %s initiate "
-	"reset.\n", p->host_no, CHAN_TO_INT(channel),
-	(initiate_reset == TRUE) ? "will" : "won't" );
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
+      p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
 
 
-  if (channel == 'B')
+  if (channel == 1)
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
@@ -2773,7 +3150,7 @@
   }
   else
   {
-    if (p->bus_type == AIC_WIDE)
+    if (p->type & AHC_WIDE)
     {
       p->needsdtr = p->needsdtr_copy;
       p->needwdtr = p->needwdtr_copy;
@@ -2799,76 +3176,70 @@
      */
     u_char targ_scratch;
 
-    targ_scratch = inb(p->base + offset);
+    targ_scratch = aic_inb(p, offset);
     targ_scratch &= SXFR;
-    outb(targ_scratch, p->base + offset);
-    offset++;
+    aic_outb(p, targ_scratch, offset++);
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
-  sblkctl = inb(p->base + SBLKCTL);
-  cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
+  sblkctl = aic_inb(p, SBLKCTL);
+  cur_channel = (sblkctl & SELBUSB) >> 3;
   if (cur_channel != channel)
   {
     /*
      * Case 1: Command for another bus is active
      */
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:-1:-1) Stealthily resetting idle "
-           "channel.\n", p->host_no, CHAN_TO_INT(channel));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
+        channel, -1, -1);
     /*
      * Stealthily reset the other bus without upsetting the current bus.
      */
-    outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
     }
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
-    outb(sblkctl, p->base + SBLKCTL);
+    aic_outb(p, sblkctl, SBLKCTL);
   }
   else
   {
     /*
      * Case 2: A command from this bus is active or we're idle.
      */
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:-1:-1) Resetting currently active "
-	"channel.\n", p->host_no, CHAN_TO_INT(channel));
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
+        channel, -1, -1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    p->msg_type = MSG_TYPE_NONE;
+    p->msg_len = 0;
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
     }
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
   }
-  if (aic7xxx_verbose)
-    printk(KERN_WARNING "(scsi%d:%d:-1:-1) Channel reset\n",
-	p->host_no, CHAN_TO_INT(channel));
+  if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+    printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
   /*
    * Clean up all the state information for the pending transactions
    * on this bus.
    */
   aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
-  if ( p->bus_type != AIC_TWIN )
+  if ( !(p->type & AHC_TWIN) )
   {
     restart_sequencer(p);
-    pause_sequencer(p);
   }
 
-  p->host->last_reset = jiffies + (HZ * AIC7XXX_RESET_DELAY);
-
-  /*
-   * Now loop through all the SCBs that have been marked for abortion,
-   * and call the scsi_done routines.
-   */
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
   return;
 }
 
@@ -2885,47 +3256,63 @@
 {
   struct aic7xxx_scb *scb;
   int tindex;
+  int sent;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
 
 
   if (p->waiting_scbs.head == NULL)
     return;
 
+  sent = 0;
+
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  pause_sequencer(p);
-  scb = p->waiting_scbs.head;
-  while (scb != NULL)
+  DRIVER_LOCK
+  while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
   {
-    if (p->curqincnt >= p->qfullcount)
-    {
-      p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
-      if (p->curqincnt >= p->qfullcount)
-      {
-        break;
-      }
-    }
-
-    /*
-     * We have some space.
-     */
-    scbq_remove_head(&p->waiting_scbs);
     tindex = TARGET_INDEX(scb->cmd);
-    if ( p->device_status[tindex].active_cmds >=
-         p->device_status[tindex].temp_queue_depth )
-    {
-        scbq_insert_tail(&p->device_status[tindex].delayed_scbs, scb);
+    if ( (p->dev_active_cmds[tindex] >=
+          p->dev_temp_queue_depth[tindex]) ||
+         (p->dev_last_reset[tindex] >= (jiffies - (4 * HZ))) )
+    {
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+        if ( !(p->dev_timer[tindex].expires) &&
+             !(p->dev_active_cmds[tindex]) )
+        {
+          p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ);
+          add_timer(&p->dev_timer[tindex]);
+        }
     }
     else
     {
         scb->flags &= ~SCB_WAITINGQ;
-        p->device_status[tindex].active_cmds++;
-        outb(scb->hscb->tag, p->base + QINFIFO);
-        p->curqincnt++;
+        p->dev_active_cmds[tindex]++;
+        p->activescbs++;
+        if ( !(scb->tag_action) )
+        {
+          aic7xxx_busy_target(p, scb);
+        }
+        p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+        sent++;
     }
-    scb = p->waiting_scbs.head;
   }
-  unpause_sequencer(p, FALSE);
+  if (sent)
+  {
+    if(p->type & AHC_AIC78x0)
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    else
+    {
+      pause_sequencer(p);
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      unpause_sequencer(p, FALSE);
+    }
+    if (p->activescbs > p->max_activescbs)
+      p->max_activescbs = p->activescbs;
+  }
+  DRIVER_UNLOCK
 }
 
 
@@ -2940,41 +3327,53 @@
 static void
 aic7xxx_timer(struct aic7xxx_host *p)
 {
-   int i;
-   unsigned long processor_flags;
-   struct aic7xxx_scb *scb;
-   
-   save_flags(processor_flags);
-   cli();
-   if (aic7xxx_verbose > 3)
-     printk(KERN_WARNING "(scsi%d:-1:-1:-1) Timer running.\n", p->host_no);
-   for(i=0; i<MAX_TARGETS; i++)
-   {
-     if ( (p->device_status[i].timer.expires) && 
-          (p->device_status[i].timer.expires <= jiffies) )
-     {
-       p->device_status[i].timer.expires = 0;
-       if ( (p->device_status[i].timer.prev != NULL) ||
-            (p->device_status[i].timer.next != NULL) )
-       {
-         del_timer(&p->device_status[i].timer);
-       }
-       p->device_status[i].temp_queue_depth = 
-	 p->device_status[i].max_queue_depth;
-       scb = p->device_status[i].delayed_scbs.head;
-       while ( scb != NULL )
-       {
-         scbq_remove_head(&p->device_status[i].delayed_scbs);
-         scbq_insert_tail(&p->waiting_scbs, scb);
-         scb = p->device_status[i].delayed_scbs.head;
-       }
-     }
-   }
-   aic7xxx_run_waiting_queues(p);
-   unpause_sequencer(p, FALSE);
-   restore_flags(processor_flags);
+  int i, j;
+  unsigned long cpu_flags = 0;
+  struct aic7xxx_scb *scb;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
+  DRIVER_LOCK
+#else
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+#endif
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if ( (p->dev_timer[i].expires) && 
+          (p->dev_timer[i].expires <= jiffies) )
+    {
+      p->dev_timer[i].expires = 0;
+      if ( (p->dev_timer[i].prev != NULL) ||
+           (p->dev_timer[i].next != NULL) )
+      {
+        del_timer(&p->dev_timer[i]);
+      }
+      p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
+      j = 0;
+      while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
+              (j++ < p->scb_data->numscbs) )
+      {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+      }
+      if (j == p->scb_data->numscbs)
+      {
+        printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n",
+          p->host_no, 0, i, -1);
+        scbq_init(&p->delayed_scbs[i]);
+        scbq_init(&p->waiting_scbs);
+        /*
+         * Well, things are screwed now, wait for a reset to clean the junk
+         * out.
+         */
+      }
+    }
+  }
+  aic7xxx_run_waiting_queues(p);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
+  DRIVER_UNLOCK
+#else
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#endif
 }
- 
 
 /*+F*************************************************************************
  * Function:
@@ -2985,15 +3384,15 @@
  *   buffer on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char period, unsigned char offset)
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period,
+        unsigned char offset)
 {
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_SDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(period,           p->base + MSG_OUT + 3 + start_byte);
-  outb(offset,           p->base + MSG_OUT + 4 + start_byte);
-  outb(start_byte + 5,   p->base + MSG_LEN);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
+  p->msg_buf[p->msg_index++] = period;
+  p->msg_buf[p->msg_index++] = offset;
+  p->msg_len += 5;
 }
 
 /*+F*************************************************************************
@@ -3005,14 +3404,13 @@
  *   on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char bus_width)
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
 {
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_WDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(bus_width,        p->base + MSG_OUT + 3 + start_byte);
-  outb(start_byte + 4,   p->base + MSG_LEN);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
+  p->msg_buf[p->msg_index++] = bus_width;
+  p->msg_len += 4;
 }
 
 /*+F*************************************************************************
@@ -3027,7 +3425,7 @@
 {
   struct aic7xxx_hwscb *hscb;
   Scsi_Cmnd *cmd;
-  int actual;
+  int actual, i;
 
   cmd = scb->cmd;
   hscb = scb->hscb;
@@ -3045,18 +3443,22 @@
      *  and cmd->underflow seems to be set rather half-
      *  heartedly in the higher-level SCSI code.
      */
-    actual = aic7xxx_length(cmd, hscb->residual_SG_segment_count);
-
+    actual = scb->sg_length;
+    for (i=1; i < hscb->residual_SG_segment_count; i++)
+    {
+      actual -= scb->sg_list[scb->sg_count - i].length;
+    }
     actual -= (hscb->residual_data_count[2] << 16) |
               (hscb->residual_data_count[1] <<  8) |
               hscb->residual_data_count[0];
 
-    if ( (actual < cmd->underflow) && (aic7xxx_verbose) )
+    if (actual < cmd->underflow)
     {
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Underflow - "
-             "Wanted at least %u, got %u, residual SG count %d.\n",
-             p->host_no, CTL_OF_SCB(scb), cmd->underflow, actual,
-             hscb->residual_SG_segment_count);
+      if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+          "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+          (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
+          hscb->residual_SG_segment_count);
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
       aic7xxx_status(cmd) = hscb->target_status;
     }
@@ -3080,32 +3482,30 @@
  *   Interrupt handler for sequencer interrupts (SEQINT).
  *-F*************************************************************************/
 static void
-aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
 {
   unsigned short targ_mask;
   unsigned char  targ_scratch;
   int scratch_offset = target;
 
-  if (channel == 'B')
-  {
-    scratch_offset += 8;
-  }
+  scratch_offset += channel << 3;
+
   targ_mask = (0x01 << scratch_offset);
   /*
    * Go back to async/narrow transfers and renegotiate.
    */
-  p->needsdtr |= p->needsdtr_copy & targ_mask;
-  p->needwdtr |= p->needwdtr_copy & targ_mask;
+  p->needsdtr |= (p->needsdtr_copy & targ_mask);
+  p->needwdtr |= (p->needwdtr_copy & targ_mask);
   p->sdtr_pending &= ~targ_mask;
   p->wdtr_pending &= ~targ_mask;
-  targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+  targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
   targ_scratch &= SXFR;
-  outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+  aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
   aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-  if (aic7xxx_verbose)
-    printk(KERN_WARNING "(scsi%d:%d:%d:-1) Bus Device Reset delivered.\n",
-         p->host_no, CHAN_TO_INT(channel), target);
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
+      target, -1);
+  aic7xxx_run_done_queue(p, /*complete*/ FALSE);
 }
 
 /*+F*************************************************************************
@@ -3124,107 +3524,31 @@
   unsigned char queue_flag = FALSE;
   char channel;
 
-  if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
-  {
-    target = (inb(p->base + SELID) >> 4) & 0x0F;
-  }
-  else
-  {
-    target = (inb(p->base + SCSIID) >> 4) & 0x0F;
-  }
-  scratch_offset = target;
-  channel = 'A';
-  lun = inb(p->base + SAVED_TCL) & 0x07;
-  if (inb(p->base + SBLKCTL) & SELBUSB)
-  {
-    channel = 'B';
-    scratch_offset += 8;
-  }
-  target_mask = (0x01 << scratch_offset);
-
-  switch (intstat & SEQINT_MASK)
+  target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
+  channel = (aic_inb(p, SBLKCTL) >> 3) & 0x01;
+  scratch_offset = target + (channel << 3);
+  lun = aic_inb(p, SAVED_TCL) & 0x07;
+  target_mask = (0x01 << scratch_offset);
+
+  switch (intstat & SEQINT_MASK)
   {
     case NO_MATCH:
       {
-        /*
-         * This could be for a normal abort request.  Figure out
-         * which SCB we were trying to find and only give an error
-         * if we didn't ask for this to happen.
-         */
-        unsigned char scb_index;
-        unsigned char busy_scbid;
-        unsigned char arg1;
-
-        busy_scbid = aic7xxx_index_busy_target(p, target, channel,
-            /*unbusy*/ FALSE);
-        arg1 = inb(p->base + ARG_1);
-
-        if (arg1 == SCB_LIST_NULL)
-        {
-          /* untagged request */
-          scb_index = busy_scbid;
-        }
-        else
-        {
-          scb_index = arg1;
-        }
-
-        if (scb_index < p->scb_data->numscbs)
-        {
-          scb = p->scb_data->scb_array[scb_index];
-          if (scb->hscb->control & ABORT_SCB)
-          {
-            /*
-             * We expected this.  Let the busfree handler take care
-             * of this when we the abort is finally sent.  Set
-             * IDENTIFY_SEEN so that the busfree handler knows that
-             * there is an SCB to cleanup.
-             */
-            outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
-	    if (aic7xxx_verbose > 1)
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reconnect SCB abort "
-		"successful\n", p->host_no, CTL_OF_SCB(scb));
-            break;
-          }
-        }
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) No active SCB for reconnecting "
-               "target - Issuing BUS DEVICE RESET.\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun);
-
-        printk(KERN_WARNING "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
-               inb(p->base + SAVED_TCL), arg1,
-               (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-        aic7xxx_handle_device_reset(p, target, channel);
-      }
-      break;
-
-    case NO_MATCH_BUSY:
-      {
-        /*
-         * XXX - Leave this as a panic for the time being since it
-         * indicates a bug in the timeout code for this to happen.
-         */
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + CUR_SCBID);
-        scb = p->scb_data->scb_array[scb_index];
-
-        panic("(scsi%d:%d:%d:%d) Target busy link failure, "
-              "but busy SCB exists!\n",
-              p->host_no, CHAN_TO_INT(channel), target, lun );
+        printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
+               "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
+        printk(WARN_LEAD "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+               p->host_no, channel, target, lun,
+               aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
+               (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       }
       break;
 
     case SEND_REJECT:
       {
-        unsigned char rej_byte;
-
-        rej_byte = inb(p->base + REJBYTE);
-	if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Rejecting unknown message "
-               "(0x%x) received from target, SEQ_FLAGS=0x%x\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun,
-               rej_byte, inb(p->base + SEQ_FLAGS));
+        if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
+            "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
+            aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
       }
       break;
 
@@ -3232,269 +3556,170 @@
       {
         /*
          * The reconnecting target either did not send an identify
-         * message, or did, but we didn't find and SCB to match and
+         * message, or did, but we didn't find an SCB to match and
          * before it could respond to our ATN/abort, it hit a dataphase.
          * The only safe thing to do is to blow it away with a bus
          * reset.
          */
-        if (aic7xxx_verbose)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target did not send an "
-               "IDENTIFY message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun,
-               inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+        if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
+          printk(INFO_LEAD "Target did not send an IDENTIFY message; "
+            "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
+            lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
 
         aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+        aic7xxx_run_done_queue(p, FALSE);
 
       }
       break;
 
     case BAD_PHASE:
-      if (inb(p->base + LASTPHASE) == P_BUSFREE)
+      if (aic_inb(p, LASTPHASE) == P_BUSFREE)
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Missed busfree.\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
+            target, lun);
         restart_sequencer(p);
       }
       else
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Unknown scsi bus phase, "
-               "continuing\n", p->host_no, CHAN_TO_INT(channel), target, lun);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
+            channel, target, lun);
       }
       break;
 
     case EXTENDED_MSG:
       {
-	unsigned char message_length;
-	unsigned char message_code;
-        unsigned char scb_index;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+        p->msg_len = 0;
+        p->msg_index = 0;
 
-	message_length = inb(p->base + MSGIN_EXT_LEN);
-	message_code = inb(p->base + MSGIN_EXT_OPCODE);
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
-
-	switch (message_code)
-	{
-          case MSG_EXT_SDTR:
-          {
-            unsigned char period;
-            unsigned char offset;
-            unsigned char saved_offset;
-            unsigned char targ_scratch;
-            unsigned char max_offset;
-            unsigned char rate;
+       /*
+        * We have to clear the SEQINT *BEFORE* we set the REQINIT handler
+        * active or else VLB and edge triggered EISA cards could loose the
+        * first REQINIT and cause a bus hang/reset cycle.
+        */
+        aic_outb(p, CLRSEQINT, CLRINT);
 
-            if (message_length != MSG_EXT_SDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
+       /*      
+        * To actually receive the message, simply turn on
+        * REQINIT interrupts and let our interrupt handler
+        * do the rest (REQINIT should already be true).
+        */
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
 
-            period = inb(p->base + MSGIN_EXT_BYTES);
-            saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
-            targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+       /*
+        * We don't want the sequencer unpaused yet so we return early
+        */
+        return;
+      }
 
-            if (targ_scratch & WIDEXFER)
-              max_offset = MAX_OFFSET_16BIT;
-            else
-              max_offset = MAX_OFFSET_8BIT;
-            offset = MIN(saved_offset, max_offset);
+    case REJECT_MSG:
+      {
+        /*
+         * What we care about here is if we had an outstanding SDTR
+         * or WDTR message for this target. If we did, this is a
+         * signal that the target is refusing negotiation.
+         */
+        unsigned char targ_scratch;
+        unsigned char scb_index;
+        unsigned char last_msg;
 
-            aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+        last_msg = aic_inb(p, LAST_MSG);
 
+        if ( (last_msg == MSG_IDENTIFYFLAG) &&
+             (scb->tag_action != 0 ) &&
+             !(scb->flags & SCB_MSGOUT_BITS) )
+        {
+          if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
+              (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS))
+          {
             /*
-             * Preserve the WideXfer flag.
+             * OK...the device seems able to accept tagged commands, but
+             * not ordered tag commands, only simple tag commands.  So, we
+             * disable ordered tag commands and go on with life just like
+             * normal.
              */
-            targ_scratch = rate | (targ_scratch & WIDEXFER);
-
+            p->orderedtag &= ~target_mask;
+            scb->tag_action = MSG_SIMPLE_Q_TAG;
+            scb->hscb->control &= ~SCB_TAG_TYPE;
+            scb->hscb->control |= MSG_SIMPLE_Q_TAG;
+            aic_outb(p, scb->hscb->control, SCB_CONTROL);
             /*
-             * Update both the target scratch area and current SCSIRATE.
+             * OK..we set the tag type to simple tag command, now we re-assert
+             * ATNO and hope this will take us into the identify phase again
+             * so we can resend the tag type and info to the device.
              */
-            outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(targ_scratch, p->base + SCSIRATE);
-
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+          else if ( (scb->tag_action == MSG_SIMPLE_Q_TAG) &&
+                   !(p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS) )
+          {
+            unsigned char i, reset = 0;
+            struct aic7xxx_scb *scbp;
+            int old_verbose;
             /*
-             * See if we initiated Sync Negotiation and didn't have
-             * have to fall down to async transfers.
+             * Hmmmm....the device is flaking out on tagged commands.  The
+             * bad thing is that we already have tagged commands enabled in
+             * the device struct in the mid level code.  We also have a queue
+             * set according to the tagged queue depth.  Gonna have to live
+             * with it by controlling our queue depth internally and making
+             * sure we don't set the tagged command flag any more.
              */
-            if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
-            {
-              /* We started it. */
-              if (saved_offset == offset)
-              {
-        	/*
-        	 * Don't send an SDTR back to the target.
-        	 */
-        	outb(0, p->base + RETURN_1);
-              }
-              else
-              {
-        	/*
-                 * We went too low - force async and disable future
-                 * sync negotiation
-                 */
-                p->needsdtr_copy &= ~target_mask;
-        	outb(SEND_REJ, p->base + RETURN_1);
-              }
-            }
-            else if ( offset != 0 )
-            {
-              /*
-               * Send our own SDTR in reply.
-               *
-               * We want to see this message as we don't expect a target
-               * to send us a SDTR request first.
-               */
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Sending reply SDTR.\n",
-                p->host_no, CTL_OF_SCB(scb));
-              aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
-              outb(SEND_MSG, p->base + RETURN_1);
-            }
-            else
-            {
-              /*
-               * The incoming SDTR was too low, reject it.
-               */
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Rejecting SDTR request.\n",
-                p->host_no, CTL_OF_SCB(scb));
-              outb(SEND_REJ, p->base + RETURN_1);
-              p->needsdtr_copy &= ~target_mask;
-            }
+            p->tagenable &= ~target_mask;
+            p->orderedtag &= ~target_mask;
+            p->dev_max_queue_depth[scratch_offset] =
+               p->dev_temp_queue_depth[scratch_offset] = 1;
             /*
-             * Clear the flags.
+             * We set this command up as a bus device reset.  However, we have
+             * to clear the tag type as it's causing us problems.  We shouldnt
+             * have to worry about any other commands being active, since if
+             * the device is refusing tagged commands, this should be the
+             * first tagged command sent to the device, however, we do have
+             * to worry about any other tagged commands that may already be
+             * in the qinfifo.  The easiest way to do this, is to issue a BDR,
+             * send all the commands back to the mid level code, then let them
+             * come back and get rebuilt as untagged commands.
              */
-            p->needsdtr &= ~target_mask;
-            p->sdtr_pending &= ~target_mask;
-            break;
-          }
-
-          case MSG_EXT_WDTR:
-          {
-            unsigned char scratch, bus_width;
-
-            if (message_length != MSG_EXT_WDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
-
-            bus_width = inb(p->base + MSGIN_EXT_BYTES);
-            scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-            if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-            {
-              /*
-               * Don't send an WDTR back to the target, since we asked first.
-               */
-              outb(0, p->base + RETURN_1);
-              switch (bus_width)
-              {
-        	case BUS_8_BIT:
-                  p->needwdtr_copy &= ~target_mask;
-        	  scratch &= 0x7F;
-        	  break;
-
-        	case BUS_16_BIT:
-                  if (aic7xxx_verbose)
-                  {
-        	    printk(KERN_INFO "(scsi%d:%d:%d:%d) Using 16 bit (Wide)"
-  	  	         "transfers.\n", p->host_no, CTL_OF_SCB(scb));
-                  }
-        	  scratch |= WIDEXFER;
-        	  break;
-
-        	case BUS_32_BIT:
-        	  outb(SEND_REJ, p->base + RETURN_1);
-                  /* No verbose here!  We want to see this condition. */
-        	  printk(KERN_WARNING "(scsi%d:%d:%d:%d) "
-  			"requesting 32 bit transfers, rejecting...\n",
-                	 p->host_no, CTL_OF_SCB(scb));
-        	  break;
-
-        	default:
-        	  break;
-              }
-            }
-            else
+            scb->tag_action = 0;
+            scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
+            aic_outb(p,  scb->hscb->control, SCB_CONTROL);
+
+            old_verbose = aic7xxx_verbose;
+            aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
+            for (i=0; i!=p->scb_data->numscbs; i++)
             {
-              int send_reject = FALSE;
-
-              /*
-               * Send our own WDTR in reply.
-               */
-              switch (bus_width)
-              {
-        	case BUS_8_BIT:
-                  p->needwdtr_copy &= ~target_mask;
-        	  scratch &= 0x7F;
-        	  break;
-
-        	case BUS_32_BIT:
-        	case BUS_16_BIT:
-        	  if (p->bus_type == AIC_WIDE)
-        	  {
-                    printk(KERN_INFO "(scsi%d:%d:%d:%d) Using 16 bit (Wide)"
-  			   "transfers.\n", p->host_no, CTL_OF_SCB(scb));
-                    bus_width = BUS_16_BIT;
-                    scratch |= WIDEXFER;
-        	  }
-        	  else
-        	  {
-                    bus_width = BUS_8_BIT;
-                    scratch &= 0x7F;  /* XXX - FreeBSD doesn't do this. */
-                    send_reject = TRUE;
-        	  }
-        	  break;
-
-        	default:
-        	  break;
-              }
-              if (send_reject)
+              scbp = p->scb_data->scb_array[i];
+              if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
               {
-                outb(SEND_REJ, p->base + RETURN_1);
-                printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target initiated "
-                       "wide negotiation on a narrow bus - rejecting!",
-                       p->host_no, CTL_OF_SCB(scb));
-              }
-              else
-              {
-                aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
-                outb(SEND_MSG, p->base + RETURN_1);
+                if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
+                {
+                  aic7xxx_reset_device(p, target, channel, lun, i);
+                  reset++;
+                }
+                aic7xxx_run_done_queue(p, FALSE);
               }
             }
-            p->needwdtr &= ~target_mask;
-            p->wdtr_pending &= ~target_mask;
-            outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(scratch, p->base + SCSIRATE);
-            break;
-	  }  /* case MSG_EXT_WDTR */
-
-          default:
+            aic7xxx_verbose = old_verbose;
             /*
-             * Unknown extended message - reject it.
+             * Wait until after the for loop to set the busy index since
+             * aic7xxx_reset_device will clear the busy index during its
+             * operation.
              */
-            outb(SEND_REJ, p->base + RETURN_1);
-            break;
-	}  /* switch (message_code) */
-      }  /* case EXTENDED_MSG */
-      break;
-
-    case REJECT_MSG:
-      {
-	/*
-	 * What we care about here is if we had an outstanding SDTR
-	 * or WDTR message for this target. If we did, this is a
-	 * signal that the target is refusing negotiation.
-	 */
-	unsigned char targ_scratch;
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
-	targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-	if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-	{
+            aic7xxx_busy_target(p, scb);
+            printk(INFO_LEAD "Device is refusing tagged commands, using "
+              "untagged I/O.\n", p->host_no, channel, target, lun);
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
           /*
            * note 8bit xfers and clear flag
            */
@@ -3502,143 +3727,202 @@
           p->needwdtr &= ~target_mask;
           p->needwdtr_copy &= ~target_mask;
           p->wdtr_pending &= ~target_mask;
-          if (aic7xxx_verbose)
-            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Refusing WIDE "
-  		 "negotiation; using 8 bit transfers.\n",
-  		 p->host_no, CTL_OF_SCB(scb));
-	}
-	else
-	{
-          if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
           {
-            /*
-             * note asynch xfers and clear flag
-             */
-            targ_scratch &= 0xF0;
-            p->needsdtr &= ~target_mask;
-            p->needsdtr_copy &= ~target_mask;
-            p->sdtr_pending &= ~target_mask;
- 	    if (aic7xxx_verbose)
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Refusing "
-  		   "synchronous negotiation; using asynchronous transfers.\n",
-  		   p->host_no, CTL_OF_SCB(scb));
+            printk(INFO_LEAD "Refusing WIDE negotiation; using 8 bit "
+              "transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+          }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT;
+          /*
+           * The sequencer should have already cleared the MK_MESSAGE bit in
+           * the SCB, so we simply restart the message out phase and resend
+           * the IDENTIFY and TAG values so that there is no confusion over
+           * what has been rejected.
+           */
+          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+         /*
+          * note asynch xfers and clear flag
+          */
+          targ_scratch &= 0xF0;
+          p->needsdtr &= ~target_mask;
+          p->needsdtr_copy &= ~target_mask;
+          p->sdtr_pending &= ~target_mask;
+          p->syncinfo[scratch_offset].period = 0;
+          p->syncinfo[scratch_offset].offset = 0;
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_SDTR) )
+          {
+            printk(INFO_LEAD "Refusing synchronous negotiation; using "
+              "asynchronous transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_SDTR;
           }
           /*
+           * The sequencer should have already cleared the MK_MESSAGE bit in
+           * the SCB, so we simply restart the message out phase and resend
+           * the IDENTIFY and TAG values so that there is no confusion over
+           * what has been rejected.
+           */
+          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+        }
+        else if (aic7xxx_verbose & VERBOSE_SEQINT)
+        {
+          /*
            * Otherwise, we ignore it.
            */
-	}
-        outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-        outb(targ_scratch, p->base + SCSIRATE);
+          printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause.  "
+            "Ignoring.\n", p->host_no, channel, target, lun);
+        }
+        aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, targ_scratch, SCSIRATE);
       }
       break;
 
     case BAD_STATUS:
       {
-	unsigned char scb_index;
-	struct aic7xxx_hwscb *hscb;
-	Scsi_Cmnd *cmd;
-
-	/* The sequencer will notify us when a command has an error that
-	 * would be of interest to the kernel.  This allows us to leave
-	 * the sequencer running in the common case of command completes
-	 * without error.  The sequencer will have DMA'd the SCB back
-	 * up to us, so we can reference the drivers SCB array.
-	 */
-	scb_index = inb(p->base + SCB_TAG);
-	scb = p->scb_data->scb_array[scb_index];
-	hscb = scb->hscb;
-
-	/*
-	 * Set the default return value to 0 indicating not to send
-	 * sense.  The sense code will change this if needed and this
-	 * reduces code duplication.
-	 */
-	outb(0, p->base + RETURN_1);
-	if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-	{
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Invalid SCB during "
-        	 "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
-        	 CHAN_TO_INT(channel), target, lun, intstat, scb_index,
-                 scb->flags, (unsigned int) scb->cmd);
-	}
-	else
-	{
+        unsigned char scb_index;
+        struct aic7xxx_hwscb *hscb;
+        Scsi_Cmnd *cmd;
+
+        /* The sequencer will notify us when a command has an error that
+         * would be of interest to the kernel.  This allows us to leave
+         * the sequencer running in the common case of command completes
+         * without error.  The sequencer will have DMA'd the SCB back
+         * up to us, so we can reference the drivers SCB array.
+         */
+        scb_index = aic_inb(p, SCB_TAG);
+        if (scb_index > p->scb_data->numscbs)
+        {
+          aic_outb(p, 0, RETURN_1);
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
+            p->host_no, channel, target, lun, intstat, scb_index);
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        hscb = scb->hscb;
+
+        /*
+         * Set the default return value to 0 indicating not to send
+         * sense.  The sense code will change this if needed and this
+         * reduces code duplication.
+         */
+        aic_outb(p, 0, RETURN_1);
+        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
+            " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
+            scb_index, scb->flags, (unsigned long) scb->cmd);
+        }
+        else
+        {
           cmd = scb->cmd;
-  	  hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+          hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
           aic7xxx_status(cmd) = hscb->target_status;
 
-          cmd->result |= hscb->target_status;
+          cmd->result = hscb->target_status;
 
           switch (status_byte(hscb->target_status))
           {
             case GOOD:
-  	      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Interrupted for status of "
-                     "GOOD???\n", p->host_no, CTL_OF_SCB(scb));
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Interrupted for status of GOOD???\n",
+                  p->host_no, CTL_OF_SCB(scb));
               break;
 
+            case COMMAND_TERMINATED:
             case CHECK_CONDITION:
-              if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+              if ( !(scb->flags & SCB_SENSE) )
               {
-        	unsigned int addr;    /* must be 32 bits */
-        	/*
-        	 * XXX - How do we save the residual (if there is one).
-        	 */
-                aic7xxx_calculate_residual(p, scb);
-
-        	/*
-  		 * Send a sense command to the requesting target.
-        	 * XXX - revisit this and get rid of the memcopys.
-  		 */
-        	memcpy((void *) scb->sense_cmd, (void *) generic_sense,
-        	       sizeof(generic_sense));
-
-        	scb->sense_cmd[1] = (cmd->lun << 5);
-        	scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
-        	scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
-        	scb->sg_list[0].length = sizeof(cmd->sense_buffer);
-        	cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+                /*
+                 * XXX - How do we save the residual (if there is one).
+                 */
+                if ( hscb->residual_SG_segment_count != 0 )
+                  aic7xxx_calculate_residual(p, scb);
+
+                /*
+                   * Send a sense command to the requesting target.
+                 * XXX - revisit this and get rid of the memcopys.
+                   */
+                memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+                       sizeof(generic_sense));
+
+                scb->sense_cmd[1] = (cmd->lun << 5);
+                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+                scb->sg_list[0].address = 
+                  cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+                scb->sg_list[0].length = 
+                  cpu_to_le32(sizeof(cmd->sense_buffer));
 
                 /*
                  * XXX - We should allow disconnection, but can't as it
                  * might allow overlapped tagged commands.
                  */
-  		/* hscb->control &= DISCENB; */
+                  /* hscb->control &= DISCENB; */
                 hscb->control = 0;
-        	hscb->target_status = 0;
-        	hscb->SG_segment_count = 1;
-
-        	addr = VIRT_TO_BUS(&scb->sg_list[0]);
-        	memcpy(&hscb->SG_list_pointer, &addr,
-        	       sizeof(hscb->SG_list_pointer));
-
-        	memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
-        	       sizeof(hscb->data_pointer));
-        	/* Maintain SCB_LINKED_NEXT */
-        	hscb->data_count &= 0xFF000000;
-  		hscb->data_count |= scb->sg_list[0].length;
-
-        	addr = VIRT_TO_BUS(scb->sense_cmd);
-        	memcpy(&hscb->SCSI_cmd_pointer, &addr,
-        	       sizeof(hscb->SCSI_cmd_pointer));
-        	hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+                hscb->target_status = 0;
+                hscb->SG_list_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+                hscb->data_pointer = scb->sg_list[0].address;
+                hscb->data_count = scb->sg_list[0].length;
+                hscb->SCSI_cmd_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+                hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+                hscb->residual_SG_segment_count = 0;
+                hscb->residual_data_count[0] = 0;
+                hscb->residual_data_count[1] = 0;
+                hscb->residual_data_count[2] = 0;
+
+                scb->sg_count = hscb->SG_segment_count = 1;
+                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->flags &= ~SCB_MSGOUT_BITS;
+                scb->tag_action = 0;
+                /*
+                 * This problem could be caused if the target has lost power
+                 * or found some other way to loose the negotiation settings,
+                 * so if needed, we'll re-negotiate while doing the sense cmd.
+                 * However, if this SCB already was attempting to negotiate,
+                 * then we assume this isn't the problem and skip this part.
+                 *
+                 * 1998/04/23 - We also don't want to set the flag if the
+                 *   original command was a TEST_UNIT_READY since that
+                 *   implies a SEND_SENSE anyway.  Plus, we don't actually
+                 *   start the negotiation here, we just flag it because
+                 *   some devices appear to choke up their message buffer
+                 *   when we mix things together like this.
+                 */
+                if ( !(scb->flags & SCB_MSGOUT_BITS) &&
+                      (scb->cmd->cmnd[0] != TEST_UNIT_READY) )
+                {
+                  if ( p->needwdtr_copy & target_mask )
+                  {
+                    p->needwdtr |= target_mask;
+                  }
+                  if ( p->needsdtr_copy & target_mask )
+                  {
+                    p->needsdtr |= target_mask;
+                  }
+                }
 
-                scb->sg_count = hscb->SG_segment_count;
-        	scb->flags |= SCB_SENSE;
+                scb->flags |= SCB_SENSE;
                 /*
                  * Ensure the target is busy since this will be an
                  * an untagged request.
                  */
-                aic7xxx_busy_target(p, target, channel, hscb->tag);
-        	outb(SEND_SENSE, p->base + RETURN_1);
+                aic7xxx_busy_target(p, scb);
+                aic_outb(p, SEND_SENSE, RETURN_1);
+                aic7xxx_error(cmd) = DID_OK;
+                break;
               }  /* first time sense, no errors */
-              else
-  	      {
-        	if (aic7xxx_error(cmd) == 0)
-  		{
-        	  aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-  		}
-  	      }
+              aic7xxx_error(cmd) = DID_OK;
+              scb->flags &= ~SCB_SENSE;
               break;
 
             case QUEUE_FULL:
@@ -3646,242 +3930,682 @@
             case BUSY:              /* drop through to here */
             {
               struct aic7xxx_scb *next_scbp, *prev_scbp;
-              int ti = TARGET_INDEX(scb->cmd);
-              
+              unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
+              /*
+               * We have to look three places for queued commands:
+               *  1: QINFIFO
+               *  2: p->waiting_scbs queue
+               *  3: WAITING_SCBS list on card (for commands that are started
+               *     but haven't yet made it to the device)
+               */
               aic7xxx_search_qinfifo(p, target, channel, lun,
                 SCB_LIST_NULL, 0, TRUE,
-                &p->device_status[ti].delayed_scbs);
+                &p->delayed_scbs[scratch_offset]);
               next_scbp = p->waiting_scbs.head;
               while ( next_scbp != NULL )
               {
                 prev_scbp = next_scbp;
                 next_scbp = next_scbp->q_next;
-                if ( aic7xxx_match_scb(prev_scbp, target, channel, lun,
+                if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
                      SCB_LIST_NULL) )
                 {
                   scbq_remove(&p->waiting_scbs, prev_scbp);
-                  scbq_insert_tail(&p->device_status[ti].delayed_scbs,
+                  scbq_insert_tail(&p->delayed_scbs[scratch_offset],
                     prev_scbp);
                 }
               }
-	      scbq_insert_head(&p->device_status[ti].delayed_scbs, scb);
-	      p->device_status[ti].active_cmds--;
-	      scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+              next_scbp = NULL;
+              active_hscb = aic_inb(p, SCBPTR);
+              prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
+              next_hscb = aic_inb(p, WAITING_SCBH);
+              while (next_hscb != SCB_LIST_NULL)
+              {
+                aic_outb(p, next_hscb, SCBPTR);
+                scb_index = aic_inb(p, SCB_TAG);
+                if (scb_index < p->scb_data->numscbs)
+                {
+                  next_scbp = p->scb_data->scb_array[scb_index];
+                  if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+                      SCB_LIST_NULL) )
+                  {
+                    if (next_scbp->flags & SCB_WAITINGQ)
+                    {
+                      p->dev_active_cmds[scratch_offset]++;
+                      p->activescbs--;
+                      scbq_remove(&p->delayed_scbs[scratch_offset], next_scbp);
+                      scbq_remove(&p->waiting_scbs, next_scbp);
+                    }
+                    scbq_insert_head(&p->delayed_scbs[scratch_offset],
+                      next_scbp);
+                    next_scbp->flags |= SCB_WAITINGQ;
+                    p->dev_active_cmds[scratch_offset]--;
+                    p->activescbs--;
+                    next_hscb = aic_inb(p, SCB_NEXT);
+                    aic_outb(p, 0, SCB_CONTROL);
+                    aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+                    aic7xxx_add_curscb_to_free_list(p);
+                    if (prev_hscb == SCB_LIST_NULL)
+                    {
+                      /* We were first on the list,
+                       * so we kill the selection
+                       * hardware.  Let the sequencer
+                       * re-init the hardware itself
+                       */
+                      aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+                      aic_outb(p, CLRSELTIMEO, CLRSINT1);
+                      aic_outb(p, next_hscb, WAITING_SCBH);
+                    }
+                    else
+                    {
+                      aic_outb(p, prev_hscb, SCBPTR);
+                      aic_outb(p, next_hscb, SCB_NEXT);
+                    }
+                  }
+                  else
+                  {
+                    prev_hscb = next_hscb;
+                    next_hscb = aic_inb(p, SCB_NEXT);
+                  }
+                } /* scb_index >= p->scb_data->numscbs */
+              }
+              aic_outb(p, active_hscb, SCBPTR);
+              if (scb->flags & SCB_WAITINGQ)
+              {
+                scbq_remove(&p->delayed_scbs[scratch_offset], scb);
+                scbq_remove(&p->waiting_scbs, scb);
+                p->dev_active_cmds[scratch_offset]++;
+                p->activescbs++;
+              }
+              scbq_insert_head(&p->delayed_scbs[scratch_offset], scb);
+              p->dev_active_cmds[scratch_offset]--;
+              p->activescbs--;
+              scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
                   
-              if (p->device_status[ti].timer.expires == 0) 
+              if (p->dev_timer[scratch_offset].expires == 0) 
+              {
+                if ( p->dev_active_cmds[scratch_offset] )
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ * 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
+                else
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ / 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
+              }
+              if (aic7xxx_verbose & VERBOSE_QUEUE_FULL)
+              {
+                if (queue_flag)
+                  printk(INFO_LEAD "Queue full received; queue depth %d, "
+                    "active %d\n", p->host_no, CTL_OF_SCB(scb),
+                    p->dev_max_queue_depth[scratch_offset],
+                    p->dev_active_cmds[scratch_offset]);
+                else
+                  printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
+
+              }
+              if (queue_flag)
+              {
+                p->dev_temp_queue_depth[scratch_offset] = 
+                  p->dev_active_cmds[scratch_offset];
+                if ( p->dev_last_queue_full[scratch_offset] !=
+                     p->dev_active_cmds[scratch_offset] )
+                {
+                  p->dev_last_queue_full[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
+                }
+                else
+                {
+                  p->dev_last_queue_full_count[scratch_offset]++;
+                }
+                if ( (p->dev_last_queue_full_count[scratch_offset] > 14) &&
+                     (p->dev_active_cmds[scratch_offset] > 4) )
+                {
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                    printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
+                      CTL_OF_SCB(scb), p->dev_active_cmds[scratch_offset]);
+                  p->dev_max_queue_depth[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full[scratch_offset] = 0;
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
+                }
+              }
+              break;
+            }
+            
+            default:
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
+                     CTL_OF_SCB(scb), scb->hscb->target_status);
+              if (!aic7xxx_error(cmd))
+              {
+                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+              }
+              break;
+          }  /* end switch */
+        }  /* end else of */
+      }
+      break;
+
+    case AWAITING_MSG:
+      {
+        unsigned char scb_index, msg_out;
+
+        scb_index = aic_inb(p, SCB_TAG);
+        msg_out = aic_inb(p, MSG_OUT);
+        scb = p->scb_data->scb_array[scb_index];
+        p->msg_index = p->msg_len = 0;
+        /*
+         * This SCB had a MK_MESSAGE set in its control byte informing
+         * the sequencer that we wanted to send a special message to
+         * this target.
+         */
+
+        if (scb->flags & SCB_DEVICE_RESET)
+        {
+          p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+            printk(INFO_LEAD "Bus device reset mailed.\n",
+                 p->host_no, CTL_OF_SCB(scb));
+        }
+        else if (scb->flags & SCB_ABORT)
+        {
+          if (scb->hscb->control & TAG_ENB)
+          {
+            if (msg_out == MSG_IDENTIFYFLAG)
+            {
+              p->msg_buf[p->msg_index++] = scb->tag_action;
+              p->msg_buf[p->msg_index++] = scb->hscb->tag;
+              p->msg_len += 2;
+            }
+            p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
+          }
+          else
+          {
+            p->msg_buf[p->msg_index++] = MSG_ABORT;
+          }
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+            printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
+              CTL_OF_SCB(scb));
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          if ( (scb->hscb->control & TAG_ENB) &&
+               (msg_out == MSG_IDENTIFYFLAG) )
+          {
+            p->msg_buf[p->msg_index++] = scb->tag_action;
+            p->msg_buf[p->msg_index++] = scb->hscb->tag;
+            p->msg_len += 2;
+          }
+          aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT));
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          unsigned char period, offset;
+
+          /*
+           * Pull the user defined setting from scratch RAM.
+           */
+          period = p->syncinfo[scratch_offset].period;
+          offset = p->syncinfo[scratch_offset].offset;
+          if ( (p->needsdtr_copy & target_mask) == 0)
+          {
+            period = 0;
+            offset = 0;
+          }
+          if ( (scb->hscb->control & TAG_ENB) &&
+               (msg_out == MSG_IDENTIFYFLAG) )
+          {
+            p->msg_buf[p->msg_index++] = scb->tag_action;
+            p->msg_buf[p->msg_index++] = scb->hscb->tag;
+            p->msg_len += 2;
+          }
+          aic7xxx_construct_sdtr(p, period, offset);
+        }
+        else 
+        {
+          sti();
+          panic("aic7xxx: AWAITING_MSG for an SCB that does "
+                "not have a waiting message.\n");
+        }
+        /*
+         * We've set everything up to send our message, now to actually do
+         * so we need to enable reqinit interrupts and let the interrupt
+         * handler do the rest.  We don't want to unpause the sequencer yet
+         * though so we'll return early.  We also have to make sure that
+         * we clear the SEQINT *BEFORE* we set the REQINIT handler active
+         * or else it's possible on VLB cards to loose the first REQINIT
+         * interrupt.  Edge triggered EISA cards could also loose this
+         * interrupt, although PCI and level triggered cards should not
+         * have this problem since they continually interrupt the kernel
+         * until we take care of the situation.
+         */
+        aic_outb(p, CLRSEQINT, CLRINT);
+        p->msg_index = 0;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+        return;
+      }
+      break;
+
+    case DATA_OVERRUN:
+      {
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned char lastphase = aic_inb(p, LASTPHASE);
+        unsigned int i;
+
+        scb = (p->scb_data->scb_array[scb_index]);
+        /*
+         * XXX - What do we really want to do on an overrun?  The
+         *       mid-level SCSI code should handle this, but for now,
+         *       we'll just indicate that the command should retried.
+         *    If we retrieved sense info on this target, then the 
+         *    base SENSE info should have been saved prior to the
+         *    overrun error.  In that case, we return DID_OK and let
+         *    the mid level code pick up on the sense info.  Otherwise
+         *    we return DID_ERROR so the command will get retried.
+         */
+        if ( !(scb->flags & SCB_SENSE) )
+        {
+          printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
+            p->host_no, CTL_OF_SCB(scb), 
+            (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
+          printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+            (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+            scb->sg_length, scb->sg_count);
+          for (i = 0; i < scb->sg_count; i++)
+          {
+            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+                 i, 
+                 le32_to_cpu(scb->sg_list[i].address),
+                 le32_to_cpu(scb->sg_list[i].length) );
+          }
+          aic7xxx_error(scb->cmd) = DID_ERROR;
+        }
+        else
+          printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
+            p->host_no, CTL_OF_SCB(scb));
+      }
+      break;
+
+    case TRACEPOINT:
+      {
+        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
+          target, lun);
+      }
+      break;
+
+    case TRACEPOINT2:
+      {
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
+          target, lun);
+      }
+      break;
+
+#if AIC7XXX_NOT_YET 
+    /* XXX Fill these in later */
+    case MSG_BUFFER_BUSY:
+      printk("aic7xxx: Message buffer busy.\n");
+      break;
+    case MSGIN_PHASEMIS:
+      printk("aic7xxx: Message-in phasemis.\n");
+      break;
+#endif
+
+    default:                   /* unknown */
+      printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, channel, target, lun, intstat,
+             aic_inb(p, SCSISIGI));
+      break;
+  }
+
+  /*
+   * Clear the sequencer interrupt and unpause the sequencer.
+   */
+  aic_outb(p, CLRSEQINT, CLRINT);
+  unpause_sequencer(p, /* unpause always */ TRUE);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_parse_msg
+ *
+ * Description:
+ *   Parses incoming messages into actions on behalf of
+ *   aic7xxx_handle_reqinit
+ *_F*************************************************************************/
+static int
+aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int reject, done;
+  unsigned char target_scratch, scratch_offset;
+  unsigned short target_mask;
+
+  reject = done = FALSE;
+  scratch_offset = TARGET_INDEX(scb->cmd);
+  target_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+  target_mask = (0x01 << scratch_offset);
+
+  /*
+   * Parse as much of the message as is availible,
+   * rejecting it if we don't support it.  When
+   * the entire message is availible and has been
+   * handled, return TRUE indicating that we have
+   * parsed an entire message.
+   */
+
+  if (p->msg_buf[0] != MSG_EXTENDED)
+  {
+    reject = TRUE;
+  }
+
+  /*
+   * Just accept the length byte outright and perform
+   * more checking once we know the message type.
+   */
+
+  if ( !reject && (p->msg_len > 2) )
+  {
+    switch(p->msg_buf[2])
+    {
+      case MSG_EXT_SDTR:
+      {
+        unsigned char period, response_period, offset;
+        unsigned char max_offset, saved_offset, rate;
+
+        if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        saved_offset = p->msg_buf[4];
+
+        if (target_scratch & WIDEXFER)
+        {
+          max_offset = MAX_OFFSET_16BIT;
+        }
+        else
+        {
+          max_offset = MAX_OFFSET_8BIT;
+        }
+        offset = MIN(saved_offset, max_offset);
+        response_period = aic7xxx_scsirate(p, &rate, &period,
+          &offset, scb->cmd->target, scb->cmd->channel, /* set */ TRUE);
+        /* Preserve the WideXfer flag */
+        target_scratch = rate | (target_scratch & WIDEXFER);
+
+        /*
+         * Update the TARGET_SCRATCH, the SCSIRATE, and our syncinfo
+         * areas.
+         */
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, target_scratch, SCSIRATE);
+        p->syncinfo[scratch_offset].period = response_period;
+        p->syncinfo[scratch_offset].offset = offset;
+
+        /*
+         * Did we start this, if not, or if we went to low and had to
+         * go async, then send an SDTR back to the target
+         */
+        p->needsdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          if (saved_offset != offset)
+          {
+            p->needsdtr_copy &= ~target_mask;
+            reject = TRUE; 
+          }
+          scb->flags &= ~SCB_MSGOUT_SDTR;
+          p->sdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_SDTR;
+          p->sdtr_pending |= target_mask;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_WDTR:
+      {
+        unsigned char bus_width;
+          
+        if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
+        {
+          break;
+        }
+
+        bus_width = p->msg_buf[3];
+        p->needwdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reject = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
               {
-		if ( p->device_status[ti].active_cmds )
-		{
-                  p->device_status[ti].timer.expires = jiffies + (HZ * 2);
-                  add_timer(&p->device_status[ti].timer);
-		}
-		else
-		{
-                  p->device_status[ti].timer.expires = jiffies + (HZ / 2);
-                  add_timer(&p->device_status[ti].timer);
-		}
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
               }
-   	      if (aic7xxx_verbose > 1)
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
               {
-                if (queue_flag)
-                  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queue full received; "
-                     "queue depth %d, active %d\n", p->host_no,
-                     CTL_OF_SCB(scb), p->device_status[ti].max_queue_depth,
-                     p->device_status[ti].active_cmds);
-                else
-                  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target busy\n",
-                     p->host_no, CTL_OF_SCB(scb));
-
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
               }
-              if (queue_flag)
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
               {
-	        p->device_status[ti].temp_queue_depth = 
-		  p->device_status[ti].active_cmds;
-                if ( (p->device_status[ti].last_queue_full <
-                     (p->device_status[ti].active_cmds - 1)) ||
-                     (p->device_status[ti].last_queue_full >
-                     (p->device_status[ti].active_cmds + 1)) )
-                {
-                  p->device_status[ti].last_queue_full = 
-                      p->device_status[ti].active_cmds;
-                  p->device_status[ti].last_queue_full_count = 0;
-                }
-                else
-                {
-                  p->device_status[ti].last_queue_full_count++;
-                }
-                if ( (p->device_status[ti].last_queue_full_count > 14) &&
-                     (p->device_status[ti].active_cmds > 4) )
-                {
-		  if (aic7xxx_verbose)
-                    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queue depth reduced "
-                      "to %d\n", p->host_no, CTL_OF_SCB(scb), 
-                      p->device_status[ti].active_cmds);
-                  p->device_status[ti].max_queue_depth = 
-                      p->device_status[ti].active_cmds;
-                  p->device_status[ti].last_queue_full = 0;
-                  p->device_status[ti].last_queue_full_count = 0;
-                }
+                printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
               }
+              target_scratch |= WIDEXFER;
               break;
             }
-            
+          }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->wdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          switch(bus_width)
+          {
             default:
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Unexpected target "
-                     "status 0x%x.\n", p->host_no,
-        	     CTL_OF_SCB(scb), scb->hscb->target_status);
-              if (!aic7xxx_error(cmd))
+            {
+              if (p->type & AHC_WIDE)
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                p->needwdtr_copy |= target_mask;
+                scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                target_scratch |= WIDEXFER;
+                if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                     (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+                {
+                  printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                    p->host_no, CTL_OF_SCB(scb));
+                  p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+                }
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              scb->flags |= SCB_MSGOUT_WDTR_8BIT;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
               {
-        	aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
               }
               break;
-          }  /* end switch */
-	}  /* end else of */
+            }
+          }
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          p->wdtr_pending |= target_mask;
+        }
+        aic_outb(p, target_scratch, SCSIRATE);
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        p->syncinfo[scratch_offset].offset =
+          (bus_width == MSG_EXT_WDTR_BUS_8_BIT) ? 
+          MAX_OFFSET_8BIT : MAX_OFFSET_16BIT;
+        done = TRUE;
+        break;
       }
-      break;
+      default:
+      {
+        reject = TRUE;
+        break;
+      }
+    } /* end of switch(p->msg_type) */
+  } /* end of if (!reject && (p->msg_len > 2)) */
 
-    case AWAITING_MSG:
+  if (reject)
+  {
+    aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
+    aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+  }
+  return(done);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_reqinit
+ *
+ * Description:
+ *   Interrupt handler for REQINIT interrupts (used to transfer messages to
+ *    and from devices).
+ *_F*************************************************************************/
+static void
+aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char lastbyte;
+  unsigned char phasemis;
+  int done;
+
+  switch(p->msg_type)
+  {
+    case MSG_TYPE_INITIATOR_MSGOUT:
       {
-	unsigned char scb_index;
-        unsigned char message_offset;
+        if (p->msg_len == 0)
+          panic("aic7xxx: REQINIT with no active message!\n");
 
-	scb_index = inb(p->base + SCB_TAG);
-	scb = p->scb_data->scb_array[scb_index];
+        lastbyte = (p->msg_index == (p->msg_len - 1));
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
 
-	/*
-	 * This SCB had a MK_MESSAGE set in its control byte informing
-	 * the sequencer that we wanted to send a special message to
-	 * this target.
-	 */
-        message_offset = inb(p->base + MSG_LEN);
-	if (scb->flags & SCB_DEVICE_RESET)
-	{
-          outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
-          outb(1, p->base + MSG_LEN);
-          if (aic7xxx_verbose > 1)
-            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset mailed.\n",
-        	 p->host_no, CTL_OF_SCB(scb));
-	}
-        else if (scb->flags & SCB_ABORT)
+        if (lastbyte || phasemis)
         {
-          if ((scb->hscb->control & TAG_ENB) != 0)
+          /* Time to end the message */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          /*
+           * NOTE-TO-MYSELF: If you clear the REQINIT after you
+           * disable REQINITs, then cases of REJECT_MSG stop working
+           * and hang the bus
+           */
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+
+          if (phasemis == 0)
           {
-            outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+            aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
+            aic_outb(p, 0, RETURN_1);
           }
           else
           {
-            outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+            aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
           }
-          outb(message_offset + 1, p->base + MSG_LEN);
-          if (aic7xxx_verbose > 1)
-            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort message mailed.\n",
-                 p->host_no, CTL_OF_SCB(scb));
-        }
-	else if (scb->flags & SCB_MSGOUT_WDTR)
-	{
-          aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+          unpause_sequencer(p, TRUE);
         }
-        else if (scb->flags & SCB_MSGOUT_SDTR)
+        else
         {
-          unsigned char target_scratch;
-          unsigned short ultra_enable;
-          int i, sxfr;
-
           /*
-           * Pull the user defined setting from scratch RAM.
+           * Present the byte on the bus (clearing REQINIT) but don't
+           * unpause the sequencer.
            */
-          target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-          sxfr = target_scratch & SXFR;
-          ultra_enable = inb(p->base + ULTRA_ENB) |
-              (inb(p->base + ULTRA_ENB + 1) << 8);
-          if (ultra_enable & target_mask)
-          {
-            sxfr |= 0x100;
-          }
-          for (i = 0; i < num_aic7xxx_syncrates; i++)
-          {
-            if (sxfr == aic7xxx_syncrates[i].rate)
-            break;
-          }
-          aic7xxx_construct_sdtr(p, message_offset,
-                                 aic7xxx_syncrates[i].period,
-                                 target_scratch & WIDEXFER ?
-                                 MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_outb(p,  p->msg_buf[p->msg_index++], SCSIDATL);
         }
-        else 
-        {
-          panic("aic7xxx: AWAITING_MSG for an SCB that does "
-                "not have a waiting message.");
-	}
+        break;
       }
-      break;
-
-    case DATA_OVERRUN:
+    case MSG_TYPE_INITIATOR_MSGIN:
       {
-	unsigned char scb_index = inb(p->base + SCB_TAG);
-        unsigned char lastphase = inb(p->base + LASTPHASE);
-	unsigned int i, overrun;
-
-	scb = (p->scb_data->scb_array[scb_index]);
-	overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
-  		  (inb(p->base + STCNT + 2) << 16);
-	overrun = 0x00FFFFFF - overrun;
-        if (aic7xxx_verbose)
-        {
-	  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Data overrun of %d bytes "
-               "detected in %s phase, tag %d; forcing a retry.\n",
-               p->host_no, CTL_OF_SCB(scb), overrun,
-               lastphase == P_DATAIN ? "Data-In" : "Data-Out",
-               scb->hscb->tag);
-          printk(KERN_WARNING "%s seen Data Phase. Length=%d, NumSGs=%d.\n",
-               inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
-               aic7xxx_length(scb->cmd, 0), scb->sg_count);
-          for (i = 0; i < scb->sg_count; i++)
-          {
-            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
-                   i, scb->sg_list[i].address, scb->sg_list[i].length);
-          }
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
+
+        if (phasemis == 0)
+        {
+          p->msg_len++;
+          /* Pull the byte in without acking it */
+          p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
+          done = aic7xxx_parse_msg(p, scb);
+          /* Ack the byte */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_inb(p, SCSIDATL);
+          p->msg_index++;
+        }
+        if (phasemis || done)
+        {
+          /* Time to end our message session */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          p->flags &= ~AHC_HANDLING_REQINITS;
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          unpause_sequencer(p, TRUE);
         }
-	/*
-	 * XXX - What do we really want to do on an overrun?  The
-	 *       mid-level SCSI code should handle this, but for now,
-	 *       we'll just indicate that the command should retried.
-	 */
-	aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
+        break;
       }
-      break;
-
-/* #if AIC7XXX_NOT_YET */
-    /* XXX Fill these in later */
-    case MSG_BUFFER_BUSY:
-      printk("aic7xxx: Message buffer busy.\n");
-      break;
-    case MSGIN_PHASEMIS:
-      printk("aic7xxx: Message-in phasemis.\n");
-      break;
-/*#endif */
-
-    case ABORT_CMDCMPLT:
-      /* This interrupt serves to pause the sequencer until we can clean
-       * up the QOUTFIFO allowing us to handle any abort SCBs that may
-       * completed yet still have an SCB in the QINFIFO or waiting for
-       * selection queue.  By the time we get here, we should have
-       * already cleaned up the queues, so all we need to do is unpause
-       * the sequencer.
-       */
-      break;
-
-    default:		   /* unknown */
-      printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-             p->host_no, intstat, inb(p->base + SCSISIGI));
-      break;
-  }
-
-  /*
-   * Clear the sequencer interrupt and unpause the sequencer.
-   */
-  outb(CLRSEQINT, p->base + CLRINT);
-  unpause_sequencer(p, /* unpause always */ TRUE);
+    default:
+      {
+        panic("aic7xxx: Unknown REQINIT message type.\n");
+        break;
+      }
+  } /* End of switch(p->msg_type) */
 }
 
 /*+F*************************************************************************
@@ -3898,8 +4622,8 @@
   unsigned char status;
   struct aic7xxx_scb *scb;
 
-  scb_index = inb(p->base + SCB_TAG);
-  status = inb(p->base + SSTAT1);
+  scb_index = aic_inb(p, SCB_TAG);
+  status = aic_inb(p, SSTAT1);
 
   if (scb_index < p->scb_data->numscbs)
   {
@@ -3914,19 +4638,41 @@
     scb = NULL;
   }
 
+
+  if ( (p->flags & AHC_HANDLING_REQINITS) && (status & REQINIT) )
+  {
+    if (scb)
+    {
+      aic7xxx_handle_reqinit(p, scb);
+    }
+    else
+    {
+      p->flags &= ~AHC_HANDLING_REQINITS;
+      aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+      aic_outb(p, CLRREQINIT, CLRSINT1);
+      aic_outb(p, CLRSCSIINT, CLRINT);
+      p->msg_type = MSG_TYPE_NONE;
+      p->msg_index = 0;
+      p->msg_len = 0;
+    }
+    return;
+  }
+
   if ((status & SCSIRSTI) != 0)
   {
-    char channel;
+    int channel;
 
-    channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
 
-    printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
-           p->host_no, channel);
+    if (aic7xxx_verbose & VERBOSE_RESET)
+      printk(WARN_LEAD "Someone else reset the channel!!\n",
+           p->host_no, channel, -1, -1);
     /*
      * Go through and abort all commands for the channel, but do not
      * reset the channel again.
      */
     aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+    aic7xxx_run_done_queue(p, FALSE);
     scb = NULL;
   }
   else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
@@ -3936,28 +4682,27 @@
      * chances are pretty good that the bus free was in response to
      * one of our abort requests.
      */
-    unsigned char lastphase = inb(p->base + LASTPHASE);
-    unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
-    char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
+    unsigned char target = (saved_tcl >> 4) & 0x0F;
+    int channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
     int printerror = TRUE;
 
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     if (lastphase == P_MESGOUT)
     {
-      unsigned char sindex;
       unsigned char message;
 
-      sindex = inb(p->base + SINDEX);
-      message = inb(p->base + sindex - 1);
+      message = aic_inb(p, SINDEX);
 
       if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
       {
-	if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB %d abort delivered.\n",
-                   p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
+            CTL_OF_SCB(scb), scb->hscb->tag);
         aic7xxx_reset_device(p, target, channel, ALL_LUNS,
-		(message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
-	aic7xxx_run_done_queue(p, FALSE);
+                (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+        aic7xxx_run_done_queue(p, FALSE);
         scb = NULL;
         printerror = 0;
       }
@@ -3983,22 +4728,25 @@
           tag = SCB_LIST_NULL;
         }
         aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
-	aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, FALSE);
       }
       else
       {  /* Since we don't really know what happened here, we'll wait */
-	 /* for the commands to timeout and get aborted if need be    */
+         /* for the commands to timeout and get aborted if need be    */
         aic7xxx_add_curscb_to_free_list(p);
       }
-      printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
-             "SEQADDR = 0x%x\n", p->host_no, lastphase,
-             (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+      printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
+             "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
+             (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       scb = NULL;
     }
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
-    outb(CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if ((status & SELTO) != 0)
   {
@@ -4006,9 +4754,18 @@
     unsigned char nextscb;
     Scsi_Cmnd *cmd;
 
-    scbptr = inb(p->base + WAITING_SCBH);
-    outb(scbptr, p->base + SCBPTR);
-    scb_index = inb(p->base + SCB_TAG);
+    scbptr = aic_inb(p, WAITING_SCBH);
+    if (scbptr >= p->scb_data->maxhscbs)
+    {
+      scb_index = SCB_LIST_NULL;
+      printk(WARN_LEAD "Bad scbptr %d during SELTO.\n", 
+        p->host_no, -1, -1, -1, scbptr);
+    }
+    else
+    {
+      aic_outb(p, scbptr, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+    }
 
     scb = NULL;
     if (scb_index < p->scb_data->numscbs)
@@ -4021,63 +4778,80 @@
     }
     if (scb == NULL)
     {
-      printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
-             p->host_no, scb_index);
+      printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, -1, -1, -1, scb_index);
       printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
-             "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
-             inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-             inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+             "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
+             aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+             aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
     }
     else
     {
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       */
       cmd = scb->cmd;
       cmd->result = (DID_TIME_OUT << 16);
 
       /*
-       * Clear an pending messages for the timed out
-       * target and mark the target as free.
+       * Clear out this hardware SCB
+       */
+      aic_outb(p, 0, SCB_CONTROL);
+
+      /*
+       * Clear out a few values in the card that are in an undetermined
+       * state.
        */
-      outb(0, p->base + MSG_LEN);
-      aic7xxx_index_busy_target(p, cmd->target,
-          cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
-      outb(0, p->base + SCB_CONTROL);
+      aic_outb(p, MSG_NOOP, MSG_OUT);
 
       /*
        * Shift the waiting for selection queue forward
        */
-      nextscb = inb(p->base + SCB_NEXT);
-      outb(nextscb, p->base + WAITING_SCBH);
+      nextscb = aic_inb(p, SCB_NEXT);
+      aic_outb(p, nextscb, WAITING_SCBH);
 
       /*
        * Put this SCB back on the free list.
        */
       aic7xxx_add_curscb_to_free_list(p);
+      /*
+       * XXX - If we queued an abort tag, go clean up the disconnected list.
+       * We know that this particular SCB had to be the queued abort since
+       * the disconnected SCB would have gotten a reconnect instead.
+       * However, if this is an abort command, then DID_TIMEOUT isn't
+       * appropriate, neither is returning the command for that matter.
+       * What we need to do then is to let the command timeout again so
+       * we get a reset since this abort just failed.
+       */
+      if (p->flags & SCB_QUEUED_ABORT)
+      {
+        cmd->result = 0;
+        scb->flags &= ~SCB_QUEUED_ABORT;
+        scb = NULL;
+      }
     }
     /*
-     * Stop the selection.
+     * Restarting the sequencer will stop the selection and make sure devices
+     * are allowed to reselect in.
      */
-    outb(0, p->base + SCSISEQ);
-    outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if (scb == NULL)
   {
-    printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+    printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
            "during scsiint 0x%x scb(%d)\n"
            "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
-           p->host_no, status, scb_index, inb(p->base + SIMODE0),
-           inb(p->base + SIMODE1), inb(p->base + SSTAT0),
-           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+           p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
+           aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+           (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
     /*
      * Turn off the interrupt and set status to zero, so that it
      * falls through the rest of the SCSIINT code.
      */
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
@@ -4089,7 +4863,7 @@
     char  *phase;
     Scsi_Cmnd *cmd;
     unsigned char mesg_out = MSG_NOOP;
-    unsigned char lastphase = inb(p->base + LASTPHASE);
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
 
     cmd = scb->cmd;
     switch (lastphase)
@@ -4124,7 +4898,7 @@
      * A parity error has occurred during a data
      * transfer phase. Flag it and continue.
      */
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Parity error during phase %s.\n",
+    printk(WARN_LEAD "Parity error during phase %s.\n",
            p->host_no, CTL_OF_SCB(scb), phase);
 
     /*
@@ -4135,19 +4909,11 @@
      */
     if (mesg_out != MSG_NOOP)
     {
-      outb(mesg_out, p->base + MSG_OUT);
-      outb(1, p->base + MSG_LEN);
+      aic_outb(p, mesg_out, MSG_OUT);
       scb = NULL;
     }
-    else
-    {
-      /*
-       * Should we allow the target to make this decision for us?
-       */
-      cmd->result = DID_RETRY_COMMAND << 16;
-    }
-    outb(CLRSCSIPERR, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, CLRSCSIPERR, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause_always */ TRUE);
   }
   else
@@ -4156,9 +4922,11 @@
      * We don't know what's going on. Turn off the
      * interrupt source and try to continue.
      */
-    printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    if (aic7xxx_verbose & VERBOSE_SCSIINT)
+      printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
+        p->host_no, -1, -1, -1, status);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
@@ -4168,184 +4936,230 @@
   }
 }
 
+#ifdef CONFIG_PCI
+
+#define  DPE 0x80
+#define  SSE 0x40
+#define  RMA 0x20
+#define  RTA 0x10
+#define  STA 0x08
+#define  DPR 0x01
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_pci_intr
+ *
+ * Description:
+ *   Check the scsi card for PCI errors and clear the interrupt
+ *
+ *   NOTE: If you don't have this function and a 2940 card encounters
+ *         a PCI error condition, the machine will end up locked as the
+ *         interrupt handler gets slammed with non-stop PCI error interrupts
+ *-F*************************************************************************/
+static void
+aic7xxx_pci_intr(struct aic7xxx_host *p)
+{
+  unsigned char status1;
+  int error;
+
+  error = 0;
+  error = pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, &status1);
+
+  if (error == 0)
+  {
+    if (status1 & DPE)
+      printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+        "phase.\n", p->host_no, -1, -1, -1);
+    if (status1 & SSE)
+      printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RMA)
+      printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RTA)
+      printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & STA)
+      printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & DPR)
+      printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+        "PERR#\n", p->host_no, -1, -1, -1);
+  }
+  else
+  {
+    printk(WARN_LEAD "Error reading PCI config register during PCI ERROR"
+      "interrupt.\n", p->host_no, -1, -1, -1);
+    aic_outb(p,  CLRPARERR, CLRINT);
+    return;
+  }
+  
+  pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, status1);
+  if (status1 & (DPR|RMA|RTA))
+    aic_outb(p,  CLRPARERR, CLRINT);
+
+}
+#endif
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_isr
  *
  * Description:
  *   SCSI controller interrupt handler.
- *
- *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- *         be disabled all through this function unless we say otherwise.
  *-F*************************************************************************/
 static void
 aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
   struct aic7xxx_host *p;
   unsigned char intstat;
-  unsigned long flags;
-  unsigned int interrupts_cleared = 0;
 
-  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+  p = (struct aic7xxx_host *)dev_id;
 
   /*
-   * Search for the host with a pending interrupt.  If we can't find
-   * one, then we've encountered a spurious interrupt.
+   * Just a few sanity checks.  Make sure p != NULL, that we have an
+   * interrupt pending, and that we aren't already in our int handler.
+   * Also, if PCI, then we are going to check for a PCI bus error status
+   * should we get too many spurious interrupts.
    */
-  while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
+  if (p == NULL)
+  {
+    printk(KERN_WARNING "aic7xxx: ISR routine called with NULL dev_id\n");
+    return;
+  }
+  else if (!(aic_inb(p, INTSTAT) & INT_PEND))
   {
-    if (p->next == NULL)
+#ifdef CONFIG_PCI
+    if ((p->type & AHC_AIC78x0) && (p->spurious_int > 500))
     {
-      p = NULL;
+      if ( aic_inb(p, ERROR) & PCIERRSTAT )
+      {
+        aic7xxx_pci_intr(p);
+      }
+      p->spurious_int = 0;
     }
     else
     {
-      p = (struct aic7xxx_host *) p->next->hostdata;
+      p->spurious_int++;
     }
+#endif
+    return;
   }
-
-  if (p == NULL)
+  else if (p->flags & AHC_IN_ISR)
+  {
     return;
+  }
 
   /*
    * Handle all the interrupt sources - especially for SCSI
    * interrupts, we won't get a second chance at them.
    */
-  intstat = inb(p->base + INTSTAT);
+  intstat = aic_inb(p, INTSTAT);
+  p->spurious_int = 0;
 
   /*
    * Keep track of interrupts for /proc/scsi
    */
   p->isr_count++;
-
-  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
-  {
-    /*
-     * We must only have one card at this IRQ and it must have been
-     * added to the board data before the spurious interrupt occurred.
-     * It is sufficient that we check isr_count and not the spurious
-     * interrupt count.
-     */
-    printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
-    if (intstat)
-    {
-      /* Try clearing all interrupts. */
-      outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
-    }
-    return;
-  }
-
-  if (p->flags & IN_ISR)
-  {
-    panic(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
-           p->host_no);
-    return;
-  }
+  p->flags |= AHC_IN_ISR;
 
   /*
    * Indicate that we're in the interrupt handler.
    */
-  save_flags(flags);
-  p->flags |= IN_ISR;
-
   if (intstat & CMDCMPLT)
   {
     struct aic7xxx_scb *scb = NULL;
     Scsi_Cmnd *cmd;
-    unsigned char qoutcnt;
     unsigned char scb_index;
-    int i;
 
     /*
+     * Clear interrupt status before running the completion loop.
+     * This eliminates a race condition whereby a command could
+     * complete between the last check of qoutfifo and the
+     * CLRCMDINT statement.  This would result in us thinking the
+     * qoutfifo was empty when it wasn't, and in actuality be a lost
+     * completion interrupt.  With multiple devices or tagged queueing
+     * this could be very bad if we caught all but the last completion
+     * and no more are imediately sent.
+     */
+    aic_outb(p, CLRCMDINT, CLRINT);
+    /*
      * The sequencer will continue running when it
      * issues this interrupt. There may be >1 commands
      * finished, so loop until we've processed them all.
      */
-    cli();
-    qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
 
-#if 1
-  if (qoutcnt >= p->qfullcount - 1)
-    printk(KERN_WARNING "(scsi%d:-1:-1:-1) Command complete near Qfull count, "
-           "qoutcnt = %d.\n", p->host_no, qoutcnt);
-#endif
-    while (qoutcnt > 0)
+    while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
     {
-      if (p->flags & PAGE_ENABLED)
+      scb_index = p->qoutfifo[p->qoutfifonext];
+      p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+      if ( scb_index >= p->scb_data->numscbs )
+        scb = NULL;
+      else
+        scb = p->scb_data->scb_array[scb_index];
+      if (scb == NULL)
       {
-        p->cmdoutcnt += qoutcnt;
-        if ( p->cmdoutcnt >= p->qfullcount )
-        {
-          outb(0, p->base + CMDOUTCNT);
-          p->cmdoutcnt = 0;
-        }
+        printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+          -1, -1, -1, scb_index);
+        continue;
+      }
+      else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+      {
+        printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+          "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+          (unsigned long) scb->cmd);
+        continue;
       }
-      for (i = 0; i < qoutcnt; i++)
+      else if (scb->flags & SCB_QUEUED_ABORT)
       {
-        scb_index = inb(p->base + QOUTFIFO);
-	if ( scb_index >= p->scb_data->numscbs )
-	    scb = NULL;
-	else
-            scb = p->scb_data->scb_array[scb_index];
-        if (scb == NULL)
+        pause_sequencer(p);
+        if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
+             (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
         {
-	  printk(KERN_WARNING "(scsi%d:-1:-1:-1) CMDCMPLT with invalid SCB "
-	         "index %d, QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
-                 inb(p->base + QOUTCNT), inb(p->base + QINCNT));
+          unpause_sequencer(p, FALSE);
           continue;
         }
-        else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-        {
-	  printk(KERN_WARNING "(scsi%d:-1:-1:-1) CMDCMPLT without command for "
-	         "SCB %d, QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
-                 p->host_no, scb_index, inb(p->base + QOUTCNT),
-                 inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
-	  continue;
-        }
-	switch (status_byte(scb->hscb->target_status))
-	{
-	  case QUEUE_FULL:
-	  case BUSY:
-	    scb->hscb->target_status = 0;
-            scb->cmd->result = 0;
-            aic7xxx_error(scb->cmd) = DID_OK;
-	    break;
-	  default:
-            cmd = scb->cmd;
-            if (scb->hscb->residual_SG_segment_count != 0)
-            {
-              aic7xxx_calculate_residual(p, scb);
-            }
-            cmd->result |= (aic7xxx_error(cmd) << 16);
-            p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-            aic7xxx_done(p, scb);
-	}
-      }
-      /*
-       * Clear interrupt status before checking the output queue again.
-       * This eliminates a race condition whereby a command could
-       * complete between the queue poll and the interrupt clearing,
-       * so notification of the command being complete never made it
-       * back up to the kernel.
-       */
-      outb(CLRCMDINT, p->base + CLRINT);
-      interrupts_cleared++;
-      qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
-    }
-
-    if (interrupts_cleared == 0)
-    {
-      outb(CLRCMDINT, p->base + CLRINT);
+        aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
+          scb->cmd->lun, scb->cmd->lun);
+        scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
+          SCB_QUEUED_ABORT);
+        unpause_sequencer(p, FALSE);
+      }
+      switch (status_byte(scb->hscb->target_status))
+      {
+        case QUEUE_FULL:
+        case BUSY:
+          scb->hscb->target_status = 0;
+          scb->cmd->result = 0;
+          aic7xxx_error(scb->cmd) = DID_OK;
+          break;
+        default:
+          cmd = scb->cmd;
+          if (scb->hscb->residual_SG_segment_count != 0)
+          {
+            aic7xxx_calculate_residual(p, scb);
+          }
+          cmd->result |= (aic7xxx_error(cmd) << 16);
+          if (scb->tag_action)
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_TAGGED_SUCCESS | DEVICE_SUCCESS | DEVICE_PRESENT;
+          else
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_SUCCESS | DEVICE_PRESENT;
+          aic7xxx_done(p, scb);
+          break;
+      }      
     }
-    restore_flags(flags);
   }
 
   if (intstat & BRKADRINT)
   {
     int i;
-    unsigned char errno = inb(p->base + ERROR);
+    unsigned char errno = aic_inb(p, ERROR);
 
-    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+    printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno);
     for (i = 0; i < NUMBER(hard_error); i++)
     {
       if (errno & hard_error[i].errno)
@@ -4353,38 +5167,56 @@
         printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
       }
     }
-    aic7xxx_reset_channel(p, 'A', TRUE);
-    if ( p->bus_type == AIC_TWIN )
+    printk(KERN_ERR "(scsi%d)   LINE=%d\n", p->host_no,
+      (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
+    aic7xxx_reset_channel(p, 0, TRUE);
+    if ( p->type & AHC_TWIN )
     {
-      aic7xxx_reset_channel(p, 'B', TRUE);
+      aic7xxx_reset_channel(p, 1, TRUE);
       restart_sequencer(p);
-      pause_sequencer(p);
     }
-    outb(CLRBRKADRINT, p->base + CLRINT);
+    aic7xxx_run_done_queue(p, FALSE);
+    aic_outb(p, CLRBRKADRINT, CLRINT);
   }
 
   if (intstat & SEQINT)
   {
-    cli();
     aic7xxx_handle_seqint(p, intstat);
-    restore_flags(flags);
   }
 
   if (intstat & SCSIINT)
   {
-    cli();
     aic7xxx_handle_scsiint(p, intstat);
-    restore_flags(flags);
   }
-
   aic7xxx_done_cmds_complete(p);
-  cli();
   aic7xxx_run_waiting_queues(p);
-  unpause_sequencer(p, TRUE);
-  p->flags &= ~IN_ISR;
-  restore_flags(flags);
+  p->flags &= ~AHC_IN_ISR;
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   do_aic7xxx_isr
+ *
+ * Description:
+ *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ *   above.  Please, children, do not try this at home, and if you ever see
+ *   anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+static void
+do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long cpu_flags;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+  aic7xxx_isr(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#else
+  DRIVER_LOCK
+  aic7xxx_isr(irq, dev_id, regs);
+  DRIVER_UNLOCK
+#endif
+}
 
 /*+F*************************************************************************
  * Function:
@@ -4406,55 +5238,58 @@
 static void
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
-  int default_depth = 2;
+  int default_depth = 3;
   unsigned char tindex;
+  unsigned short target_mask;
 
   tindex = device->id | (device->channel << 3);
+  target_mask = (1 << tindex);
 
   device->queue_depth = default_depth;
-#ifdef AIC7XXX_TAGGED_QUEUEING
+  p->dev_mid_level_queue_depth[tindex] = 3;
+  p->dev_temp_queue_depth[tindex] = 1;
+  p->dev_max_queue_depth[tindex] = 1;
+  p->tagenable &= ~target_mask;
+
   if (device->tagged_supported)
   {
-    unsigned short target_mask;
     int tag_enabled = TRUE;
 
-    target_mask = (1 << (device->id | (device->channel << 3)));
-
 #ifdef AIC7XXX_CMDS_PER_LUN
     default_depth = AIC7XXX_CMDS_PER_LUN;
 #else
-    if (p->scb_data->maxhscbs <= 4)
-    {
-      default_depth = 4;  /* Not many SCBs to work with. */
-    }
-    else
-    {
-      default_depth = 8;
-    }
+    default_depth = 8;  /* Not many SCBs to work with. */
 #endif
  
     if (!(p->discenable & target_mask))
     {
-      printk(KERN_INFO "(scsi%d:%d:%d:%d) Disconnection disabled, unable to "
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
+        printk(INFO_LEAD "Disconnection disabled, unable to "
              "enable tagged queueing.\n",
              p->host_no, device->channel, device->id, device->lun);
     }
     else
     {
-#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
-      device->queue_depth = default_depth;
-#else
       if (p->instance >= NUMBER(aic7xxx_tag_info))
       {
+        static int print_warning = TRUE;
+        if(print_warning)
+        {
+          printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
+                           " installed controllers.\n");
+          printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
+                           " the aic7xxx.c source file.\n");
+          print_warning = FALSE;
+        }
         device->queue_depth = default_depth;
       }
       else
       {
 
-        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
         {
           tag_enabled = FALSE;
-          device->queue_depth = 2;  /* Tagged queueing is disabled. */
+          device->queue_depth = 3;  /* Tagged queueing is disabled. */
         }
         else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
@@ -4466,23 +5301,24 @@
             aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
       }
-#endif
       if ((device->tagged_queue == 0) && tag_enabled)
       {
-        if (aic7xxx_verbose)
+        if (aic7xxx_verbose & VERBOSE_QUEUE)
         {
-    	  printk(KERN_INFO "(scsi%d:%d:%d:%d) Enabled tagged queuing, "
-    	         "queue depth %d.\n", p->host_no,
-    	         device->channel, device->id, device->lun, device->queue_depth);
-        }
-        p->device_status[tindex].max_queue_depth = device->queue_depth;
-        p->device_status[tindex].temp_queue_depth = device->queue_depth;
+              printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
+                p->host_no, device->channel, device->id,
+                device->lun, device->queue_depth);
+        }
+        p->dev_max_queue_depth[tindex] = device->queue_depth;
+        p->dev_temp_queue_depth[tindex] = device->queue_depth;
+        p->dev_mid_level_queue_depth[tindex] = device->queue_depth;
+        p->tagenable |= target_mask;
+        p->orderedtag |= target_mask;
         device->tagged_queue = 1;
         device->current_tag = SCB_LIST_NULL;
       }
     }
   }
-#endif
 }
 
 /*+F*************************************************************************
@@ -4503,14 +5339,27 @@
 {
   Scsi_Device *device;
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  int scbnum;
 
+  scbnum = 0;
   for (device = scsi_devs; device != NULL; device = device->next)
   {
     if (device->host == host)
     {
       aic7xxx_device_queue_depth(p, device);
+      scbnum += device->queue_depth;
     }
   }
+  while (scbnum > p->scb_data->numscbs)
+  {
+    /*
+     * Pre-allocate the needed SCBs to get around the possibility of having
+     * to allocate some when memory is more or less exhausted and we need
+     * the SCB in order to perform a swap operation (possible deadlock)
+     */
+    if ( aic7xxx_allocate_scb(p, TRUE) == NULL )
+      return;
+  }
 }
 
 /*+F*************************************************************************
@@ -4534,9 +5383,15 @@
  *
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
- *-F*************************************************************************/
-static aha_chip_type
-aic7xxx_probe(int slot, int base, aha_status_type *bios)
+ *
+ * NOTE:  This function is only needed on Intel and Alpha platforms,
+ *   the other platforms we support don't have EISA/VLB busses.  So,
+ *   we #ifdef this entire function to avoid compiler warnings about
+ *   an unused function.
+ *-F*************************************************************************/
+#if defined(__i386__) || defined(__alpha__)
+static ahc_type
+aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
 {
   int i;
   unsigned char buf[4];
@@ -4544,13 +5399,13 @@
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    aha_chip_type type;
+    ahc_type type;
     int bios_disabled;
   } AIC7xxx[] = {
-    { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
-    { 4, { 0x04, 0x90, 0x77, 0x70 }, AIC_7770, FALSE }, /* motherboard 7770  */
-    { 4, { 0x04, 0x90, 0x77, 0x56 }, AIC_284x, FALSE }, /* 284x BIOS enabled */
-    { 4, { 0x04, 0x90, 0x77, 0x57 }, AIC_284x, TRUE }   /* 284x BIOS disabled */
+    { 4, { 0x04, 0x90, 0x77, 0x71 }, AHC_274, FALSE }, /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x70 }, AHC_AIC7770, FALSE },  /* mb 7770  */
+    { 4, { 0x04, 0x90, 0x77, 0x56 }, AHC_284, FALSE }, /* 284x BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 }, AHC_284, TRUE }   /* 284x BIOS disabled */
   };
 
   /*
@@ -4574,13 +5429,13 @@
       {
         if (AIC7xxx[i].bios_disabled)
         {
-          *bios = AIC_DISABLED;
+          *flags |= AHC_USEDEFAULTS;
         }
         else
         {
-          *bios = AIC_ENABLED;
+          *flags |= AHC_BIOS_ENABLED;
         }
-	return (AIC7xxx[i].type);
+        return (AIC7xxx[i].type);
       }
 
       printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
@@ -4588,8 +5443,10 @@
     }
   }
 
-  return (AIC_NONE);
+  return (AHC_NONE);
 }
+#endif /* (__i386__) || (__alpha__) */
+
 
 /*+F*************************************************************************
  * Function:
@@ -4626,11 +5483,11 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0)	\
-  {						\
-    ;  /* Do nothing */				\
-  }						\
-  (void) inb(p->base + SEECTL_2840);
+  while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
+  }                                                \
+  (void) aic_inb(p, SEECTL_2840);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -4643,7 +5500,7 @@
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
     CLOCK_PULSE(p);
 
     /*
@@ -4653,10 +5510,10 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4667,10 +5524,10 @@
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
 
@@ -4683,11 +5540,11 @@
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
-      outb(temp, p->base + SEECTL_2840);
+      seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4704,11 +5561,11 @@
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(CK_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
   }
 
@@ -4755,16 +5612,16 @@
    * is needed.  Reason: after the 7870 chip reset, there
    * should be no contention.
    */
-  outb(SEEMS, p->base + SEECTL);
+  aic_outb(p, SEEMS, SEECTL);
   wait = 1000;  /* 1000 msec = 1 second */
-  while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+  while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
   {
     wait--;
     udelay(1000);  /* 1 msec */
   }
-  if ((inb(p->base + SEECTL) & SEERDY) == 0)
+  if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
-    outb(0, p->base + SEECTL);
+    aic_outb(p, 0, SEECTL);
     return (0);
   }
   return (1);
@@ -4780,7 +5637,7 @@
 static inline void
 release_seeprom(struct aic7xxx_host *p)
 {
-  outb(0, p->base + SEECTL);
+  aic_outb(p, 0, SEECTL);
 }
 
 /*+F*************************************************************************
@@ -4834,8 +5691,8 @@
  *   this case, has no implied timing.
  *-F*************************************************************************/
 static int
-read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
-    unsigned int len, seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset, 
+    unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
 {
   int i = 0, k;
   unsigned char temp;
@@ -4847,9 +5704,9 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + SEECTL) & SEERDY) == 0)	\
-  {						\
-    ;  /* Do nothing */				\
+  while ((aic_inb(p, SEECTL) & SEERDY) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
   }
 
   /*
@@ -4872,7 +5729,7 @@
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
     CLOCK_PULSE(p);
 
     /*
@@ -4882,10 +5739,10 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
     /*
@@ -4896,10 +5753,10 @@
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4912,11 +5769,11 @@
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
-      outb(temp, p->base + SEECTL);
+      scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4934,11 +5791,11 @@
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS | SEECK, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
   }
 
@@ -4961,7 +5818,6 @@
   }
   printk("\n");
 #endif
-
   if (checksum != scarray[len - 1])
   {
     return (0);
@@ -4984,13 +5840,13 @@
   unsigned char brdctl;
 
   brdctl = BRDCS | BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl |= value;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDCS;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
 }
 
 /*+F*************************************************************************
@@ -5003,8 +5859,77 @@
 static inline unsigned char
 read_brdctl(struct aic7xxx_host *p)
 {
-  outb(BRDRW | BRDCS, p->base + BRDCTL);
-  return (inb(p->base + BRDCTL));
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  return (aic_inb(p, BRDCTL));
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic785x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic785x class controller chips
+ *-F*************************************************************************/
+static void
+aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  aic_outb(p, 0, BRDCTL);
+  brdctl = aic_inb(p, BRDCTL);
+  *int_50 = !(brdctl & BRDDAT5);
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = ( aic_inb(p, SPIOCAP) & EEPROM ) != 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic787x class controller chips
+ *
+ * NOTE: This functions assumes the SEEPROM will have already been aquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  /*
+   * First read the status of our cables.  Set the rom bank to
+   * 0 since the bank setting serves as a multiplexor for the
+   * cable detection logic.  BRDDAT5 controls the bank switch.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the two internal connectors.  BRDDAT6
+   * is internal 50, BRDDAT7 is internal 68.  For each, the cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_50 = !(brdctl & BRDDAT6);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = (brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+  
 }
 
 /*+F*************************************************************************
@@ -5019,82 +5944,72 @@
 configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
     unsigned short adapter_control, unsigned char max_targ)
 {
-  unsigned char brdctl_int, brdctl_ext;
   int internal50_present;
   int internal68_present = 0;
   int external_present = 0;
   int eprom_present;
   int high_on;
   int low_on;
-  int old_verbose;
 
   if (acquire_seeprom(p))
   {
     if (adapter_control & CFAUTOTERM)
     {
-      old_verbose = aic7xxx_verbose;
-      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination.  Please "
-                       "verify driver\n");
-      printk(KERN_INFO "         detected settings and use manual termination "
-                       "if necessary.\n"); 
-
+      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination on "
+                       "controller:\n");
+      printk(KERN_INFO "aic7xxx: <%s> at ", board_names[p->board_name_index]);
+      switch(p->type & 0x1ff1)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+          printk("EISA slot %d\n", p->pci_device_fn);
+          break;
+        case AHC_284:
+          printk("VLB slot %d\n", p->pci_device_fn);
+          break;
+        default:
+          printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+            PCI_FUNC(p->pci_device_fn));
+          break;
+      }
+      printk(KERN_INFO "aic7xxx: Please verify driver detected settings are "
+        "correct.\n");
+      printk(KERN_INFO "aic7xxx: If not, then please properly set the device "
+        "termination\n");
+      printk(KERN_INFO "aic7xxx: in the Adaptec SCSI BIOS by hitting CTRL-A "
+        "when prompted\n");
+      printk(KERN_INFO "aic7xxx: during machine bootup.\n");
       /* Configure auto termination. */
-      outb(SEECS | SEEMS, p->base + SEECTL);
-
-      /*
-       * First read the status of our cables.  Set the rom bank to
-       * 0 since the bank setting serves as a multiplexor for the
-       * cable detection logic.  BRDDAT5 controls the bank switch.
-       */
-      write_brdctl(p, 0);
+      aic_outb(p, SEECS | SEEMS, SEECTL);
 
-      /*
-       * Now read the state of the internal connectors.  The
-       * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
-       * set when cables are not present (BRDDAT6 is INT50 and
-       * BRDDAT7 is INT68).
-       */
-      brdctl_int = read_brdctl(p);
-      internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
-      if (max_targ > 8)
+      if ( (p->type & AHC_AIC7860) == AHC_AIC7860 )
       {
-        internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
+        aic785x_cable_detect(p, &internal50_present, &external_present,
+          &eprom_present);
       }
-
-      /*
-       * Set the rom bank to 1 and determine
-       * the other signals.
-       */
-      write_brdctl(p, BRDDAT5);
-
-      /*
-       * Now read the state of the external connectors.  BRDDAT6 is
-       * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
-       * set when the eprom is present.
-       */
-      brdctl_ext = read_brdctl(p);
-      external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
-      eprom_present = brdctl_ext & BRDDAT7;
-      if (aic7xxx_verbose)
-      {
-        if (max_targ > 8)
-        {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
-                 "Ext-68 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 internal68_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        else
-        {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
-               "brdctl_ext=0x%x\n",
-               eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
+      else
+      {
+        aic787x_cable_detect(p, &internal50_present, &internal68_present,
+          &external_present, &eprom_present);
+      }
+      if (max_targ > 8)
+      {
+        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+               "Ext-68 %s)\n",
+               internal50_present ? "YES" : "NO",
+               internal68_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
       }
+      else
+      {
+        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+               internal50_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
+        internal68_present = 0;
+      }
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "aic7xxx: EEPROM %s present.\n",
+             eprom_present ? "is" : "is not");
 
       /*
        * Now set the termination based on what we found.  BRDDAT6
@@ -5108,16 +6023,18 @@
         high_on = TRUE;
       }
 
-      if ((internal50_present + internal68_present + external_present) <= 1)
+      if ( ( (internal50_present ? 1 : 0) +
+             (internal68_present ? 1 : 0) +
+             (external_present   ? 1 : 0) ) <= 1)
       {
         low_on = TRUE;
       }
           
       if (internal50_present && internal68_present && external_present)
       {
-        printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
-               "         Only two connectors on the adapter may be "
-               "used at a time!\n");
+        printk(KERN_INFO "aic7xxx: Illegal cable configuration!!  Only two\n");
+        printk(KERN_INFO "aic7xxx: connectors on the SCSI controller may be "
+               "in use at a time!\n");
       }
 
       if (high_on == TRUE)
@@ -5128,28 +6045,23 @@
       if (low_on == TRUE)
         *sxfrctl1 |= STPWEN;
 
-      if (aic7xxx_verbose)
+      if (max_targ > 8)
       {
-        if (max_targ > 8)
-        {
-          printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-                 low_on ? "ON" : "OFF",
-                 high_on ? "ON" : "OFF");
-        }
-        else
-        {
-          printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
-        }
+        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+              low_on ? "ON" : "OFF", high_on ? "ON" : "OFF");
+      }
+      else
+      {
+        printk(KERN_INFO "aic7xxx: Termination %s\n",
+          low_on ? "Enabled" : "Disabled");
       }
-      aic7xxx_verbose = old_verbose;
     }
     else
     {
       if (adapter_control & CFSTERM)
-      {
         *sxfrctl1 |= STPWEN;
-      }
-      outb(SEEMS | SEECS, p->base + SEECTL);
+
+      aic_outb(p, SEEMS | SEECS, SEECTL);
       /*
        * Configure high byte termination.
        */
@@ -5161,7 +6073,7 @@
       {
         write_brdctl(p, 0);
       }
-      if (aic7xxx_verbose)
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
       {
         printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
                (adapter_control & CFSTERM) ? "ON" : "OFF",
@@ -5184,7 +6096,6 @@
 detect_maxscb(struct aic7xxx_host *p)
 {
   int i;
-  unsigned char max_scbid = 255;
 
   /*
    * It's possible that we've already done this for multichannel
@@ -5196,90 +6107,35 @@
      * We haven't initialized the SCB settings yet.  Walk the SCBs to
      * determince how many there are.
      */
-    outb(0, p->base + FREE_SCBH);
+    aic_outb(p, 0, FREE_SCBH);
 
     for (i = 0; i < AIC7XXX_MAXSCB; i++)
     {
-      outb(i, p->base + SCBPTR);
-      outb(i, p->base + SCB_CONTROL);
-      if (inb(p->base + SCB_CONTROL) != i)
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, i, SCB_CONTROL);
+      if (aic_inb(p, SCB_CONTROL) != i)
         break;
-      outb(0, p->base + SCBPTR);
-      if (inb(p->base + SCB_CONTROL) != 0)
+      aic_outb(p, 0, SCBPTR);
+      if (aic_inb(p, SCB_CONTROL) != 0)
         break;
 
-      outb(i, p->base + SCBPTR);
-      outb(0, p->base + SCB_CONTROL);   /* Clear the control byte. */
-      outb(i + 1, p->base + SCB_NEXT);  /* Set the next pointer. */
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);  /* Make the tag invalid. */
-
-      /* Make the non-tagged targets not busy. */
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
+      aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
     }
 
     /* Make sure the last SCB terminates the free list. */
-    outb(i - 1, p->base + SCBPTR);
-    outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+    aic_outb(p, i - 1, SCBPTR);
+    aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
 
     /* Ensure we clear the first (0) SCBs control byte. */
-    outb(0, p->base + SCBPTR);
-    outb(0, p->base + SCB_CONTROL);
+    aic_outb(p, 0, SCBPTR);
+    aic_outb(p, 0, SCB_CONTROL);
 
     p->scb_data->maxhscbs = i;
   }
 
-  if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
-  {
-    /* Determine the number of valid bits in the FIFOs. */
-    outb(max_scbid, p->base + QINFIFO);
-    max_scbid = inb(p->base + QINFIFO);
-    p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
-  }
-  else
-  {
-    p->scb_data->maxscbs = p->scb_data->maxhscbs;
-  }
-  if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
-  {
-    /*
-     * Disable paging if the QINFIFO doesn't allow more SCBs than
-     * we have in hardware.
-     */
-    p->flags &= ~PAGE_ENABLED;
-  }
-
-  /*
-   * Set the Queue Full Count.  Some cards have more queue space than
-   * SCBs.
-   */
-  switch (p->chip_class)
-  {
-    case AIC_777x:
-      p->qfullcount = 4;
-      p->qcntmask = 0x07;
-      break;
-    case AIC_785x:
-    case AIC_786x:
-      p->qfullcount = 8;
-      p->qcntmask = 0x0f;
-      break;
-    case AIC_787x:
-    case AIC_788x:
-      if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
-      {
-        p->qfullcount = AIC7XXX_MAXSCB;
-        p->qcntmask = 0xFF;
-      }
-      else
-      {
-        p->qfullcount = 16;
-        p->qcntmask = 0x1F;
-      }
-      break;
-  }
 }
 
 /*+F*************************************************************************
@@ -5290,15 +6146,14 @@
  *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
  *-F*************************************************************************/
 static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+  int reset_delay)
 {
-  int i;
-  unsigned char sblkctl, flags = 0;
+  int i, result;
   int max_targets;
   int found = 1;
-  char channel_ids[] = {'A', 'B', 'C'};
   unsigned char target_settings;
-  unsigned char scsi_conf, sxfrctl1;
+  unsigned char term, scsi_conf, sxfrctl1;
   unsigned short ultraenable = 0;
   struct Scsi_Host *host;
 
@@ -5307,78 +6162,12 @@
    */
   request_region(p->base, MAXREG - MINREG, "aic7xxx");
 
-  /*
-   * Read the bus type from the SBLKCTL register. Set the FLAGS
-   * register in the sequencer for twin and wide bus cards.
-   */
-  sblkctl = inb(p->base + SBLKCTL);
-  if (p->flags & PAGE_ENABLED)
-    flags = PAGESCBS;
-
-  switch (sblkctl & SELBUS_MASK)
-  {
-    case SELNARROW:     /* narrow/normal bus */
-      p->scsi_id = inb(p->base + SCSICONF) & 0x07;
-      p->bus_type = AIC_SINGLE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
-      break;
-
-    case SELWIDE:     /* Wide bus */
-      p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
-      p->bus_type = AIC_WIDE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
-      break;
-
-    case SELBUSB:     /* Twin bus */
-      p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
-      p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
-      p->bus_type = AIC_TWIN;
-      printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
-             p->scsi_id, p->scsi_id_b);
-      outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
-      break;
-
-    default:
-      printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
-	     "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
-      outb(0, p->base + SEQ_FLAGS);
-      return (0);
-  }
-
-  /*
-   * Detect SCB parameters and initialize the SCB array.
-   */
-  detect_maxscb(p);
-  printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
-         p->scb_data->maxhscbs, p->scb_data->maxscbs,
-         p->qfullcount, p->qcntmask);
 
   host = p->host;
 
-  host->can_queue = p->scb_data->maxscbs;
-  host->cmd_per_lun = 2;
+  p->scb_data->maxscbs = AIC7XXX_MAXSCB;
+  host->can_queue = AIC7XXX_MAXSCB;
+  host->cmd_per_lun = 3;
   host->sg_tablesize = AIC7XXX_MAX_SG;
   host->select_queue_depths = aic7xxx_select_queue_depth;
   host->this_id = p->scsi_id;
@@ -5386,11 +6175,11 @@
   host->n_io_port = 0xFF;
   host->base = (unsigned char *) p->mbase;
   host->irq = p->irq;
-  if (p->bus_type == AIC_WIDE)
+  if (p->type & AHC_WIDE)
   {
     host->max_id = 16;
   }
-  if (p->bus_type == AIC_TWIN)
+  if (p->type & AHC_TWIN)
   {
     host->max_channel = 1;
   }
@@ -5405,141 +6194,212 @@
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
 
-  for (i = 0; i < NUMBER(p->device_status); i++)
+  for (i = 0; i < NUMBER(p->untagged_scbs); i++)
   {
-    p->device_status[i].commands_sent = 0;
-    p->device_status[i].flags = 0;
-    p->device_status[i].active_cmds = 0;
-    p->device_status[i].last_reset = 0;
-    p->device_status[i].last_queue_full = 0;
-    p->device_status[i].last_queue_full_count = 0;
-    p->device_status[i].max_queue_depth = 2;
-    p->device_status[i].temp_queue_depth = 2;
-    scbq_init(&p->device_status[i].delayed_scbs);
-    init_timer(&p->device_status[i].timer);
-    p->device_status[i].timer.expires = 0;
-    p->device_status[i].timer.data = (unsigned long)p;
-    p->device_status[i].timer.function = (void *)aic7xxx_timer;
+    p->untagged_scbs[i] = SCB_LIST_NULL;
+    p->qinfifo[i] = SCB_LIST_NULL;
+    p->qoutfifo[i] = SCB_LIST_NULL;
+  }
+  /*
+   * We currently have no commands of any type
+   */
+  p->qinfifonext = 0;
+  p->qoutfifonext = 0;
+
+  for (i = 0; i < MAX_TARGETS; i++)
+  {
+    p->dev_commands_sent[i] = 0;
+    p->dev_flags[i] = DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+    p->dev_active_cmds[i] = 0;
+    p->dev_last_reset[i] = 0;
+    p->dev_last_queue_full[i] = 0;
+    p->dev_last_queue_full_count[i] = 0;
+    p->dev_max_queue_depth[i] = 1;
+    p->dev_temp_queue_depth[i] = 1;
+    p->dev_mid_level_queue_depth[i] = 3;
+    scbq_init(&p->delayed_scbs[i]);
+    init_timer(&p->dev_timer[i]);
+    p->dev_timer[i].expires = 0;
+    p->dev_timer[i].data = (unsigned long)p;
+    p->dev_timer[i].function = (void *)aic7xxx_timer;
+    p->syncinfo[i].period = 0;
+    p->syncinfo[i].offset = 0;
+  }
+
+  printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
+    board_names[p->board_name_index]);
+  switch(p->type & 0x1ff1)
+  {
+    case AHC_AIC7770:
+    case AHC_274:
+      printk("EISA slot %d\n", p->pci_device_fn);
+      break;
+    case AHC_284:
+      printk("VLB slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+        PCI_FUNC(p->pci_device_fn));
+      break;
   }
-  if (aic7xxx_boards[p->irq] == NULL)
+  if (p->type & AHC_TWIN)
   {
-    int result;
-    int irq_flags = 0;
+    printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+           p->host_no, p->scsi_id, p->scsi_id_b);
+  }
+  else
+  {
+    char *channel;
 
-#ifdef AIC7XXX_OLD_ISR_TYPE
-    irq_flags = SA_INTERRUPT;
-#endif
-    /*
-     * Warning! This must be done before requesting the irq.  It is
-     * possible for some boards to raise an interrupt as soon as
-     * they are enabled.  So when we request the irq from the Linux
-     * kernel, an interrupt is triggered immediately.  Therefore, we
-     * must ensure the board data is correctly set before the request.
-     */
-    aic7xxx_boards[p->irq] = host;
+    channel = "";
 
-    /*
-     * Register IRQ with the kernel.  Only allow sharing IRQs with
-     * PCI devices.
-     */
-    if (p->chip_class == AIC_777x)
+    if ((p->type & AHC_39x) != 0)
+    {
+      channel = " A";
+
+      if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
+      {
+        channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+    }
+    if (p->type & AHC_WIDE)
     {
-      result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+      printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
     }
     else
     {
-      result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
-                "aic7xxx", NULL));
-      if (result < 0)
-      {
-        irq_flags = (irq_flags & SA_INTERRUPT) ? 0 : SA_INTERRUPT;
-        result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
-                "aic7xxx", NULL));
-      }
+      printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
     }
+    printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
+  }
+  aic_outb(p, 0, SEQ_FLAGS);
+
+  /*
+   * Detect SCB parameters and initialize the SCB array.
+   */
+  detect_maxscb(p);
+  printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
+  printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
+    p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+    p->base, p->irq);
+  printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
+    p->host_no, p->mbase, (unsigned long)p->maddr);
+
+
+
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  if ((p->type & AHC_AIC7770) == AHC_AIC7770)
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+  }
+  else
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+              "aic7xxx", p));
     if (result < 0)
     {
-      printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
-             p->irq);
-      aic7xxx_boards[p->irq] = NULL;
-      return (0);
+      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+              "aic7xxx", p));
     }
   }
-  else
+  if (result < 0)
   {
-    /*
-     * We have found a host adapter sharing an IRQ of a previously
-     * registered host adapter. Add this host adapter's Scsi_Host
-     * to the beginning of the linked list of hosts at the same IRQ.
-     */
-    p->next = aic7xxx_boards[p->irq];
-    aic7xxx_boards[p->irq] = host;
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring.\n",
+           p->host_no, p->irq);
+    return (0);
   }
 
   /*
    * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
    */
-  if (p->bus_type == AIC_TWIN)
+  if (p->type & AHC_TWIN)
   {
     /*
      * The controller is gated to channel B after a chip reset; set
      * bus B values first.
      */
-    outb(p->scsi_id_b, p->base + SCSIID);
-    scsi_conf = inb(p->base + SCSICONF + 1);
-    sxfrctl1 = inb(p->base + SXFRCTL1);
-    outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-         ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
-    if (p->flags & ULTRA_ENABLED)
+    term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0;
+    aic_outb(p, p->scsi_id_b, SCSIID);
+    scsi_conf = aic_inb(p, SCSICONF + 1);
+    sxfrctl1 = aic_inb(p, SXFRCTL1);
+    aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+         ENSTIMER | ACTNEGEN, SXFRCTL1);
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+    if (p->type & AHC_ULTRA)
     {
-      outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+      aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
     }
     else
     {
-      outb(DFON | SPIOEN, p->base + SXFRCTL0);
+      aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    }
+    if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+    {
+      scsi_conf &= ~0x07;
+      scsi_conf |= p->scsi_id_b;
+      aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF + 1);
     }
-
     if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
     {
       /* Reset SCSI bus B. */
-      if (aic7xxx_verbose)
-        printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+      if (aic7xxx_verbose & VERBOSE_PROBE)
+        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
 
       aic7xxx_reset_current_bus(p);
     }
 
     /* Select channel A */
-    outb(SELNARROW, p->base + SBLKCTL);
+    aic_outb(p, SELNARROW, SBLKCTL);
   }
 
-  outb(p->scsi_id, p->base + SCSIID);
-  scsi_conf = inb(p->base + SCSICONF);
-  sxfrctl1 = inb(p->base + SXFRCTL1);
-  outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-       ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
-  if (p->flags & ULTRA_ENABLED)
+  term = ((p->flags & AHC_TERM_ENB_A) != 0) ? STPWEN : 0;
+  aic_outb(p, p->scsi_id, SCSIID);
+  scsi_conf = aic_inb(p, SCSICONF);
+  sxfrctl1 = aic_inb(p, SXFRCTL1);
+  aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+       ENSTIMER | ACTNEGEN, SXFRCTL1);
+  aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+  if (p->type & AHC_ULTRA)
   {
-    outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
   }
   else
   {
-    outb(DFON | SPIOEN, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+  }
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+  {
+    scsi_conf &= ~0x07;
+    scsi_conf |= p->scsi_id;
+    aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF);
   }
 
+
   if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
   {
     /* Reset SCSI bus A. */
-    if (aic7xxx_verbose)
-      printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+    if (aic7xxx_verbose & VERBOSE_PROBE)
+    {  /* In case we are a 3940, 3985, or 7895, print the right channel */
+      char *channel = "";
+      if (p->flags & AHC_MULTI_CHANNEL)
+      {
+        channel = " A";
+        if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+          channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+      printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
+    }
 
     aic7xxx_reset_current_bus(p);
 
     /*
      * Delay for the reset delay.
      */
-    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    if (!reset_delay)
+      aic7xxx_delay(AIC7XXX_RESET_DELAY);
   }
 
   /*
@@ -5554,7 +6414,10 @@
   p->sdtr_pending = 0x0;
   p->needwdtr_copy = 0x0;
   p->wdtr_pending = 0x0;
-  if (p->bus_type == AIC_SINGLE)
+  p->tagenable = 0x0;
+  p->ultraenb = 0x0;
+  p->discenable = 0xffff;
+  if ((p->type & (AHC_TWIN|AHC_WIDE)) == 0)
   {
     max_targets = 8;
   }
@@ -5566,31 +6429,36 @@
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
-  if (p->flags & USE_DEFAULTS)
+  if (p->flags & AHC_USEDEFAULTS)
   {
-    printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
-           "device parameters.\n");
-    p->discenable = 0xFFFF;
+    printk(KERN_INFO "(scsi%d) Host adapter BIOS disabled. Using default SCSI "
+           "device parameters.\n", p->host_no);
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = 0xffff;
+    p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
   }
   else
   {
-    p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
-        inb(p->base + DISC_DSB));
+    p->discenable = ~((aic_inb(p, DISC_DSB + 1) << 8) |
+        aic_inb(p, DISC_DSB));
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = (aic_inb(p, ULTRA_ENB + 1) << 8) | 
+          aic_inb(p, ULTRA_ENB);
   }
 
   for (i = 0; i < max_targets; i++)
   {
-    if (p->flags & USE_DEFAULTS)
+    if (p->flags & AHC_USEDEFAULTS)
     {
       target_settings = 0;  /* 10 or 20 MHz depending on Ultra enable */
       p->needsdtr_copy |= (0x01 << i);
       p->needwdtr_copy |= (0x01 << i);
-      if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+      if (p->type & AHC_ULTRA)
         ultraenable |= (0x01 << i);
     }
     else
     {
-      target_settings = inb(p->base + TARG_SCRATCH + i);
+      target_settings = aic_inb(p, TARG_SCRATCH + i);
       if (target_settings & 0x0F)
       {
         p->needsdtr_copy |= (0x01 << i);
@@ -5608,24 +6476,33 @@
          */
         target_settings &= 0x7F;
       }
-      if (p->flags & ULTRA_ENABLED)
+    }
+
+    aic_outb(p, target_settings, TARG_SCRATCH + i);
+    if (p->needsdtr_copy & (0x01 << i))
+    {
+      short sxfr, j;
+
+      sxfr = target_settings & SXFR;
+      if ((p->ultraenb & (1 << i)) != 0)
+      {
+        /* Want an ultra speed in the table */
+        sxfr |= 0x100;
+      }
+      for (j = 0; j < NUMBER(aic7xxx_syncrates); j++)
       {
-        switch (target_settings & 0x70)
-        {
-          case 0x00:
-          case 0x10:
-          case 0x20:
-            ultraenable |= (0x01 << i);
-            break;
-          case 0x40:  /* treat 10MHz as 10MHz without Ultra enabled */
-            target_settings &= ~(0x70);
-            break;
-          default:
-            break;
-        }
+        if (sxfr == aic7xxx_syncrates[j].rate)
+          break;
       }
+      p->syncinfo[i].period = aic7xxx_syncrates[j].period;
+      p->syncinfo[i].offset =
+       (p->type & AHC_WIDE) ? MAX_OFFSET_16BIT : MAX_OFFSET_8BIT;
+    }
+    else
+    {
+      p->syncinfo[i].period = 0;
+      p->syncinfo[i].offset = 0;
     }
-    outb(target_settings, p->base + TARG_SCRATCH + i);
   }
 
   /*
@@ -5633,26 +6510,14 @@
    * work on some cards that don't leave these fields cleared
    * when BIOS is not installed.
    */
-  if (p->bus_type != AIC_WIDE)
+  if ( !(p->type & AHC_WIDE))
   {
     p->needwdtr_copy = 0;
   }
   p->needsdtr = p->needsdtr_copy;
   p->needwdtr = p->needwdtr_copy;
-  p->orderedtag = 0;
-  outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
-  outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
-
-  /*
-   * Set the number of available hardware SCBs.
-   */
-  outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
-
-  /*
-   * 2s compliment of maximum tag value.
-   */
-  i = p->scb_data->maxscbs;
-  outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
+  aic_outb(p, 0, ULTRA_ENB);
+  aic_outb(p, 0, ULTRA_ENB + 1);
 
   /*
    * Allocate enough hardware scbs to handle the maximum number of
@@ -5670,20 +6535,10 @@
     p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
     if (p->scb_data->hscbs == NULL)
     {
-      printk("aic7xxx: Unable to allocate hardware SCB array; "
-             "failing detection.\n");
+      printk("(scsi%d) Unable to allocate hardware SCB array; "
+             "failing detection.\n", p->host_no);
       release_region(p->base, MAXREG - MINREG);
-      /*
-       * Ensure that we only free the IRQ when there is _not_ another
-       * aic7xxx adapter sharing this IRQ.  The adapters are always
-       * added to the beginning of the list, so we can grab the next
-       * pointer and place it back in the board array.
-       */
-      if (p->next == NULL)
-      {
-        free_irq(p->irq, aic7xxx_isr);
-      }
-      aic7xxx_boards[p->irq] = p->next;
+      free_irq(p->irq, p);
       return(0);
     }
     /* At least the control byte of each SCB needs to be 0. */
@@ -5691,41 +6546,35 @@
 
     /* Tell the sequencer where it can find the hardware SCB array. */
     hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
-    outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
-    outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
-    outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
-    outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
-  }
-
-  /*
-   * QCount mask to deal with broken aic7850s that sporadically get
-   * garbage in the upper bits of their QCNT registers.
-    */
-  outb(p->qcntmask, p->base + QCNTMASK);
+    aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
+
+    /* Set up the fifo areas at the same time */
+    hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+    aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
+
+    /* The Q-FIFOs we just set up are all empty */
+    aic_outb(p, 0, QINPOS);
+    aic_outb(p, 0, KERNEL_QINPOS);
+    aic_outb(p, 0, QOUTPOS);
 
-  /*
-   * Set FIFO depth and command out count.  These are only used when
-   * paging is enabled and should not be touched for AIC-7770 based
-   * adapters; FIFODEPTH and CMDOUTCNT overlay SCSICONF and SCSICONF+1
-   * which are used to control termination.
-   */
-  if (p->flags & PAGE_ENABLED)
-  {
-    outb(p->qfullcount, p->base + FIFODEPTH);
-    outb(0, p->base + CMDOUTCNT);
-    p->cmdoutcnt = 0;
   }
 
   /*
    * We don't have any waiting selections or disconnected SCBs.
    */
-  outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
-  outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+  aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+  aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
 
   /*
    * Message out buffer starts empty
    */
-  outb(0, p->base + MSG_LEN);
+  aic_outb(p, MSG_NOOP, MSG_OUT);
 
   /*
    * Load the sequencer program, then re-enable the board -
@@ -5736,12 +6585,18 @@
    */
   aic7xxx_loadseq(p);
 
-  if (p->chip_class == AIC_777x)
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
   {
-    outb(ENABLE, p->base + BCTL);  /* Enable the boards BUS drivers. */
+    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
   }
 
   /*
+   * Link us into the list of valid hosts
+   */
+  p->next = first_aic7xxx;
+  first_aic7xxx = p;
+
+  /*
    * Unpause the sequencer before returning and enable
    * interrupts - we shouldn't get any until the first
    * command is sent to us by the high-level SCSI code.
@@ -5759,38 +6614,56 @@
  *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
  *   is paused upon return.
  *-F*************************************************************************/
-static void
+int
 aic7xxx_chip_reset(struct aic7xxx_host *p)
 {
   unsigned char hcntrl;
   int wait;
 
   /* Retain the IRQ type across the chip reset. */
-  hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+  hcntrl = (aic_inb(p, HCNTRL) & IRQMS) | INTEN;
 
   /*
    * For some 274x boards, we must clear the CHIPRST bit and pause
    * the sequencer. For some reason, this makes the driver work.
    */
-  outb(PAUSE | CHIPRST, p->base + HCNTRL);
+  aic_outb(p, PAUSE | CHIPRST, HCNTRL);
 
   /*
    * In the future, we may call this function as a last resort for
    * error handling.  Let's be nice and not do any unecessary delays.
    */
   wait = 1000;  /* 1 second (1000 * 1000 usec) */
-  while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+  while ((wait > 0) && ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0))
   {
     udelay(1000);  /* 1 msec = 1000 usec */
     wait = wait - 1;
   }
 
-  if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+  if ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0)
   {
     printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
   }
 
-  outb(hcntrl | PAUSE, p->base + HCNTRL);
+  aic_outb(p, hcntrl | PAUSE, HCNTRL);
+
+  switch( aic_inb(p, SBLKCTL) & 0x0a )
+  {
+    case 0:  /* normal narrow card */
+      break;
+    case 2:  /* Wide card */
+      p->type |= AHC_WIDE;
+      break;
+    case 8:  /* Twin card */
+      p->type |= AHC_TWIN;
+      p->flags |= AHC_MULTI_CHANNEL;
+      break;
+    default: /* hmmm...we don't know what this is */
+      printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
+        aic_inb(p, SBLKCTL) & 0x0a);
+      return(-1);
+  }
+  return(0);
 }
 
 /*+F*************************************************************************
@@ -5802,8 +6675,7 @@
  *   and a pointer to a aic7xxx_host struct upon success.
  *-F*************************************************************************/
 static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
-    aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
 {
   struct aic7xxx_host *p = NULL;
   struct Scsi_Host *host;
@@ -5820,46 +6692,45 @@
     memset(p, 0, sizeof(struct aic7xxx_host));
     p->host = host;
 
-    if (scb_data != NULL)
+    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (p->scb_data != NULL)
     {
-      /*
-       * We are sharing SCB data areas; use the SCB data pointer
-       * provided.
-       */
-      p->scb_data = scb_data;
-      p->flags |= SHARED_SCBDATA;
+      memset(p->scb_data, 0, sizeof(scb_data_type));
+      scbq_init (&p->scb_data->free_scbs);
     }
     else
     {
       /*
-       * We are not sharing SCB data; allocate one.
+       * For some reason we don't have enough memory.  Free the
+       * allocated memory for the aic7xxx_host struct, and return NULL.
        */
-      p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
-      if (p->scb_data != NULL)
-      {
-        memset(p->scb_data, 0, sizeof(scb_data_type));
-        scbq_init (&p->scb_data->free_scbs);
-      }
-      else
-      {
-        /*
-         * For some reason we don't have enough memory.  Free the
-         * allocated memory for the aic7xxx_host struct, and return NULL.
-         */
-        scsi_unregister(host);
-        p = NULL;
-      }
+      scsi_unregister(host);
+      p = NULL;
     }
     if (p != NULL)
     {
       p->host_no = host->host_no;
-      p->base = base;
-      p->mbase = mbase;
-      p->maddr = NULL;
-      p->flags = flags;
-      p->chip_type = chip_type;
-      p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
-      p->pause = p->unpause | PAUSE;
+      p->base = temp->base;
+      p->mbase = temp->mbase;
+      p->maddr = temp->maddr;
+      p->flags = temp->flags;
+      p->type = temp->type;
+      p->unpause = temp->unpause;
+      p->pause = temp->pause;
+      p->pci_bus = temp->pci_bus;
+      p->pci_device_fn = temp->pci_device_fn;
+      p->bios_address = temp->bios_address;
+      p->irq = temp->irq;
+      p->scsi_id = temp->scsi_id;
+      p->scsi_id_b = temp->scsi_id_b;
+      p->discenable = temp->discenable;
+      p->ultraenb = temp->ultraenb;
+      p->tagenable = 0;
+      p->orderedtag = 0;
+      p->board_name_index = temp->board_name_index;
+      p->adapter_control = temp->adapter_control;
+      p->bios_control = temp->bios_control;
+      DRIVER_LOCK_INIT
     }
   }
   return (p);
@@ -5874,48 +6745,47 @@
  *   the driver (struct aic7xxx_host *).
  *-F*************************************************************************/
 static void
-aic7xxx_free (struct aic7xxx_host *p)
+aic7xxx_free(struct aic7xxx_host *p)
 {
-  int i;
+  int i, jump;
 
   /*
-   * We should be careful in freeing the scb_data area.  For those
-   * adapters sharing external SCB RAM(398x), there will be only one
-   * scb_data area allocated.  The flag SHARED_SCBDATA indicates if
-   * one adapter is sharing anothers SCB RAM.
+   * Free the allocated hardware SCB space.
    */
-  if (!(p->flags & SHARED_SCBDATA))
+  if (p->scb_data->hscbs != NULL)
   {
-    /*
-     * Free the allocated hardware SCB space.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-    /*
-     * Free the driver SCBs.  These were allocated on an as-need
-     * basis.
-     */
-    for (i = 0; i < p->scb_data->numscbs; i++)
-    {
-      kfree(p->scb_data->scb_array[i]);
-    }
-    /*
-     * Free the hardware SCBs.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-
-    /*
-     * Free the SCB data area.
-     */
-    kfree(p->scb_data);
+    kfree(p->scb_data->hscbs);
+  }
+  /*
+   * Free the driver SCBs.  These were allocated on an as-need
+   * basis. However, we allocated them 30 at a time up until the
+   * very last allocation (if there was one).  So, we need to free
+   * every 30th pointer to free the array (this also frees the
+   * SG_array structs as well).
+   *
+   * Note, on 64 bit machines we allocate 29 at a time instead.
+   */
+  jump = (sizeof(int) == sizeof(void *)) ? 30 : 29;
+  for (i = 0; i < p->scb_data->numscbs; i += jump)
+  {
+    kfree(p->scb_data->scb_array[i]);
   }
   /*
-   * Free the instance of the device structure.
+   * Free the SCB data area.
+   */
+  kfree(p->scb_data);
+
+  /*
+   * Free the instance of the device structure.
+   */
+
+  /*
+   * XXXXXXXX  FIXXXXXMEEEEEE.  How do we unmap the I/O range we have mapped
+   * if we are doing MMAPed I/O ??????????  Our biggest concern is the issue
+   * of possibly calling unmap on an area that *might* be used on another
+   * controller as well (aka, the 4096 byte MMAPed area is back to back
+   * with another controller, and the PAGE_SIZE is greater then 4096, allowing
+   * us to remap in a shared page).
    */
   scsi_unregister(p->host);
 }
@@ -5937,46 +6807,42 @@
   unsigned short scarray[128];
   struct seeprom_config *sc = (struct seeprom_config *) scarray;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
     printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
   }
-  switch (p->chip_type)
+  switch (p->type & 0x00001ff1)
   {
-    case AIC_7770:  /* None of these adapters have seeproms. */
-    case AIC_7771:
-    case AIC_7855:
+    case AHC_AIC7770:  /* None of these adapters have seeproms. */
+    case AHC_274:
       break;
 
-    case AIC_284x:
+    case AHC_284:
       have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
       break;
 
-    case AIC_7850:  /* The 2910B is a 7850 with a seeprom. */
-    case AIC_7861:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7874:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7884:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+    case AHC_AIC7850:  /* The 2910B is a 7850 with a seeprom. */
+    case AHC_294AU:
+    case AHC_AIC7870:  /* For these controllers we try the three possible */
+    case AHC_AIC7895:  /* SEEPROM read types.  If none works, then we are */
+    case AHC_294:      /* SOL.  This should catch any SEEPROM variety     */
+    case AHC_394:      /* Adaptec or some motherboard manufacturer might  */
+    case AHC_294U:     /* throw at us, and since we perform a checksum    */
+    case AHC_394U:     /* during the read, we should get bogus seeprom    */
+    case AHC_AIC7860:  /* reads. */
+    case AHC_AIC7880:
+    case AHC_398:
+    case AHC_398U:
+      have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   scarray, sizeof(*sc)/2, C46);
-      break;
-
-    case AIC_7860:  /* Motherboard Ultra controllers might have RAID port. */
-    case AIC_7880:
-      have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
       if (!have_seeprom)
-      {
-        have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
-      }
-      break;
-
-    case AIC_7873:  /* The 3985 adapters use the 93c56 serial EEPROM. */
-    case AIC_7883:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(scarray)/2, C46);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(*sc)/2, C56_66);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   scarray, sizeof(scarray)/2, C56_66);
       break;
 
@@ -5986,19 +6852,19 @@
 
   if (!have_seeprom)
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("\naic7xxx: No SEEPROM available; using defaults.\n");
     }
-    p->flags |= USE_DEFAULTS;
+    p->flags |= AHC_USEDEFAULTS;
+    p->flags &= ~AHC_BIOS_ENABLED;
   }
   else
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("done\n");
     }
-    p->flags |= HAVE_SEEPROM;
 
     /*
      * Update the settings in sxfrctl1 to match the termination settings.
@@ -6009,14 +6875,17 @@
      * First process the settings that are different between the VLB
      * and PCI adapter seeproms.
      */
-    if (p->chip_class == AIC_777x)
+    if (p->type & AHC_284)
     {
       /* VLB adapter seeproms */
       if (sc->bios_control & CF284XEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CF284XSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
       /*
        * The 284x SEEPROM doesn't have a max targets field.  We
        * set it to 16 to make sure we take care of the 284x-wide
@@ -6034,30 +6903,90 @@
     {
       /* PCI adapter seeproms */
       if (sc->bios_control & CFEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CFSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
 
       /* Limit to 16 targets just in case. */
       max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
     }
 
+    p->discenable = 0;
+
+    for (i = 0; i < max_targets; i++)
+    {
+      if( (p->type & AHC_ULTRA) &&
+         !(sc->adapter_control & CFULTRAEN) &&
+          (sc->device_flags[i] & CFSYNCHISULTRA) )
+      {
+        p->flags |= AHC_NEWEEPROM_FMT;
+        break;
+      }
+    }
+
     for (i = 0; i < max_targets; i++)
     {
       target_settings = (sc->device_flags[i] & CFXFER) << 4;
       if (sc->device_flags[i] & CFSYNCH)
+      {
         target_settings |= SOFS;
+      }
       if (sc->device_flags[i] & CFWIDEB)
+      {
         target_settings |= WIDEXFER;
+      }
       if (sc->device_flags[i] & CFDISC)
+      {
         p->discenable |= (0x01 << i);
-      outb(target_settings, p->base + TARG_SCRATCH + i);
+      }
+      if (p->flags & AHC_NEWEEPROM_FMT)
+      {
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= (0x01 << i);
+        }
+      }
+      else if (sc->adapter_control & CFULTRAEN)
+      {
+        p->ultraenb |= (0x01 << i);
+      }
+      if ( ((target_settings & 0x70) == 0x40) &&
+           (p->ultraenb & (0x01 << i)) )
+      {
+        target_settings &= ~0x70;
+        p->ultraenb &= ~(0x01 << i);
+      }
+      aic_outb(p, target_settings, TARG_SCRATCH + i);
     }
-    outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
-    outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
+    aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+    aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+    aic_outb(p,  (p->ultraenb & 0xFF), ULTRA_ENB);
+    aic_outb(p,  ((p->ultraenb >> 8) & 0xFF), ULTRA_ENB + 1);
 
     p->scsi_id = sc->brtime_id & CFSCSIID;
+    p->adapter_control = sc->adapter_control;
+    p->bios_control = sc->bios_control;
+
+    if (p->bios_control & CFBIOSEN)
+    {
+      p->flags &= ~AHC_USEDEFAULTS;
+      p->flags |= AHC_BIOS_ENABLED;
+    }
+    else
+    {
+      p->flags &= ~AHC_BIOS_ENABLED;
+      p->flags |= AHC_USEDEFAULTS;
+    }
+
+    if ((p->type & 0x1ff1) == AHC_AIC7895)
+    {
+      if (p->adapter_control & CFBPRIMARY)
+        p->flags |= AHC_CHANNEL_B_PRIMARY;
+    }
 
     scsi_conf = (p->scsi_id & 0x7);
     if (sc->adapter_control & CFSPARITY)
@@ -6066,37 +6995,39 @@
      * The 7850 controllers with a seeprom, do not honor the CFRESETB
      * flag in the seeprom.  Assume that we want to reset the SCSI bus.
      */
-    if ((sc->adapter_control & CFRESETB) || (p->chip_class == AIC_7850))
+    if (sc->adapter_control & CFRESETB)
       scsi_conf |= RESET_SCSI;
-
-    if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
-    {
-      /*
-       * We allow the operator to override ultra enable through
-       * the boot prompt.
-       */
-      if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
-      {
-        /* Treat us as a non-ultra card */
-        p->flags &= ~ULTRA_ENABLED;
-      }
-    }
+    /*
+     * We may be a 2842, if so, preserve the TERM_ENB bit in scsi conf
+     */
+    if ( (p->flags & AHC_TERM_ENB_A) && 
+        ((p->type & AHC_AIC7770) == AHC_AIC7770) )
+      scsi_conf |= TERM_ENB;
+    /*
+     * If this is an Ultra card, is Ultra mode enabled?  If not, disable
+     * it in the host struct as well
+     */
+    if ( (p->type & AHC_ULTRA) && 
+        !(sc->adapter_control & CFULTRAEN) &&
+        !(p->flags & AHC_NEWEEPROM_FMT) )
+      p->type &= ~AHC_ULTRA;
 
     /* Set the host ID */
-    outb(scsi_conf, p->base + SCSICONF);
+    aic_outb(p, scsi_conf, SCSICONF);
     /* In case we are a wide card */
-    outb(p->scsi_id, p->base + SCSICONF + 1);
+    aic_outb(p, p->scsi_id, SCSICONF + 1);
 
-    if (p->chip_class != AIC_777x)
+    if ((p->type & AHC_AIC7860) == AHC_AIC7860)
     {
+      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
       /*
        * Update the settings in sxfrctl1 to match the termination
        * settings.
        */
-      *sxfrctl1 = 0;
-      configure_termination(p, sxfrctl1, sc->adapter_control,
-        (unsigned char) sc->max_targets & CFMAXTARG);
+        configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
     }
+    else if (have_seeprom && ((p->type & AHC_AIC7770) != AHC_AIC7770))
+      configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
   }
   return (have_seeprom);
 }
@@ -6116,41 +7047,40 @@
 int
 aic7xxx_detect(Scsi_Host_Template *template)
 {
+  struct aic7xxx_host *temp_p = NULL;
+  struct aic7xxx_host *current_p = NULL;
+  struct aic7xxx_host *list_p = NULL;
   int found = 0;
-  aha_status_type adapter_bios;
-  aha_chip_class_type chip_class;
-  aha_chip_type chip_type;
-  int slot, base;
-  int chan_num = 0;
-  unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
-  int i;
-  struct aic7xxx_host *p;
+  ahc_flag_type flags = 0;
+  ahc_type type;
+  unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+  unsigned char hcntrl, hostconf;
+  unsigned int slot, base;
+#endif
 
+#ifdef MODULE
   /*
-   * Since we may allow sharing of IRQs, it is imperative
-   * that we "null-out" the aic7xxx_boards array. It is
-   * not guaranteed to be initialized to 0 (NULL). We use
-   * a NULL entry to indicate that no prior hosts have
-   * been found/registered for that IRQ.
+   * If we are called as a module, the aic7xxx pointer may not be null
+   * and it would point to our bootup string, just like on the lilo
+   * command line.  IF not NULL, then process this config string with
+   * aic7xxx_setup
    */
-  for (i = 0; i < NUMBER(aic7xxx_boards); i++)
-  {
-    aic7xxx_boards[i] = NULL;
-  }
+  if(aic7xxx)
+    aic7xxx_setup(aic7xxx, NULL);
+
+#endif
 
   template->proc_dir = &proc_scsi_aic7xxx;
-  template->name = aic7xxx_info(NULL);
   template->sg_tablesize = AIC7XXX_MAX_SG;
 
-  /*
-   * Initialize the spurious count to 0.
-   */
-  aic7xxx_spurious_count = 0;
 
+#if defined(__i386__) || defined(__alpha__)
   /*
    * EISA/VL-bus card signature probe.
    */
-  for (slot = MINSLOT; slot <= MAXSLOT; slot++)
+  slot = MINSLOT;
+  while (slot <= MAXSLOT)
   {
     base = SLOTBASE(slot) + MINREG;
 
@@ -6160,185 +7090,256 @@
        * Some other driver has staked a
        * claim to this i/o region already.
        */
-      continue;
+      slot++;
+      continue; /* back to the beginning of the for loop */
     }
-
-    chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
-    if (chip_type != AIC_NONE)
+    flags = 0;
+    type = aic7xxx_probe(slot, base + HID0, &flags);
+    switch (type)
     {
-
-      switch (chip_type)
-      {
-        case AIC_7770:
-        case AIC_7771:
+      case AHC_AIC7770:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at EISA %d\n",
-                 board_names[chip_type], slot);
-          break;
-        case AIC_284x:
+               board_names[2], slot);
+        break;
+      case AHC_274:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at EISA %d\n",
+               board_names[3], slot);
+        break;
+      case AHC_284:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at VLB %d\n",
-                 board_names[chip_type], slot);
-          break;
-        default:
-          break;
-      }
+               board_names[4], slot);
+        break;
+      default:
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
+    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+    if (temp_p == NULL)
+    {
+      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+      slot++;
+      continue; /* back to the beginning of the while loop */
+    }
+    /*
+     * Pause the card preserving the IRQ type.  Allow the operator
+     * to override the IRQ trigger.
+     */
+    if (aic7xxx_irq_trigger == 1)
+      hcntrl = IRQMS;  /* Level */
+    else if (aic7xxx_irq_trigger == 0)
+      hcntrl = 0;  /* Edge */
+    else
+      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
+    memset(temp_p, 0, sizeof(struct aic7xxx_host));
+    temp_p->unpause = hcntrl | INTEN;
+    temp_p->pause = hcntrl | PAUSE | INTEN;
+    temp_p->base = base;
+    temp_p->type = type;
+    temp_p->flags = flags | AHC_PAGESCBS;
+    temp_p->mbase = 0;
+    temp_p->maddr = 0;
+    temp_p->pci_bus = 0;
+    temp_p->pci_device_fn = slot;
+    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+    if (aic7xxx_chip_reset(temp_p) == -1)
+      temp_p->irq = 0;
+    else
+      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+    switch (temp_p->irq)
+    {
+      case 9:
+      case 10:
+      case 11:
+      case 12:
+      case 14:
+      case 15:
+        break;
 
-      /*
-       * We found a card, allow 1 spurious interrupt.
-       */
-      aic7xxx_spurious_count = 1;
+      default:
+        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level %d, ignoring.\n", temp_p->irq);
+        kfree(temp_p);
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
 
-      /*
-       * Pause the card preserving the IRQ type.  Allow the operator
-       * to override the IRQ trigger.
-       */
-      if (aic7xxx_irq_trigger == 1)
-        hcntrl = IRQMS;  /* Level */
-      else if (aic7xxx_irq_trigger == 0)
-        hcntrl = 0;  /* Edge */
-      else
-        hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
-      outb(hcntrl | PAUSE, base + HCNTRL);
-      p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
-      if (p == NULL)
-      {
-        printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-        continue;
-      }
-      aic7xxx_chip_reset(p);
+    /*
+     * We are commited now, everything has been checked and this card
+     * has been found, now we just set it up
+     */
+    /*
+     * Insert our new struct into the list at the end
+     */
+    if (list_p == NULL)
+    {
+      list_p = current_p = temp_p;
+    }
+    else
+    {
+      current_p = list_p;
+      while (current_p->next != NULL)
+        current_p = current_p->next;
+      current_p->next = temp_p;
+    }
+    if (aic7xxx_extended)
+    {
+      temp_p->flags |= AHC_EXTEND_TRANS_A;
+      if (temp_p->flags & AHC_MULTI_CHANNEL)
+        temp_p->flags |= AHC_EXTEND_TRANS_B;
+    }
 
-      irq = inb(INTDEF + base) & 0x0F;
-      switch (irq)
+    switch (temp_p->type & 0x1ff1)
+    {
+      case AHC_AIC7770:
+        temp_p->board_name_index = 2;
+      case AHC_274:
       {
-        case 9:
-        case 10:
-        case 11:
-        case 12:
-        case 14:
-        case 15:
-          break;
-
-        default:
-          printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
-          "level %d, ignoring.\n", irq);
-          irq = 0;
-          aic7xxx_free(p);
-          break;
-      }
+        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
 
-      if (irq != 0)
-      {
-        p->irq = irq & 0x0F;
-        p->chip_class = AIC_777x;
-#ifdef AIC7XXX_PAGE_ENABLE
-        p->flags |= PAGE_ENABLED;
-#endif
-        p->instance = found;
-        if (aic7xxx_extended)
+        /*
+         * Get the primary channel information.  Right now we don't
+         * do anything with this, but someday we will be able to inform
+         * the mid-level SCSI code which channel is primary.
+         */
+        if (temp_p->board_name_index == 0)
+          temp_p->board_name_index = 3;
+        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
         {
-          p->flags |= EXTENDED_TRANSLATION;
+          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
         }
 
-        switch (p->chip_type)
+        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+        {
+          temp_p->flags |= AHC_USEDEFAULTS;
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        }
+        else
         {
-          case AIC_7770:
-          case AIC_7771:
+          temp_p->flags &= ~AHC_USEDEFAULTS;
+          temp_p->flags |= AHC_BIOS_ENABLED;
+          if ( (temp_p->bios_control & 0x20) == 0 )
           {
-            unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
-
-            /*
-             * Get the primary channel information.  Right now we don't
-             * do anything with this, but someday we will be able to inform
-             * the mid-level SCSI code which channel is primary.
-             */
-            if (biosctrl & CHANNEL_B_PRIMARY)
-            {
-              p->flags |= FLAGS_CHANNEL_B_PRIMARY;
-            }
-
-            if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+            switch(temp_p->bios_control & 0x07)
             {
-              p->flags |= USE_DEFAULTS;
+              case 0x0:
+                temp_p->bios_address = 0xcc000;
+                break;
+              case 0x1:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd4000;
+                break;
+              case 0x3:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xdc000;
+                break;
+              case 0x5:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe4000;
+                break;
+              case 0x7:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
           }
-
-          case AIC_284x:
-            if (!load_seeprom(p, &sxfrctl1))
+          else
+          {
+            switch(temp_p->bios_control & 0x06)
             {
-              if (aic7xxx_verbose)
-                printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+              case 0x0:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
-
-          default:  /* Won't get here. */
-            break;
+          }
         }
-        printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
-               (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
-               (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
-        /*
-         * Check for Rev C or E boards. Rev E boards can supposedly have
-         * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
-         * It's still not clear extactly what is different about the Rev E
-         * boards, but we think it allows 8 bit entries in the QOUTFIFO to
-         * support "paging" SCBs (more than 4 commands can be active at once).
-         *
-         * The Rev E boards have a read/write autoflush bit in the
-         * SBLKCTL register, while in the Rev C boards it is read only.
-         */
-        sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
-        outb(sblkctl, p->base + SBLKCTL);
-        if (inb(p->base + SBLKCTL) == sblkctl)
+        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+        if (temp_p->flags & AHC_USEDEFAULTS)
         {
-          /*
-           * We detected a Rev E board, we allow paging on this board.
-           */
-          printk("Revision >= E\n");
-          outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+          temp_p->scsi_id = temp_p->scsi_id_b = 7;
+          temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
         }
         else
         {
-          /* Do not allow paging. */
-          p->flags &= ~PAGE_ENABLED;
-          printk("Revision <= C\n");
+          if ( ((temp_p->adapter_control >> 8) & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_A;
+          if ( (temp_p->adapter_control & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_B;
+          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
         }
+        break;
+      }
 
-        if (aic7xxx_verbose)
-          printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-                 (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-
-        /*
-         * Set the FIFO threshold and the bus off time.
-         */
-        hostconf = inb(p->base + HOSTCONF);
-        outb(hostconf & DFTHRSH, p->base + BUSSPD);
-        outb((hostconf << 2) & BOFF, p->base + BUSTIME);
-
-        /*
-         * Try to initialize the card and register it with the kernel.
-         */
-        if (aic7xxx_register(template, p))
+      case AHC_284:
+        load_seeprom(temp_p, &sxfrctl1);
+        temp_p->board_name_index = 4;
+        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
         {
-          /*
-           * We successfully found a board and registered it.
-           */
-          found = found + 1;
-        }
-        else
-        {
-          /*
-           * Something went wrong; release and free all resources.
-           */
-          aic7xxx_free(p);
+          case 0x00:
+            temp_p->bios_address = 0xe0000;
+            break;
+          case 0x20:
+            temp_p->bios_address = 0xc8000;
+            break;
+          case 0x40:
+            temp_p->bios_address = 0xd0000;
+            break;
+          case 0x60:
+            temp_p->bios_address = 0xd8000;
+            break;
+          default:
+            break; /* can't get here */
         }
-      }
-      /*
-       * Disallow spurious interrupts.
-       */
-      aic7xxx_spurious_count = 0;
+        break;
+
+      default:  /* Won't get here. */
+        break;
+    }
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+        temp_p->irq,
+        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
     }
+
+    /*
+     * Set the FIFO threshold and the bus off time.
+     */
+    hostconf = aic_inb(temp_p, HOSTCONF);
+    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+    slot++;
+    found++;
   }
 
+#endif /* defined(__i386__) || defined(__alpha__) */
+
 #ifdef CONFIG_PCI
   /*
    * PCI-bus probe.
@@ -6349,180 +7350,312 @@
     {
       unsigned short      vendor_id;
       unsigned short      device_id;
-      aha_chip_type       chip_type;
-      aha_chip_class_type chip_class;
+      ahc_type            type;
+      ahc_flag_type       flags;
+      int                 board_name_index;
     } const aic7xxx_pci_devices[] = {
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AIC_7873, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AIC_7874, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AIC_7880, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AIC_7881, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AIC_7882, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AIC_7883, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
+       AHC_FNONE,                                            1 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       5 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       6 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  7 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_294AU,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  8 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                      9 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     10 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_394,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     11 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_398,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     12 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     13 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     14 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     15 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_394U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     16 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_398U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     17 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     18 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 19 }
     };
 
-    int error, flags;
-    int done = 0;
-    unsigned int iobase, mbase;
-    unsigned short index = 0;
-    unsigned char pci_bus, pci_device_fn;
-    unsigned char ultra_enb = 0;
-    unsigned int  devconfig, class_revid;
-    scb_data_type *shared_scb_data = NULL;
-    char rev_id[] = {'B', 'C', 'D'};
+    unsigned short command;
+    unsigned int  devconfig, i;
+#ifdef MMAPIO
+    unsigned long page_offset, base;
+#endif
+    struct aic7xxx_host *first_7895 = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+    struct pci_dev *pdev = NULL;
+#else
+    int index;
+    unsigned int piobase, mmapbase;
+    unsigned char pci_bus, pci_devfn, pci_irq;
+#endif
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
     {
-      done = FALSE;
-      while (!done)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+      pdev = NULL;
+      while ((pdev = pci_find_device(aic7xxx_pci_devices[i].vendor_id,
+                                     aic7xxx_pci_devices[i].device_id,
+                                     pdev)))
+#else
+      index = 0;
+      while (!(pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
+                                   aic7xxx_pci_devices[i].device_id,
+                                   index++, &pci_bus, &pci_devfn)) )
+#endif
       {
-        if (pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
-                                aic7xxx_pci_devices[i].device_id,
-                                index, &pci_bus, &pci_device_fn))
-        {
-          index = 0;
-          done = TRUE;
-        }
-        else  /* Found an Adaptec PCI device. */
-        {
-          chip_class = aic7xxx_pci_devices[i].chip_class;
-          chip_type = aic7xxx_pci_devices[i].chip_type;
-          chan_num = 0;
-          flags = 0;
-          switch (aic7xxx_pci_devices[i].chip_type)
+        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
+        {
+          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
           {
-            case AIC_7855:
-              flags |= USE_DEFAULTS;
-              break;
-
-            case AIC_7872:  /* 3940 */
-            case AIC_7882:  /* 3940-Ultra */
-              flags |= MULTI_CHANNEL;
-              chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
-              number_of_3940s++;
-              break;
-
-            case AIC_7873:  /* 3985 */
-            case AIC_7883:  /* 3985-Ultra */
-              chan_num = number_of_3985s;  /* Has 3 controllers */
-              flags |= MULTI_CHANNEL;
-              number_of_3985s++;
-              if (number_of_3985s == 3)
-              {
-                number_of_3985s = 0;
-                shared_scb_data = NULL;
-              }
-              break;
-
-            default:
-              break;
+            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
+              "supported by\n");
+            printk(KERN_INFO "         this driver, we are ignoring it.\n");
           }
+        }
+        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+                                    GFP_ATOMIC)) != NULL )
+        {
+          memset(temp_p, 0, sizeof(struct aic7xxx_host));
+          temp_p->type = aic7xxx_pci_devices[i].type;
+          temp_p->flags = aic7xxx_pci_devices[i].flags;
+          temp_p->board_name_index = aic7xxx_pci_devices[i].board_name_index;
 
           /*
            * Read sundry information from PCI BIOS.
            */
-          error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                            PCI_BASE_ADDRESS_0, &iobase);
-          error += pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                            PCI_INTERRUPT_LINE, &irq);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                            PCI_BASE_ADDRESS_1, &mbase);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             DEVCONFIG, &devconfig);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             CLASS_PROGIF_REVID, &class_revid);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+          temp_p->irq = pdev->irq;
+          temp_p->pci_bus = pdev->bus->number;
+          temp_p->pci_device_fn = pdev->devfn;
+          temp_p->base = pdev->base_address[0];
+          temp_p->mbase = pdev->base_address[1];
+          pci_read_config_word(pdev, PCI_COMMAND, &command);
+          pci_write_config_word(pdev, PCI_COMMAND,
+             command | PCI_COMMAND_MASTER |
+             PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+#else
+          temp_p->pci_bus = pci_bus;
+          temp_p->pci_device_fn = pci_devfn;
+          pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+            &pci_irq);
+          temp_p->irq = pci_irq;
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+            &piobase);
+          temp_p->base = piobase;
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1,
+            &mmapbase);
+          temp_p->mbase = mmapbase;
+          pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+          pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+            command | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
+            PCI_COMMAND_IO);
+#endif
 
-          printk("aic7xxx: <%s> at PCI %d\n",
-                 board_names[chip_type], PCI_SLOT(pci_device_fn));
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic7xxx_pci_devices[i].board_name_index],
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
 
           /*
            * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
            * we mask it off.
            */
-          iobase &= PCI_BASE_ADDRESS_IO_MASK;
-
-          p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
-                            shared_scb_data);
-
-          if (p == NULL)
+          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
+          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+          temp_p->unpause = (aic_inb(temp_p, HCNTRL) & IRQMS) | INTEN;
+          temp_p->pause = temp_p->unpause | PAUSE;
+
+#ifdef MMAPIO
+          base = temp_p->mbase & PAGE_MASK;
+          page_offset = temp_p->mbase - base;
+          /*
+           * replace the next line with this one if you are using 2.1.x:
+           * temp_p->maddr = ioremap(base, page_offset + 256);
+           */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+          temp_p->maddr = ioremap(base, page_offset + 256);
+#else
+          temp_p->maddr = vremap(base, page_offset + 256);
+#endif
+          if(temp_p->maddr)
           {
-            printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-            continue;
+            temp_p->maddr += page_offset;
           }
-
-          /* Remember to set the channel number, irq, and chip class. */
-          p->chan_num = chan_num;
-          p->irq = irq;
-          p->chip_class = chip_class;
-#ifdef AIC7XXX_PAGE_ENABLE
-          p->flags |= PAGE_ENABLED;
 #endif
-          p->instance = found;
+
+          aic_outb(temp_p, temp_p->pause, HCNTRL);
+          while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+
+          temp_p->bios_address = 0;
 
           /*
            * Remember how the card was setup in case there is no seeprom.
            */
-          p->scsi_id = inb(p->base + SCSIID) & OID;
-          if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+          temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+          /*
+           * Get current termination setting
+           */
+          sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+
+          if (aic7xxx_chip_reset(temp_p) == -1)
           {
-            p->flags |= ULTRA_ENABLED;
-            ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
           }
-	  sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
-
-          aic7xxx_chip_reset(p);
 
-#ifdef AIC7XXX_USE_EXT_SCBRAM
-          if (devconfig & RAMPSM)
+          switch (temp_p->type & 0x1ff1)
           {
-            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
-                   "access.\n");
-            /*
-             * XXX - Assume 9 bit SRAM and enable parity checking.
-             */
-            devconfig |= EXTSCBPEN;
+            case AHC_394:   /* 3940 */
+            case AHC_394U:  /* 3940-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 5:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                default:
+                  break;
+              }
+              break;
 
-            /*
-             * XXX - Assume fast SRAM and only enable 2 cycle access if we
-             *       are sharing the SRAM across multiple adapters (398x).
-             */
-            if ((devconfig & MPORTMODE) == 0)
-            {
-              devconfig |= EXTSCBTIME;
-            }
-            devconfig &= ~SCBRAMSEL;
-            pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                       DEVCONFIG, devconfig);
+            case AHC_398:   /* 3985 */
+            case AHC_398U:  /* 3985-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 8:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                case 12:
+                  temp_p->flags |= AHC_CHNLC;
+                  break;
+                default:
+                  break;
+              }
+              break;
+
+            case AHC_AIC7895:
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              if (PCI_FUNC(temp_p->pci_device_fn) != 0)
+              {
+                temp_p->flags |= AHC_CHNLB;
+              }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              devconfig |= SCBSIZE32;
+              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#else
+              pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                &devconfig);
+              devconfig |= SCBSIZE32;
+              pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                devconfig);
+#endif
+              if (aic7xxx_7895_irq_hack != -1)
+              {
+                if (first_7895 == NULL)
+                {
+                  printk(KERN_INFO "aic7xxx: Using 7895_irq_hack.  Please "
+                    "upgrade your motherboard BIOS\n");
+                  first_7895 = temp_p;
+                }
+                else if (aic7xxx_7895_irq_hack == 0)
+                {
+                  if (temp_p->flags & AHC_CHNLB)
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+                else
+                {
+                  if ( !(temp_p->flags & AHC_CHNLB) )
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * Loading of the SEEPROM needs to come after we've set the flags
+           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
+           * on 394x and 398x cards we'll end up reading the wrong settings
+           * for channels B and C
+           */
+          if ( !(load_seeprom(temp_p, &sxfrctl1)) )
+          {
+            temp_p->flags |= AHC_USEDEFAULTS;
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
+            temp_p->scsi_id_b = temp_p->scsi_id;
           }
-#endif
 
-          if ((p->flags & USE_DEFAULTS) == 0)
+          /*
+           * and then we need another switch based on the type in order to
+           * make sure the channel B primary flag is set properly on 7895
+           * controllers....Arrrgggghhh!!!
+           */
+          switch(temp_p->type & 0x1ff1)
           {
-            load_seeprom(p, &sxfrctl1);
+            case AHC_AIC7895:
+              current_p = list_p;
+              while(current_p != NULL)
+              {
+                if ( (current_p->pci_bus == temp_p->pci_bus) &&
+                     (PCI_SLOT(current_p->pci_device_fn) ==
+                      PCI_SLOT(temp_p->pci_device_fn)) )
+                {
+                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
+                    temp_p->flags |= 
+                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
+                  else
+                    current_p->flags |=
+                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+                }
+                current_p = current_p->next;
+              }
+              break;
+            default:
+              break;
           }
 
           /*
            * Take the LED out of diagnostic mode
            */
-          sblkctl = inb(p->base + SBLKCTL);
-          outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+          aic_outb(temp_p, 
+            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
+            SBLKCTL);
 
           /*
            * We don't know where this is set in the SEEPROM or by the
            * BIOS, so we default to 100%.
            */
-          outb(DFTHRSH_100, p->base + DSPCISTATUS);
+          aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
 
-          if (p->flags & USE_DEFAULTS)
+          if (temp_p->flags & AHC_USEDEFAULTS)
           {
             int j;
+            unsigned char k;
             /*
              * Default setup; should only be used if the adapter does
              * not have a SEEPROM.
@@ -6534,158 +7667,315 @@
              */
             for (j = TARG_SCRATCH; j < 0x60; j++)
             {
-              if (inb(p->base + j) != 0x00)      /* Check for all zeroes. */
+              k = aic_inb(temp_p, j);
+              /* Check for all zeros and ones.  Break out if we pass */
+              if( (k != 0x00) && (k != 0xff) )
                 break;
             }
-            if (j == TARG_SCRATCH)
-            {
-              for (j = TARG_SCRATCH; j < 0x60; j++)
-              {
-                if (inb(p->base + 1) != 0xFF)    /* Check for all ones. */
-                  break;
-              }
-            }
-            if ((j != 0x60) && (p->scsi_id != 0))
+            /* If j makes it to 0x60, then all entries are either 0x00 or
+             * 0xff.  We would then assume we have *not* been initialized
+             * and drop through here.  OTOH, if even one entry is inited,
+             * then as long as we appear to have a valid SCSI ID, we'll use
+             * the leftover BIOS values.
+             */
+            if ((j != 0x60) && (temp_p->scsi_id != 0))
             {
-              p->flags &= ~USE_DEFAULTS;
-              if (aic7xxx_verbose)
+              temp_p->flags &= ~AHC_USEDEFAULTS;
+              if (aic7xxx_verbose & VERBOSE_PROBE2)
               {
                 printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
               }
             }
             else
             {
-              if (aic7xxx_verbose)
-              {
-                printk(KERN_INFO "aic7xxx: No BIOS found; using default "
-                       "settings.\n");
-              }
               /*
                * Assume only one connector and always turn on
                * termination.
                */
+              temp_p->flags &= ~AHC_BIOS_ENABLED;
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
               sxfrctl1 = STPWEN;
-              p->scsi_id = 7;
+              temp_p->scsi_id = 7;
             }
-            outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
-                 p->base + SCSICONF);
+            aic_outb(temp_p, (temp_p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+                 SCSICONF);
             /* In case we are a wide card. */
-            outb(p->scsi_id, p->base + SCSICONF + 1);
-            if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
-            {
-              /*
-               * If there wasn't a BIOS or the board wasn't in this mode
-               * to begin with, turn off Ultra.
-               */
-              p->flags &= ~ULTRA_ENABLED;
-            }
+            aic_outb(temp_p, temp_p->scsi_id, SCSICONF + 1);
           }
-
-          /*
-           * Print some additional information about the adapter.
-           */
-          printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
-                 "IO Mem 0x%x, IRQ %d",
-                 (p->flags & USE_DEFAULTS) ? "dis" : "en",
-                 p->base, p->mbase, p->irq);
-          if ((class_revid & DEVREVID) < 3)
+          else /* not using defaults */
           {
-            printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A;
           }
-          printk("\n");
-
-          /*
-           * I don't think we need to bother with allowing
-           * spurious interrupts for the 787x/785x, but what
-           * the hey.
-           */
-          aic7xxx_spurious_count = 1;
 
           if (aic7xxx_extended)
-            p->flags |= EXTENDED_TRANSLATION;
-
-          if (aic7xxx_verbose)
-            printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-                   (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+            temp_p->flags |= AHC_EXTEND_TRANS_A;
 
           /*
            * Put our termination setting into sxfrctl1 now that the
            * generic initialization is complete.
            */
-          sxfrctl1 |= inb(p->base + SXFRCTL1);
-          outb(sxfrctl1, p->base + SXFRCTL1);
-
-          if (aic7xxx_register(template, p) == 0)
+          sxfrctl1 |= aic_inb(temp_p, SXFRCTL1);
+          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+          if ( list_p == NULL )
           {
-            aic7xxx_free(p);
+            list_p = current_p = temp_p;
           }
           else
           {
-            found = found + 1;
+            current_p = list_p;
+            while(current_p->next != NULL)
+              current_p = current_p->next;
+            current_p->next = temp_p;
+          }
+          temp_p->next = NULL;
+          found++;
+        }  /* Found an Adaptec PCI device. */
+        else /* Well, we found one, but we couldn't get any memory */
+        {
+          printk("aic7xxx: Found <%s>\n", 
+            board_names[aic7xxx_pci_devices[i].board_name_index]);
+          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
+            "skipping.\n");
+        }
+      } /* while(pdev=....) */
+    } /* for PCI_DEVICES */
+  } /* PCI BIOS present */
+#endif CONFIG_PCI
+  /*
+   * Now, we re-order the probed devices by BIOS address and BUS class.
+   * In general, we follow this algorithm to make the adapters show up
+   * in the same order under linux that the computer finds them.
+   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
+   *     address, going from lowest to highest.
+   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
+   *     address, going from lowest to highest.
+   *  3: Remaining VLB/EISA controllers going in slot order.
+   *  4: Remaining PCI controllers, going in PCI device order (reversable)
+   */
 
-#ifdef AIC7XXX_USE_EXT_SCBRAM
+  {
+    struct aic7xxx_host *vlb_enab, *vlb_disab, *pci;
+    struct aic7xxx_host *prev_p;
+    struct aic7xxx_host *p;
+    unsigned char left;
+
+    prev_p = vlb_enab = vlb_disab = pci = NULL;
+
+    temp_p = list_p;
+    while (temp_p != NULL)
+    {
+      switch(temp_p->type)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+        case AHC_284:
+          if (temp_p->flags & AHC_BIOS_ENABLED)
+          {
+            if (vlb_enab == NULL)
+            {
+              vlb_enab = temp_p;
+              temp_p = temp_p->next;
+              vlb_enab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_enab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->bios_address < temp_p->bios_address))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_enab = temp_p;
+                temp_p = temp_p->next;
+                vlb_enab->next = current_p;
+              }
+            }
+          }
+          else
+          {
+            if (vlb_disab == NULL)
+            {
+              vlb_disab = temp_p;
+              temp_p = temp_p->next;
+              vlb_disab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_disab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->base < temp_p->base))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_disab = temp_p;
+                temp_p = temp_p->next;
+                vlb_disab->next = current_p;
+              }
+            }
+          }
+          break;
+        default:  /* All PCI controllers fall through to default */
+          if (pci == NULL)
+          {
+            pci = temp_p;
+            temp_p = temp_p->next;
+            pci->next = NULL;
+          }
+          else
+          {
+            current_p = pci;
+            prev_p = NULL;
+            if (!aic7xxx_reverse_scan)
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) < 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            else
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) > 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
             /*
-             * Set the shared SCB data once we've successfully probed a
-             * 398x adapter.
-             *
-             * Note that we can only do this if the use of external
-             * SCB RAM is enabled.
+             * Are we dealing with a 7985 where we need to sort the
+             * channels as well, if so, the bios_address values should
+             * be the same
              */
-            if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
+                 (temp_p->pci_bus == current_p->pci_bus) &&
+                 (PCI_SLOT(temp_p->pci_device_fn) ==
+                  PCI_SLOT(current_p->pci_device_fn)) )
             {
-              if (shared_scb_data == NULL)
+              if (temp_p->flags & AHC_CHNLB)
+              {
+                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+              else
               {
-                shared_scb_data = p->scb_data;
+                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
               }
             }
-#endif
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              pci = temp_p;
+              temp_p = temp_p->next;
+              pci->next = current_p;
+            }
           }
-
-          index++;
-          /*
-           * Disable spurious interrupts.
-           */
-          aic7xxx_spurious_count = 0;
-        }  /* Found an Adaptec PCI device. */
+          break;
+      }  /* End of switch(temp_p->type) */
+    } /* End of while (temp_p != NULL) */
+    /*
+     * At this point, the cards have been broken into 4 sorted lists, now
+     * we run through the lists in order and register each controller
+     */
+    left = found;
+    temp_p = vlb_enab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = pci;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = vlb_disab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
       }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
     }
   }
-#endif CONFIG_PCI
   return (found);
 }
 
-static void
-aic7xxx_fake_scsi_done(Scsi_Cmnd *cmd)
-{
-  memset(&cmd->sense_buffer[0], '\0', sizeof(cmd->sense_buffer));
-}
-
-static void
-aic7xxx_make_fake_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *cmd, int which)
-{
-  Scsi_Cmnd *cmd2;
-
-  if (which == 0)
-    p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 = cmd2 =
-	kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
-  else
-    p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 = cmd2 =
-	kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
-  if (cmd2 != NULL)
-  {
-    memcpy(cmd2, cmd, sizeof(Scsi_Cmnd));
-    memset(&cmd2->cmnd[0], '\0', sizeof(cmd2->cmnd));
-    cmd2->cmnd[0] = TEST_UNIT_READY;
-    cmd2->cmd_len = 6;
-    cmd2->bufflen = 0;
-    cmd2->request_bufflen = 0;
-    cmd2->buffer = NULL;
-    cmd2->request_buffer = NULL;
-    cmd2->use_sg = 0;
-    cmd2->underflow = 0;
-  }
-}
-
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_buildscb
@@ -6707,85 +7997,61 @@
    * Setup the control byte if we need negotiation and have not
    * already requested it.
    */
+  hscb->control = 0;
+  scb->tag_action = 0;
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
-#ifdef AIC7XXX_TAGGED_QUEUEING
-    if (cmd->device->tagged_queue)
+    if (p->tagenable & mask)
     {
       cmd->tag = hscb->tag;
-      p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 200)
+      p->dev_commands_sent[TARGET_INDEX(cmd)]++;
+      if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
       {
         hscb->control |= MSG_SIMPLE_Q_TAG;
+        scb->tag_action = MSG_SIMPLE_Q_TAG;
       }
       else
       {
-        hscb->control |= MSG_ORDERED_Q_TAG;
-        p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+        if (p->orderedtag & mask)
+        {
+          hscb->control |= MSG_ORDERED_Q_TAG;
+          scb->tag_action = MSG_ORDERED_Q_TAG;
+        }
+        else
+        {
+          hscb->control |= MSG_SIMPLE_Q_TAG;
+          scb->tag_action = MSG_SIMPLE_Q_TAG;
+        }
+        p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
       }
     }
-#endif  /* Tagged queueing */
   }
-  if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
+  if ( (p->needwdtr & mask) &&
+      !(p->wdtr_pending & mask) &&
+       (scb->cmd->lun == 0) )
   {
-    if ( cmd->cmnd[0] == TEST_UNIT_READY )
-    {
-      p->wdtr_pending |= mask;
-      hscb->control |= MK_MESSAGE;
-      scb->flags |= SCB_MSGOUT_WDTR;
-    }
+    p->wdtr_pending |= mask;
+    hscb->control |= MK_MESSAGE;
+    if (p->needwdtr_copy & mask)
+      scb->flags |= SCB_MSGOUT_WDTR_16BIT;
     else
-    {
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 == NULL )
-        aic7xxx_make_fake_cmnd(p, cmd, 0);
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 == NULL )
-        aic7xxx_make_fake_cmnd(p, cmd, 1);
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 != NULL )
-        aic7xxx_queue(p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0,
-          aic7xxx_fake_scsi_done);
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 != NULL )
-        aic7xxx_queue(p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1,
-          aic7xxx_fake_scsi_done);
-    }
-#if 0
-    printk("scsi%d: Sending WDTR request to target %d.\n",
-           p->host_no, cmd->target);
-#endif
+      scb->flags |= SCB_MSGOUT_WDTR_8BIT;
   }
   else
   {
-    if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
+    if ( (p->needsdtr & mask) &&
+        !(p->sdtr_pending & mask) &&
+        !(p->wdtr_pending & mask) &&
+         (scb->cmd->lun == 0) )
     {
-      if ( cmd->cmnd[0] == TEST_UNIT_READY )
-      {
-        p->sdtr_pending |= mask;
-        hscb->control |= MK_MESSAGE;
-        scb->flags |= SCB_MSGOUT_SDTR;
-      }
-      else
-      {
-        if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 == NULL )
-          aic7xxx_make_fake_cmnd(p, cmd, 0);
-        if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 == NULL )
-          aic7xxx_make_fake_cmnd(p, cmd, 1);
-        if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 != NULL )
-          aic7xxx_queue(p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1,
-            aic7xxx_fake_scsi_done);
-      }
-#if 0
-      printk("scsi%d: Sending SDTR request to target %d.\n",
-             p->host_no, cmd->target);
-#endif
+      p->sdtr_pending |= mask;
+      hscb->control |= MK_MESSAGE;
+      scb->flags |= SCB_MSGOUT_SDTR;
     }
   }
-#if 0
-  printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
-         "mask(0x%x).\n",
-	 cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
-#endif
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
-	((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
 
   /*
    * The interpretation of request_buffer and request_bufflen
@@ -6799,7 +8065,7 @@
    *       little-endian format.
    */
   hscb->SCSI_cmd_length = cmd->cmd_len;
-  hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
+  hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
 
   if (cmd->use_sg)
   {
@@ -6814,46 +8080,42 @@
     int i;
 
     sg = (struct scatterlist *)cmd->request_buffer;
+    scb->sg_length = 0;
     for (i = 0; i < cmd->use_sg; i++)
     {
-      scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
-      scb->sg_list[i].length = (unsigned int) sg[i].length;
+      scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
+      scb->sg_list[i].length = cpu_to_le32(sg[i].length);
+      scb->sg_length += sg[i].length;
     }
-    hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+    hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(scb->sg_list));
     hscb->SG_segment_count = cmd->use_sg;
-    scb->sg_count = hscb->SG_segment_count;
+    scb->sg_count = cmd->use_sg;
 
     /* Copy the first SG into the data pointer area. */
     hscb->data_pointer = scb->sg_list[0].address;
-    hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
-#if 0
-    printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
-           cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
-#endif
+    hscb->data_count = scb->sg_list[0].length;
   }
   else
   {
-#if 0
-  printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
-	(unsigned long) cmd->request_buffer, cmd->request_bufflen);
-#endif
     if (cmd->request_bufflen)
     {
-      hscb->SG_segment_count = 1;
       scb->sg_count = 1;
-      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
-      scb->sg_list[0].length = cmd->request_bufflen;
-      hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
-      hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
-      hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
+      scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+      scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+      scb->sg_length = cmd->request_bufflen;
+      hscb->SG_segment_count = 1;
+      hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+      hscb->data_count = scb->sg_list[0].length;
+      hscb->data_pointer = scb->sg_list[0].address;
     }
     else
     {
-      hscb->SG_segment_count = 0;
       scb->sg_count = 0;
+      scb->sg_length = 0;
+      hscb->SG_segment_count = 0;
       hscb->SG_list_pointer = 0;
+      hscb->data_count = 0;
       hscb->data_pointer = 0;
-      hscb->data_count = SCB_LIST_NULL << 24;
     }
   }
 }
@@ -6868,57 +8130,53 @@
 int
 aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 {
-  long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
   int tindex = TARGET_INDEX(cmd);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-
   /*
    * Check to see if channel was scanned.
    */
-  if (!(p->flags & A_SCANNED) && (cmd->channel == 0))
+  if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
   {
-    printk(KERN_INFO "scsi%d: Scanning channel A for devices.\n", p->host_no);
-    p->flags |= A_SCANNED;
+    printk(INFO_LEAD "Scanning channel for devices.\n",
+      p->host_no, 0, -1, -1);
+    p->flags |= AHC_A_SCANNED;
   }
   else
   {
-    if (!(p->flags & B_SCANNED) && (cmd->channel == 1))
+    if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
     {
-      printk(KERN_INFO "scsi%d: Scanning channel B for devices.\n", p->host_no);
-      p->flags |= B_SCANNED;
+      printk(INFO_LEAD "Scanning channel for devices.\n",
+        p->host_no, 1, -1, -1);
+      p->flags |= AHC_B_SCANNED;
     }
   }
 
-#if 0
-  printk("aic7xxx: (queue) cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
-	cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
-	cmd->lun & 0x07);
-#endif
-
-  if ( (p->device_status[tindex].active_cmds > cmd->device->queue_depth) &&
-      !(p->wdtr_pending & (0x1 << tindex)) && 
-      !(p->sdtr_pending & (0x1 << tindex)) )
+  if (p->dev_active_cmds[tindex] > cmd->device->queue_depth)
   {
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Commands queued exceeds queue "
-	   "depth, active=%d\n",
+    printk(WARN_LEAD "Commands queued exceeds queue "
+           "depth, active=%d\n",
            p->host_no, CTL_OF_CMD(cmd), 
-	   p->device_status[tindex].active_cmds);
-  }
-  scb = aic7xxx_allocate_scb(p);
+           p->dev_active_cmds[tindex]);
+    if ( p->dev_active_cmds[tindex] > 220 )
+      p->dev_active_cmds[tindex] = 0;
+  }
+  DRIVER_LOCK
+  scb = aic7xxx_allocate_scb(p, FALSE);
+  DRIVER_UNLOCK
   if (scb == NULL)
   {
-    panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
+    panic("(scsi%d) aic7xxx_queue:Couldn't get a free SCB.\n", p->host_no);
   }
   else
   {
     scb->cmd = cmd;
     aic7xxx_position(cmd) = scb->hscb->tag;
-#if 0
-    debug_scb(scb);
-#endif;
 
     /*
      * Construct the SCB beforehand, so the sequencer is
@@ -6926,17 +8184,6 @@
      */
     aic7xxx_buildscb(p, cmd, scb);
 
-#if 0
-    if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
-    {
-      printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
-             "address.\n");
-    }
-    printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
-	   scb->hscb->tag, (unsigned int) scb->cmd,
-	   scb->flags, (unsigned int) p->free_scb);
-#endif
-
     /*
      * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
      * is set up properly, and the parity error flag is reset, then send
@@ -6951,26 +8198,20 @@
 
     scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-    save_flags(processor_flags);
-    cli();
-    if (p->device_status[tindex].delayed_scbs.head != NULL) 
+    DRIVER_LOCK
+    if (p->delayed_scbs[tindex].head != NULL) 
     {
-        scbq_insert_tail(&p->device_status[tindex].delayed_scbs, scb);
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
     }
     else
     {
         scbq_insert_tail(&p->waiting_scbs, scb);
     }
-    if ((p->flags & (IN_ISR | IN_ABORT | RESET_PENDING)) == 0)
+    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
     {
       aic7xxx_run_waiting_queues(p);
     }
-    restore_flags(processor_flags);
-
-#if 0
-    printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
-           (long) cmd, (long) scb->cmd, scb->hscb->tag);
-#endif;
+    DRIVER_UNLOCK
   }
   return (0);
 }
@@ -6992,53 +8233,54 @@
   struct aic7xxx_scb   *scb;
   struct aic7xxx_hwscb *hscb;
   int result = -1;
-  char channel;
+  int channel;
   unsigned char saved_scbptr, lastphase;
-  unsigned char hscb_index, linked_next;
+  unsigned char hscb_index;
   int disconnected;
 
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   hscb = scb->hscb;
 
-  lastphase = inb(p->base + LASTPHASE);
-  if (aic7xxx_verbose > 1)
+  lastphase = aic_inb(p, LASTPHASE);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
   {
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus Device reset, scb flags 0x%x, ",
+    printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
          p->host_no, CTL_OF_SCB(scb), scb->flags);
     switch (lastphase)
     {
       case P_DATAOUT:
-        printk("Data-Out phase, ");
+        printk("Data-Out phase\n");
         break;
       case P_DATAIN:
-        printk("Data-In phase, ");
+        printk("Data-In phase\n");
         break;
       case P_COMMAND:
-        printk("Command phase, ");
+        printk("Command phase\n");
         break;
       case P_MESGOUT:
-        printk("Message-Out phase, ");
+        printk("Message-Out phase\n");
         break;
       case P_STATUS:
-        printk("Status phase, ");
+        printk("Status phase\n");
         break;
       case P_MESGIN:
-        printk("Message-In phase, ");
+        printk("Message-In phase\n");
         break;
       default:
       /*
        * We're not in a valid phase, so assume we're idle.
        */
-        printk("while idle, LASTPHASE = 0x%x, ", lastphase);
+        printk("while idle, LASTPHASE = 0x%x\n", lastphase);
         break;
     }
-    printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
-         inb(p->base + SCSISIGI),
-         inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-         inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+    printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+         "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+         aic_inb(p, SCSISIGI),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
   }
 
-  channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
+  channel = cmd->channel;
 
     /*
      * Send a Device Reset Message:
@@ -7052,142 +8294,155 @@
      * fails, we'll get another timeout a few seconds later which will
      * attempt a bus reset.
      */
-  saved_scbptr = inb(p->base + SCBPTR);
+  saved_scbptr = aic_inb(p, SCBPTR);
   disconnected = FALSE;
 
   if (lastphase != P_BUSFREE)
   {
-    if (inb(p->base + SCB_TAG) >= p->scb_data->numscbs)
+    if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
     {
-        /*
-         * Perform a bus reset.
-         *
-         * XXX - We want to queue an abort for the timedout SCB
-         *       instead.
-         */
-      printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
-             "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
+      printk(WARN_LEAD "Invalid SCB ID %d is active, "
+             "SCB flags = 0x%x.\n", p->host_no,
+            CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
       return(SCSI_RESET_ERROR);
     }
-    if (scb->hscb->tag == inb(p->base + SCB_TAG))
+    if (scb->hscb->tag == aic_inb(p, SCB_TAG))
     { 
       if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
       {
-        /* Send the abort message to the active SCB. */
-        outb(1, p->base + MSG_LEN);
-        outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
-        outb(lastphase | ATNO, p->base + SCSISIGO);
-	if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Device reset message in "
-		"message buffer\n", p->host_no, CTL_OF_SCB(scb));
+        if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+          printk(INFO_LEAD "Device reset message in "
+                "message buffer\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-	p->device_status[TARGET_INDEX(scb->cmd)].flags &= 
-		~DEVICE_SUCCESS;
-	p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
-		BUS_DEVICE_RESET_PENDING;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
+        /* Send the abort message to the active SCB. */
+        aic_outb(p, HOST_MSG, MSG_OUT);
+        aic_outb(p, lastphase | ATNO, SCSISIGO);
         return(SCSI_RESET_PENDING);
       }
       else
       {
-	/* We want to send out the message, but it could screw an already */
-	/* in place and being used message.  Instead, we return an error  */
-	/* to try and start the bus reset phase since this command is     */
+        /* We want to send out the message, but it could screw an already */
+        /* in place and being used message.  Instead, we return an error  */
+        /* to try and start the bus reset phase since this command is     */
         /* probably hung (aborts failed, and now reset is failing).  We   */
         /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
         /* any more on this device, but instead will escalate to a bus or */
         /* host reset (additionally, we won't try to abort any more).     */
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Device reset, Message buffer "
-		"in use\n", p->host_no, CTL_OF_SCB(scb));
-	scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        printk(WARN_LEAD "Device reset, Message buffer "
+                "in use\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-	p->device_status[TARGET_INDEX(scb->cmd)].flags &= 
-		~DEVICE_SUCCESS;
-	p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
-		BUS_DEVICE_RESET_PENDING;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
         return(SCSI_RESET_ERROR);
       }
     }
-  }
+  } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
   hscb_index = aic7xxx_find_scb(p, scb);
   if (hscb_index == SCB_LIST_NULL)
   {
-    disconnected = TRUE;
-    linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+    disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
   }
   else
   {
-    outb(hscb_index, p->base + SCBPTR);
-    if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+    aic_outb(p, hscb_index, SCBPTR);
+    if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
     {
       disconnected = TRUE;
     }
-    linked_next = inb(p->base + SCB_LINKED_NEXT);
   }
   if (disconnected)
   {
         /*
-         * Simply set the ABORT_SCB control bit and preserve the
-         * linked next pointer.
+         * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+         * the rest on a reconnect.
          */
-    scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
-    scb->hscb->data_count &= ~0xFF000000;
-    scb->hscb->data_count |= linked_next << 24;
-    if ((p->flags & PAGE_ENABLED) == 0)
-    {
-      scb->hscb->control &= ~DISCONNECTED;
-    }
-    scb->flags |= SCB_RESET | SCB_DEVICE_RESET | SCB_QUEUED_ABORT;
-    p->device_status[TARGET_INDEX(scb->cmd)].flags &= ~DEVICE_SUCCESS;
-    p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
-	BUS_DEVICE_RESET_PENDING;
+    scb->hscb->control |= MK_MESSAGE;
+    scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+        BUS_DEVICE_RESET_PENDING;
     if (hscb_index != SCB_LIST_NULL)
     {
       unsigned char scb_control;
 
-      scb_control = inb(p->base + SCB_CONTROL);
-      outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
+      aic_outb(p, hscb_index, SCBPTR);
+      scb_control = aic_inb(p, SCB_CONTROL);
+      aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
     }
         /*
          * Actually requeue this SCB in case we can select the
          * device before it reconnects.  If the transaction we
-         * want to abort is not tagged, unbusy it first so that
-         * we don't get held back from sending the command.
+         * want to abort is not tagged, then this will be the only
+         * outstanding command and we can simply shove it on the
+         * qoutfifo and be done.  If it is tagged, then it goes right
+         * in with all the others, no problem :)  We need to add it
+         * to the qinfifo and let the sequencer know it is there.
+         * Now, the only problem left to deal with is, *IF* this
+         * command completes, in spite of the MK_MESSAGE bit in the
+         * control byte, then we need to pick that up in the interrupt
+         * routine and clean things up.  This *shouldn't* ever happen.
          */
-    if ((scb->hscb->control & TAG_ENB) == 0)
-    {
-      aic7xxx_search_qinfifo(p, cmd->target, channel, cmd->lun, 
-	     SCB_LIST_NULL, 0, TRUE, &p->waiting_scbs);
-    }
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queueing device reset command.\n",
-           p->host_no, CTL_OF_SCB(scb));
-    if ( !(scb->flags & SCB_WAITINGQ) ) /* Make sure we don't already have   */
-    {					/* an abort scb queued, or else we   */
-					/* corrupt the waiting queue and     */
-					/* active_cmds counter by queueing   */
-					/* again.			     */
-      scbq_insert_head(&p->waiting_scbs, scb);
-      scb->flags |= SCB_WAITINGQ;
-      p->device_status[TARGET_INDEX(scb->cmd)].active_cmds--;
-    }
-    else
-    {
-      scb->flags &= ~SCB_ABORT;
-    }
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Queueing device reset "
+           "command.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    scb->flags |= SCB_QUEUED_ABORT;
     result = SCSI_RESET_PENDING;
   }
   else if (result == -1)
   {
     result = SCSI_RESET_ERROR;
   }
-  outb(saved_scbptr, p->base + SCBPTR);
+  aic_outb(p, saved_scbptr, SCBPTR);
   return (result);
 }
 
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_panic_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+void
+aic7xxx_panic_abort(struct aic7xxx_host *p)
+{
+  int i;
+
+  printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if(p->dev_flags[i] & DEVICE_PRESENT)
+    {
+      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%s, SDTR:%s, q_depth=%d:%d\n",
+        p->host_no, 0, i, 0, p->dev_flags[i],
+        (p->needwdtr_copy & (1 << i)) ? "Yes" : "No",
+        (p->needsdtr_copy & (1 << i)) ? "Yes" : "No",
+        p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+    }
+  }
+  printk("SIMODE0=0x%x, SIMODE1=0x%x, SSTAT0=0x%x, SSTAT1=0x%x, INTSTAT=0x%x\n",
+    aic_inb(p, SIMODE0), aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+    aic_inb(p, SSTAT1), aic_inb(p, INTSTAT) );
+  printk("p->flags=0x%x, p->type=0x%x, sequencer %s paused\n",
+     p->flags, p->type,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  panic("Stopping to debug\n");
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_abort
  *
  * Description:
@@ -7200,15 +8455,26 @@
   struct aic7xxx_host *p;
   int    result, found=0;
   unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
-  unsigned long processor_flags;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
   Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
 
-  save_flags(processor_flags);
-  pause_sequencer(p);
-  cli();
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
+
+  DRIVER_LOCK
 
 /*
  *  Run the isr to grab any command in the QOUTFIFO and any other misc.
@@ -7218,19 +8484,22 @@
  *  code.
  */
 
-  while ( (inb(p->base + INTSTAT) & INT_PEND) && !(p->flags & IN_ISR) )
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL);
+    aic7xxx_isr(p->irq, p, (void *)NULL);
     pause_sequencer(p);
   }
 
-  if (scb == NULL)    /*  Totally bogus cmd since it points beyond our  */
-  {                   /*  valid SCB range.  The suspect scb hasn't been */
-                      /*  allocated yet.                                */
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called with bogus Scsi_Cmnd->"
-	"SCB mapping.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+                      /*  Totally bogus cmd since it points beyond our  */
+  {                   /*  valid SCB range or doesn't even match it's own*/
+                      /*  timeout serial number.                        */
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
+        "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_NOT_RUNNING);
   }
   if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
@@ -7250,25 +8519,27 @@
     {
       if (cmd_next == cmd) 
       {
-	if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called for command "
-	  "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
-	if ( cmd_prev == NULL )
-	  p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-	else
-	  cmd_prev->host_scribble = cmd_next->host_scribble;
-	cmd_next->done(cmd_next);
-        unpause_sequencer(p, TRUE);
-	restore_flags(processor_flags);
-	return(SCSI_ABORT_SUCCESS);
-      }				  
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "Abort called for command "
+          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        if ( cmd_prev == NULL )
+          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+        else
+          cmd_prev->host_scribble = cmd_next->host_scribble;
+        cmd_next->done(cmd_next);
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+                                         * completion */
+      }                                  
       cmd_prev = cmd_next;
       cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
     }
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called for already completed"
-	" command.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called for already completed"
+        " command.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_NOT_RUNNING);
   }
     
@@ -7294,29 +8565,29 @@
 
   if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB aborted once already, "
-	"escalating.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB aborted once already, "
+        "escalating.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_SNOOZE);
   }
-  if ( (p->flags & (RESET_PENDING | ABORT_PENDING)) || 
-          (p->device_status[TARGET_INDEX(scb->cmd)].flags & 
+  if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
+          (p->dev_flags[TARGET_INDEX(scb->cmd)] & 
            BUS_DEVICE_RESET_PENDING) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset/Abort pending for this "
-	"device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "Reset/Abort pending for this "
+        "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_PENDING);
   }
 
   found = 0;
-  p->flags |= IN_ABORT;
-  if (aic7xxx_verbose)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+  p->flags |= AHC_IN_ABORT;
+  if (aic7xxx_verbose & VERBOSE_ABORT)
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
          p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
 
 /*
@@ -7327,13 +8598,13 @@
  *    level code to reset the timeout.
  */
 
-  if ( scb->hscb->tag == inb(p->base + SCB_TAG) )
+  if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
   {
    /*
     *  Check to see if the sequencer is just sitting on this command, or
     *   if it's actively being run.
     */
-    result = inb(p->base + LASTPHASE);
+    result = aic_inb(p, LASTPHASE);
     switch (result)
     {
       case P_DATAOUT:    /*    For any of these cases, we can assume we are */
@@ -7342,15 +8613,15 @@
       case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
       case P_MESGOUT:    /*    chances to finish and then escalate to a     */
       case P_MESGIN:     /*    reset call                                   */
-	if (aic7xxx_verbose > 1)
-         printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB is currently active.  "
-		"Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
-        unpause_sequencer(p, TRUE);
-	p->flags &= ~IN_ABORT;
-	scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
-	p->flags |= ABORT_PENDING;      /*  here so we will know not to    */
-        restore_flags(processor_flags); /*  muck with other SCBs if this   */
-        return(SCSI_ABORT_PENDING);      /*  one doesn't complete and clear */
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB is currently active.  "
+                "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        unpause_sequencer(p, FALSE);
+        p->flags &= ~AHC_IN_ABORT;
+        scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
+        p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
+        DRIVER_UNLOCK                   /*  muck with other SCBs if this   */
+        return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
         break;                          /*  out.                           */
       default:
         break;
@@ -7361,12 +8632,13 @@
   {
       int tindex = TARGET_INDEX(cmd);
      
-      if (aic7xxx_verbose > 1) 
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found on waiting list and "
-	    "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+      if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
+        printk(INFO_LEAD "SCB found on waiting list and "
+            "aborted.\n", p->host_no, CTL_OF_SCB(scb));
       scbq_remove(&p->waiting_scbs, scb);
-      scbq_remove(&p->device_status[tindex].delayed_scbs, scb);
-      p->device_status[tindex].active_cmds++;
+      scbq_remove(&p->delayed_scbs[tindex], scb);
+      p->dev_active_cmds[tindex]++;
+      p->activescbs++;
       scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
       scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
       found = 1;
@@ -7378,10 +8650,11 @@
   if ( found == 0 )
   {
     if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
-                     INT_TO_CHAN(cmd->channel),
-	             cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
-	             FALSE, NULL)) != 0) && (aic7xxx_verbose > 1))
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found in QINFIFO and "
+                     cmd->channel,
+                     cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+                     FALSE, NULL)) != 0) &&
+                    (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
+      printk(INFO_LEAD "SCB found in QINFIFO and "
         "aborted.\n", p->host_no, CTL_OF_SCB(scb));
   }
 
@@ -7393,35 +8666,44 @@
   {
     unsigned char scb_next_ptr;
     prev_hscbptr = SCB_LIST_NULL;
-    saved_hscbptr = inb(p->base + SCBPTR);
-    next_hscbptr = inb(p->base + WAITING_SCBH);
+    saved_hscbptr = aic_inb(p, SCBPTR);
+    next_hscbptr = aic_inb(p, WAITING_SCBH);
     while ( next_hscbptr != SCB_LIST_NULL )
     {
-      outb( next_hscbptr, p->base + SCBPTR );
-      if ( scb->hscb->tag == inb(p->base + SCB_TAG) )
+      aic_outb(p,  next_hscbptr, SCBPTR );
+      if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
       {
         found = 1;
-	if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found on hardware waiting"
-	    " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
-	if ( prev_hscbptr == SCB_LIST_NULL )
-	    outb(inb(p->base + SCB_NEXT), p->base + WAITING_SCBH);
-	else
-	{
-	    scb_next_ptr = inb(p->base + SCB_NEXT);
-	    outb(prev_hscbptr, p->base + SCBPTR);
-	    outb(scb_next_ptr, p->base + SCB_NEXT);
-	    outb(next_hscbptr, p->base + SCBPTR);
-	}
-	outb(SCB_LIST_NULL, p->base + SCB_TAG);
-	aic7xxx_add_curscb_to_free_list(p);
-	scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB found on hardware waiting"
+            " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+        if ( prev_hscbptr == SCB_LIST_NULL )
+        {
+            aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
+            /* stop the selection since we just
+             * grabbed the scb out from under the
+             * card
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+            aic_outb(p, CLRSELTIMEO, CLRSINT1);
+        }
+        else
+        {
+            scb_next_ptr = aic_inb(p, SCB_NEXT);
+            aic_outb(p, prev_hscbptr, SCBPTR);
+            aic_outb(p, scb_next_ptr, SCB_NEXT);
+            aic_outb(p, next_hscbptr, SCBPTR);
+        }
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        aic7xxx_add_curscb_to_free_list(p);
+        scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
         break;
       }
       prev_hscbptr = next_hscbptr;
-      next_hscbptr = inb(p->base + SCB_NEXT);
+      next_hscbptr = aic_inb(p, SCB_NEXT);
     }
-    outb( saved_hscbptr, p->base + SCBPTR );
+    aic_outb(p,  saved_hscbptr, SCBPTR );
   }
         
 /*
@@ -7436,42 +8718,32 @@
 
   if ( found == 0 )
   {
-    p->flags |= ABORT_PENDING;
+    p->flags |= AHC_ABORT_PENDING;
     scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
-    scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+    scb->hscb->control |= MK_MESSAGE;
     result=aic7xxx_find_scb(p, scb);
     if ( result != SCB_LIST_NULL ) 
     {
-      saved_hscbptr = inb(p->base + SCBPTR);
-      outb(result, p->base + SCBPTR);
-      tmp_char = inb(p->base + SCB_CONTROL);
-      outb( tmp_char | MK_MESSAGE | ABORT_SCB, p->base + SCB_CONTROL);
-      outb(saved_hscbptr, p->base + SCBPTR);
+      saved_hscbptr = aic_inb(p, SCBPTR);
+      aic_outb(p, result, SCBPTR);
+      tmp_char = aic_inb(p, SCB_CONTROL);
+      aic_outb(p,  tmp_char | MK_MESSAGE, SCB_CONTROL);
+      aic_outb(p, saved_hscbptr, SCBPTR);
     }
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB disconnected.  Queueing Abort"
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
         " SCB.\n", p->host_no, CTL_OF_SCB(scb));
-    if ( (scb->hscb->control & TAG_ENB) == 0 )
-    {
-      aic7xxx_search_qinfifo(p, cmd->target, INT_TO_CHAN(cmd->channel),
-	cmd->lun, SCB_LIST_NULL, 0, TRUE, &p->waiting_scbs);
-    }
-    if ( !(scb->flags & SCB_WAITINGQ) )
-    {
-      scbq_insert_head(&p->waiting_scbs, scb);
-      scb->flags |= SCB_WAITINGQ;
-      p->device_status[TARGET_INDEX(scb->cmd)].active_cmds--;
-    }
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
   }
-  else
-  { 
-    scb->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-    scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+  if (found)
+  {
+    aic7xxx_run_done_queue(p, TRUE);
+    aic7xxx_run_waiting_queues(p);
   }
-  aic7xxx_run_done_queue(p, TRUE);
-  aic7xxx_run_waiting_queues(p);
-  p->flags &= ~IN_ABORT;
-  restore_flags(processor_flags);
+  p->flags &= ~AHC_IN_ABORT;
+  unpause_sequencer(p, FALSE);
+  DRIVER_UNLOCK
 
 /*
  *  On the return value.  If we found the command and aborted it, then we know
@@ -7507,44 +8779,54 @@
   struct aic7xxx_host *p;
   int    tindex;
   int    result = -1;
-  char   channel = 'A';
-  unsigned long processor_flags;
-#define	DEVICE_RESET 0x01
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+#define DEVICE_RESET 0x01
 #define BUS_RESET    0x02
 #define HOST_RESET   0x04
 #define FAIL         0x08
-#define	RESET_DELAY  0x10
-  int	action;
+#define RESET_DELAY  0x10
+  int        action;
   Scsi_Cmnd *cmd_prev, *cmd_next;
 
 
   if ( cmd == NULL )
   {
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(aic7xxx) Reset called with NULL Scsi_Cmnd "
-	"pointer, failing.\n");
+    printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
+      "pointer, failing.\n");
     return(SCSI_RESET_SNOOZE);
   }
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  channel = INT_TO_CHAN(cmd->channel);
   tindex = TARGET_INDEX(cmd);
 
-  save_flags(processor_flags);
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
+
+  DRIVER_LOCK
+
   pause_sequencer(p);
-  cli();
-  while ( (inb(p->base + INTSTAT) & INT_PEND) && !(p->flags & IN_ISR) )
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL );
+    aic7xxx_isr(p->irq, p, (void *)NULL );
     pause_sequencer(p);
   }
 
   if (scb == NULL)
   {
-    if (aic7xxx_verbose)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called with bogus Scsi_Cmnd"
-	   "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
       action = HOST_RESET;
@@ -7556,43 +8838,38 @@
   }
   else if (scb->cmd != cmd) 
   {
-    if (aic7xxx_verbose > 1)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called with recycled SCB "
-	"for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+    printk(INFO_LEAD "Reset called with recycled SCB "
+        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
     cmd_prev = NULL;
     cmd_next = p->completeq.head;
     while ( cmd_next != NULL )
     {
       if (cmd_next == cmd)
       {
-	if (aic7xxx_verbose > 1)
-	  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset, found cmd on completeq"
-	  ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
-	if ( cmd_prev == NULL )
-	  p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-	else
-	  cmd_prev->host_scribble = cmd_next->host_scribble;
-	cmd_next->done(cmd_next);
-	unpause_sequencer(p, TRUE);
-	restore_flags(processor_flags);
-	return(SCSI_RESET_SUCCESS);
+        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+          printk(INFO_LEAD "Reset, found cmd on completeq"
+          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_RESET_NOT_RUNNING);
       }
       cmd_prev = cmd_next;
       cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
     }
     if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
     {
-      if (aic7xxx_verbose)
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset, cmd not found,"
-	  " failing.\n", p->host_no, CTL_OF_CMD(cmd));
-      unpause_sequencer(p, TRUE);
-      restore_flags(processor_flags);
+      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "Reset, cmd not found,"
+          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(SCSI_RESET_NOT_RUNNING);
     }
     else
     {
-      if (aic7xxx_verbose)
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called, no scb, "
+      if (aic7xxx_verbose & VERBOSE_RESET_MID)
+        printk(INFO_LEAD "Reset called, no scb, "
           "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
       scb = NULL;
       action = HOST_RESET;
@@ -7600,9 +8877,18 @@
   }
   else
   {
-    if (aic7xxx_verbose)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called, scb %d, flags "
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called, scb %d, flags "
         "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
+    {
+      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
+          CTL_OF_SCB(scb));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_NOT_RUNNING);
+    }
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
       action = HOST_RESET;
@@ -7616,58 +8902,65 @@
       action = DEVICE_RESET;
     }
   }
-  if ( ((jiffies - p->last_reset) < (HZ * AIC7XXX_RESET_DELAY)) &&
-    (action & (HOST_RESET | BUS_RESET | DEVICE_RESET)) )
+  if ( (action & DEVICE_RESET) && 
+        (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
   {
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called too soon after "
-	"last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = RESET_DELAY;
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Bus device reset already sent to "
+        "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
   }
-  if ( ((jiffies - p->device_status[tindex].last_reset) < 
-	(HZ * AIC7XXX_RESET_DELAY)) && !(action & (HOST_RESET | BUS_RESET)))
+  if ( (action & DEVICE_RESET) &&
+       (scb->flags & SCB_QUEUED_ABORT) )
   {
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called too soon after last "
-	"reset without requesting\n"
-	"(scsi%d:%d:%d:%d) bus or host reset, escalating.\n", p->host_no,
-	CTL_OF_CMD(cmd), p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Have already attempted to reach "
+        "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "message, will escalate to bus "
+        "reset.\n", p->host_no, CTL_OF_CMD(cmd));
+    }
     action = BUS_RESET;
   }
   if ( (action & DEVICE_RESET) && 
-	(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING) )
+       (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset already sent to "
-	"device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+     printk(INFO_LEAD "Bus device reset stupid when "
+        "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
     action = BUS_RESET;
   }
-  if ( (action & DEVICE_RESET) &&
-       (scb->flags & SCB_QUEUED_ABORT) )
+  if ( (action & BUS_RESET) && !(p->type & AHC_TWIN) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Have already attempted to reach "
-	"device with queued\n(scsi%d:%d:%d:%d) message, will escalate to bus "
-	"reset.\n", p->host_no, CTL_OF_CMD(cmd), p->host_no, CTL_OF_CMD(cmd));
-    action = BUS_RESET;
+    action = HOST_RESET;
   }
-  if ( (action & DEVICE_RESET) && (p->flags & (RESET_PENDING | ABORT_PENDING)) )
+  if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+       !(action & (HOST_RESET | BUS_RESET)))
   {
-    if (aic7xxx_verbose > 2)
-     printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset stupid when "
-	"other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Reset called too soon after last "
+        "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
+        CTL_OF_CMD(cmd));
+    }
     action = BUS_RESET;
   }
-  if ( (action & BUS_RESET) && (p->bus_type != AIC_TWIN) )
+  if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
+        (action & (HOST_RESET | BUS_RESET)) )
   {
-    action = HOST_RESET;
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Reset called too soon after "
+        "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = RESET_DELAY;
   }
-  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & RESET_PENDING)
-	&& ((jiffies - p->reset_start) > (2 * HZ * AIC7XXX_RESET_DELAY)) )
+  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
+        && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
   {
     printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!!  Card must have left to go "
-	"back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
-    restore_flags(processor_flags);
+        "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_RESET_SNOOZE);
   }
 /*
@@ -7677,35 +8970,41 @@
   switch (action)
   {
     case RESET_DELAY:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(SCSI_RESET_PENDING);
       break;
     case FAIL:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(SCSI_RESET_ERROR);
       break;
     case DEVICE_RESET:
-      p->flags |= RESET_PENDING;
+      p->flags |= AHC_IN_RESET;
       result = aic7xxx_bus_device_reset(p, cmd);
       aic7xxx_run_done_queue(p, TRUE);
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
       aic7xxx_run_waiting_queues(p);
-      p->flags &= ~RESET_PENDING;
-      restore_flags(processor_flags);
+      unpause_sequencer(p, FALSE);
+      p->flags &= ~AHC_IN_RESET;
+      DRIVER_UNLOCK
       return(result);
       break;
     case BUS_RESET:
     case HOST_RESET:
     default:
       p->reset_start = jiffies;
-      p->flags |= RESET_PENDING;
-      aic7xxx_reset_channel(p, channel, TRUE);
-      if ( (p->bus_type == AIC_TWIN) && (action & HOST_RESET) )
+      p->flags |= AHC_IN_RESET;
+      aic7xxx_reset_channel(p, cmd->channel, TRUE);
+      if ( (p->type & AHC_TWIN) && (action & HOST_RESET) )
       {
-        aic7xxx_reset_channel(p, (channel == 'A') ? 'B' : 'A', TRUE);
+        aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
         restart_sequencer(p);
-	pause_sequencer(p);
       }
       if (scb == NULL)
       {
-	cmd->result = DID_RESET << 16;
+        cmd->result = DID_RESET << 16;
         cmd->done(cmd);
       }
       p->last_reset = jiffies;
@@ -7714,13 +9013,21 @@
       else
       {
         result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-        while (inb(p->base + QOUTCNT)) inb(p->base + QOUTFIFO);
-        if (p->flags & PAGE_ENABLED) outb(0, p->base + CMDOUTCNT);
+        aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
+          SIMODE1);
         aic7xxx_clear_intstat(p);
+        p->flags &= ~AHC_HANDLING_REQINITS;
+        p->msg_type = MSG_TYPE_NONE;
+        p->msg_index = 0;
+        p->msg_len = 0;
       }
-      p->flags &= ~RESET_PENDING;
+      aic7xxx_run_done_queue(p, TRUE);
+      p->flags &= ~AHC_IN_RESET;
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
       aic7xxx_run_waiting_queues(p);
-      restore_flags(processor_flags);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(result);
       break;
   }
@@ -7750,7 +9057,7 @@
   sectors = 32;
   cylinders = disk->capacity / (heads * sectors);
 
-  if ((p->flags & EXTENDED_TRANSLATION) && (cylinders > 1024))
+  if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
   {
     heads = 255;
     sectors = 63;
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h
--- v2.0.33/linux/drivers/scsi/aic7xxx.h	Tue Mar 10 13:19:09 1998
+++ linux/drivers/scsi/aic7xxx.h	Wed Jun  3 15:17:48 1998
@@ -23,35 +23,81 @@
 #ifndef _aic7xxx_h
 #define _aic7xxx_h
 
-#define AIC7XXX_H_VERSION  "$Revision: 3.2.1 $"
+#define AIC7XXX_H_VERSION  "3.2.4"
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if defined(__i386__)
+#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
+#else
+#  define AIC7XXX_BIOSPARAM NULL
+#endif
 
 /*
  * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
  * to do with card config are filled in after the card is detected.
  */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
+#define AIC7XXX	{						\
+	next: NULL,						\
+	module: NULL,						\
+	proc_dir: NULL,						\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: NULL,						\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	eh_strategy_handler: NULL,				\
+	eh_abort_handler: NULL,					\
+	eh_device_reset_handler: NULL,				\
+	eh_bus_reset_handler: NULL,				\
+	eh_host_reset_handler: NULL,				\
+	abort: aic7xxx_abort,					\
+	reset: aic7xxx_reset,					\
+	slave_attach: NULL,					\
+	bios_param: AIC7XXX_BIOSPARAM,				\
+	can_queue: 255,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING,			\
+	use_new_eh_code: 0					\
+}
+#else
 #define AIC7XXX	{						\
-	NULL,							\
-	NULL,							\
-	NULL,							\
-	aic7xxx_proc_info,					\
-	NULL,							\
-	aic7xxx_detect,						\
-	NULL,							\
-	aic7xxx_info,						\
-	NULL,							\
-	aic7xxx_queue,						\
-	aic7xxx_abort,						\
-	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					\
+	next: NULL,						\
+	usage_count: NULL,					\
+	proc_dir: NULL, 					\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: NULL,						\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	abort: aic7xxx_abort,					\
+	reset: aic7xxx_reset,					\
+	slave_attach: NULL,					\
+	bios_param: AIC7XXX_BIOSPARAM,				\
+	can_queue: 255,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING			\
 }
+#endif
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
 extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.0.33/linux/drivers/scsi/aic7xxx_proc.c	Tue Dec  2 13:52:32 1997
+++ linux/drivers/scsi/aic7xxx_proc.c	Wed Jun  3 15:17:48 1998
@@ -53,9 +53,6 @@
 
 static int aic7xxx_buffer_size = 0;
 static char *aic7xxx_buffer = NULL;
-static const char *bus_names[] = { "Single", "Twin", "Wide" };
-static const char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
-   "AIC-787x", "AIC-788x" };
 
 
 /*+F*************************************************************************
@@ -86,7 +83,6 @@
 {
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
-  int    found = FALSE;
   int    size = 0;
   unsigned char i;
 #ifdef AIC7XXX_PROC_STATS
@@ -95,36 +91,11 @@
 #endif
 
   HBAptr = NULL;
-  for (i=0; i < NUMBER(aic7xxx_boards); i++)
-  {
-    if ((HBAptr = aic7xxx_boards[i]) != NULL)
-    {
-      if (HBAptr->host_no == hostno)
-      {
-        break;
-      }
 
-      while ((HBAptr->hostdata != NULL) && !found &&
-          ((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
-      {
-        if (HBAptr->host_no == hostno)
-        {
-          found = TRUE;
-        }
-      }
+  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
+    ;
 
-      if (!found)
-      {
-        HBAptr = NULL;
-      }
-      else
-      {
-        break;
-      }
-    }
-  }
-
-  if (HBAptr == NULL)
+  if (!p)
   {
     size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
     if (size > length)
@@ -137,6 +108,8 @@
     }
   }
 
+  HBAptr = p->host;
+
   if (inout == TRUE) /* Has data been written to the file? */ 
   {
     return (aic7xxx_set_info(buffer, length, HBAptr));
@@ -150,16 +123,20 @@
    * if proc_stats is defined, then we sweep the stats structure to see
    * how many drives we will be printing out for and add 384 bytes per
    * device with active stats.
+   *
+   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+   * can be easily viewed for debugging purposes.  So, we bumped that
+   * 1.5k to 4k so we can quit having to bump it all the time.
    */
 
-  size = 1536;
+  size = 4096;
 #ifdef AIC7XXX_PROC_STATS
   for (target = 0; target < MAX_TARGETS; target++)
   {
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
       if (p->stats[target][lun].xfers != 0)
-        size += 384;
+        size += 512;
     }
   }
 #endif
@@ -182,29 +159,20 @@
 
   size = 0;
   size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
-  size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
-  size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
-#if 0
-  size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
-#endif
+  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
 #ifdef AIC7XXX_RESET_DELAY
   size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
 #endif
-#ifdef AIC7XXX_CMDS_PER_LUN
-  size += sprintf(BLS, "  AIC7XXX_CMDS_PER_LUN   : %d\n", AIC7XXX_CMDS_PER_LUN);
-#endif
-#ifdef AIC7XXX_TAGGED_QUEUEING
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Disabled\n");
-#endif
-#ifdef AIC7XXX_PAGE_ENABLE
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Disabled\n");
-#endif
+  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
+  size += sprintf(BLS, "                             Check below to see "
+                       "which\n"
+                       "                             devices use tagged "
+                       "queueing\n");
+  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled (This is no longer "
+                       "an option)\n");
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
 #else
@@ -213,17 +181,54 @@
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
   size += sprintf(BLS, "           SCSI Adapter: %s\n",
-      board_names[p->chip_type]);
-  size += sprintf(BLS, "                         (%s chipset)\n",
-      chip_names[p->chip_class]);
-  size += sprintf(BLS, "               Host Bus: %s\n", bus_names[p->bus_type]);
-  size += sprintf(BLS, "                Base IO: %#.4x\n", p->base);
-  size += sprintf(BLS, "         Base IO Memory: 0x%x\n", p->mbase);
+      board_names[p->board_name_index]);
+  if (p->flags & AHC_TWIN)
+    size += sprintf(BLS, "                         Twin Channel\n");
+  else
+  {
+    char *channel = "";
+    char *ultra = "";
+    char *wide = "Narrow ";
+    if (p->flags & AHC_MULTI_CHANNEL)
+    {
+      channel = " Channel A";
+      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+    }
+    if (p->type & AHC_WIDE)
+      wide = "Wide ";
+    if (p->type & AHC_ULTRA)
+      ultra = "Ultra ";
+    size += sprintf(BLS, "                           %s%sController%s\n",
+      ultra, wide, channel);
+  }
+  if( !(p->maddr) )
+  {
+    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+  }
+  else
+  {
+    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+  }
+  if( !(p->type & AHC_AIC78x0) )
+  {
+    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+    size += sprintf(BLS, "                         %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
+  else
+  {
+    size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
   size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
-  size += sprintf(BLS, "                   SCBs: Used %d, HW %d, Page %d\n",
-      p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
-  size += sprintf(BLS, "             Interrupts: %d", p->isr_count);
-  if (p->chip_class == AIC_777x)
+  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+            p->activescbs, p->max_activescbs);
+  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+            p->scb_data->maxscbs);
+  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+  if (p->type & AHC_AIC7770)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
@@ -232,16 +237,39 @@
   {
     size += sprintf(BLS, "\n");
   }
-  size += sprintf(BLS, "          Serial EEPROM: %s\n",
-      (p->flags & HAVE_SEEPROM) ? "True" : "False");
+  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+            p->bios_control);
+  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+            p->adapter_control);
   size += sprintf(BLS, "   Extended Translation: %sabled\n",
-      (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis");
+      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
   size += sprintf(BLS, "         SCSI Bus Reset: %sabled\n",
       aic7xxx_no_reset ? "Dis" : "En");
-  size += sprintf(BLS, "             Ultra SCSI: %sabled\n",
-      (p->flags & ULTRA_ENABLED) ? "En" : "Dis");
-  size += sprintf(BLS, "Disconnect Enable Flags: 0x%x\n", p->discenable);
-  
+  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+  if (p->type & AHC_ULTRA)
+  {
+    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+  }
+  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+#ifdef AIC7XXX_CMDS_PER_LUN
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
+#else
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
+#endif
+  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Statistics:\n");
@@ -254,15 +282,15 @@
       {
         continue;
       }
-      if (p->bus_type == AIC_TWIN)
+      if (p->type & AHC_TWIN)
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A' + (target >> 3), (target & 0x7), lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, (target >> 3), (target & 0x7), lun);
       }
       else
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A', target, lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, 0, target, lun);
       }
       size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n",
           sp->xfers, sp->r_total, sp->w_total);
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v2.0.33/linux/drivers/scsi/aic7xxx_reg.h	Tue Mar 10 13:19:09 1998
+++ linux/drivers/scsi/aic7xxx_reg.h	Wed Jun  3 15:17:48 1998
@@ -147,6 +147,16 @@
 #define		SELID_MASK      	0xf0
 #define		ONEBIT          	0x08
 
+#define	SPIOCAP         		0x1b
+#define		SOFT1           	0x80
+#define		SOFT0           	0x40
+#define		SOFTCMDEN       	0x20
+#define		HAS_BRDCTL      	0x10
+#define		SEEPROM         	0x08
+#define		EEPROM          	0x04
+#define		ROM             	0x02
+#define		SSPIOCPS        	0x01
+
 #define	BRDCTL          		0x1d
 #define		BRDDAT7         	0x80
 #define		BRDDAT6         	0x40
@@ -181,11 +191,9 @@
 
 #define	DISC_DSB        		0x32
 
-#define	MSG_LEN         		0x34
-
-#define	MSG_OUT         		0x35
+#define	MSG_OUT         		0x34
 
-#define	DMAPARAMS       		0x3d
+#define	DMAPARAMS       		0x35
 #define		WIDEODD         	0x40
 #define		SCSIEN          	0x20
 #define		SDMAENACK       	0x10
@@ -196,36 +204,21 @@
 #define		FIFOFLUSH       	0x02
 #define		FIFORESET       	0x01
 
-#define	SCBCOUNT        		0x3e
-
-#define	COMP_SCBCOUNT   		0x3f
-
-#define	QCNTMASK        		0x40
-
-#define	SEQ_FLAGS       		0x41
-#define		RESELECTED      	0x80
-#define		IDENTIFY_SEEN   	0x40
-#define		TAGGED_SCB      	0x20
+#define	SEQ_FLAGS       		0x36
+#define		IDENTIFY_SEEN   	0x80
+#define		SCBPTR_VALID    	0x20
 #define		DPHASE          	0x10
-#define		PAGESCBS        	0x04
+#define		AMTARGET        	0x08
 #define		WIDE_BUS        	0x02
 #define		TWIN_BUS        	0x01
 
-#define	SAVED_TCL       		0x42
+#define	SAVED_TCL       		0x37
 
-#define	SG_COUNT        		0x43
+#define	SG_COUNT        		0x38
 
-#define	SG_NEXT         		0x44
+#define	SG_NEXT         		0x39
 
-#define	WAITING_SCBH    		0x48
-
-#define	SAVED_LINKPTR   		0x49
-
-#define	SAVED_SCBPTR    		0x4a
-
-#define	REJBYTE         		0x4b
-
-#define	LASTPHASE       		0x4c
+#define	LASTPHASE       		0x3d
 #define		P_MESGIN        	0xe0
 #define		PHASE_MASK      	0xe0
 #define		P_STATUS        	0xc0
@@ -238,34 +231,40 @@
 #define		P_BUSFREE       	0x01
 #define		P_DATAOUT       	0x00
 
-#define	MSGIN_EXT_LEN   		0x4d
+#define	WAITING_SCBH    		0x3e
+
+#define	DISCONNECTED_SCBH		0x3f
 
-#define	MSGIN_EXT_OPCODE		0x4e
+#define	FREE_SCBH       		0x40
 
-#define	MSGIN_EXT_BYTES 		0x4f
+#define	HSCB_ADDR       		0x41
 
-#define	DISCONNECTED_SCBH		0x52
+#define	SCBID_ADDR      		0x45
 
-#define	FREE_SCBH       		0x53
+#define	TMODE_CMDADDR   		0x49
 
-#define	HSCB_ADDR       		0x54
+#define	KERNEL_QINPOS   		0x4d
 
-#define	CUR_SCBID       		0x58
+#define	QINPOS          		0x4e
 
-#define	ARG_1           		0x59
-#define	RETURN_1        		0x59
+#define	QOUTPOS         		0x4f
+
+#define	TMODE_CMDADDR_NEXT		0x50
+
+#define	ARG_1           		0x51
+#define	RETURN_1        		0x51
 #define		SEND_MSG        	0x80
 #define		SEND_SENSE      	0x40
 #define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
 
-#define	SCSICONF        		0x5a
-
-#define	CMDOUTCNT       		0x5a
-
-#define	FIFODEPTH       		0x5b
+#define	LAST_MSG        		0x52
 
-#define	SCSICONF2       		0x5b
+#define	SCSICONF        		0x5a
+#define		TERM_ENB        	0x80
 #define		RESET_SCSI      	0x40
+#define		HWSCSIID        	0x0f
+#define		HSCSIID         	0x07
 
 #define	HOSTCONF        		0x5d
 
@@ -356,13 +355,13 @@
 #define		SEQINT_MASK     	0xf1
 #define		DATA_OVERRUN    	0xe1
 #define		MSGIN_PHASEMIS  	0xd1
-#define		MSG_BUFFER_BUSY 	0xc1
+#define		TRACEPOINT2     	0xc1
+#define		TRACEPOINT      	0xb1
 #define		AWAITING_MSG    	0xa1
-#define		ABORT_CMDCMPLT  	0x91
 #define		RESIDUAL        	0x81
 #define		BAD_STATUS      	0x71
 #define		REJECT_MSG      	0x61
-#define		NO_MATCH_BUSY   	0x51
+#define		ABORT_REQUESTED 	0x51
 #define		EXTENDED_MSG    	0x41
 #define		NO_MATCH        	0x31
 #define		NO_IDENT        	0x21
@@ -375,13 +374,17 @@
 #define		SEQINT          	0x01
 
 #define	CLRINT          		0x92
+#define		CLRPARERR       	0x10
 #define		CLRBRKADRINT    	0x08
 #define		CLRSCSIINT      	0x04
 #define		CLRCMDINT       	0x02
 #define		CLRSEQINT       	0x01
 
 #define	ERROR           		0x92
-#define		PARERR          	0x08
+#define		PCIERRSTAT      	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
 #define		ILLOPCODE       	0x04
 #define		ILLSADDR        	0x02
 #define		ILLHADDR        	0x01
@@ -414,8 +417,6 @@
 #define		MK_MESSAGE      	0x80
 #define		DISCENB         	0x40
 #define		TAG_ENB         	0x20
-#define		MUST_DMAUP_SCB  	0x10
-#define		ABORT_SCB       	0x08
 #define		DISCONNECTED    	0x04
 #define		SCB_TAG_TYPE    	0x03
 
@@ -440,8 +441,6 @@
 
 #define	SCB_DATACNT     		0xb0
 
-#define	SCB_LINKED_NEXT 		0xb3
-
 #define	SCB_CMDPTR      		0xb4
 
 #define	SCB_CMDLEN      		0xb8
@@ -466,10 +465,24 @@
 #define		DI_2840         	0x01
 
 
+#define	CMD_GROUP_CODE_SHIFT	0x05
 #define	BUS_8_BIT	0x00
+#define	QOUTFIFO_OFFSET	0x01
+#define	CMD_GROUP2_BYTE_DELTA	0xfa
 #define	MAX_OFFSET_8BIT	0x0f
 #define	BUS_16_BIT	0x01
+#define	QINFIFO_OFFSET	0x02
+#define	CMD_GROUP5_BYTE_DELTA	0x0b
 #define	MAX_OFFSET_16BIT	0x08
+#define	UNTAGGEDSCB_OFFSET	0x00
 #define	SCB_LIST_NULL	0xff
 #define	SG_SIZEOF	0x08
+#define	CMD_GROUP4_BYTE_DELTA	0x04
+#define	CMD_GROUP0_BYTE_DELTA	0xfc
+#define	HOST_MSG	0xff
 #define	BUS_32_BIT	0x02
+
+
+/* Downloaded Constant Definitions */
+#define	TMODE_NUMCMDS	0x01
+#define	QCNTMASK	0x00
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/aic7xxx_seq.h linux/drivers/scsi/aic7xxx_seq.h
--- v2.0.33/linux/drivers/scsi/aic7xxx_seq.h	Tue Mar 10 13:19:09 1998
+++ linux/drivers/scsi/aic7xxx_seq.h	Wed Jun  3 15:17:48 1998
@@ -1,54 +1,39 @@
 /*
   * DO NOT EDIT - This file is automatically generated.
   */
-static u_int8_t seqprog[] = {
+static unsigned char seqprog[] = {
 	0xff, 0x6a, 0x03, 0x02,
+	0x32, 0x6a, 0x00, 0x00,
 	0x12, 0x6a, 0x00, 0x00,
-	0x00, 0x65, 0x6f, 0x16,
-	0x40, 0x0b, 0x3c, 0x1a,
-	0x20, 0x0b, 0x37, 0x1a,
-	0x40, 0x00, 0x03, 0x1a,
+	0x00, 0x65, 0x92, 0x16,
+	0xf7, 0x01, 0x01, 0x02,
+	0xff, 0x4e, 0x64, 0x02,
+	0xbf, 0x60, 0x60, 0x02,
+	0x60, 0x0b, 0x37, 0x1a,
+	0x40, 0x00, 0x05, 0x1a,
 	0x08, 0x1f, 0x1f, 0x04,
-	0x40, 0x0b, 0x3c, 0x1a,
-	0x20, 0x0b, 0x37, 0x1a,
-	0x40, 0x00, 0x03, 0x1a,
+	0x60, 0x0b, 0x37, 0x1a,
+	0x40, 0x00, 0x05, 0x1a,
 	0x08, 0x1f, 0x1f, 0x04,
-	0xff, 0x48, 0x2c, 0x18,
-	0xff, 0x40, 0x64, 0x02,
-	0x00, 0x9c, 0x03, 0x1e,
-	0x00, 0x6a, 0xad, 0x17,
-	0xff, 0x65, 0x03, 0x1c,
-	0xff, 0x9b, 0x58, 0x02,
-	0xff, 0x58, 0x90, 0x02,
-	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0x58, 0x77, 0x17,
-	0x28, 0xa0, 0x2a, 0x1a,
-	0x50, 0x6a, 0x60, 0x00,
-	0xff, 0x90, 0x4a, 0x02,
-	0x00, 0xa1, 0xa1, 0x17,
-	0xff, 0x6c, 0x59, 0x02,
-	0xff, 0x59, 0x27, 0x1c,
-	0xff, 0x4a, 0x90, 0x02,
-	0x00, 0x65, 0xaa, 0x17,
-	0x00, 0x6a, 0x52, 0x17,
-	0xff, 0x65, 0x1f, 0x18,
-	0x51, 0x6a, 0x91, 0x00,
-	0xff, 0x58, 0xb3, 0x02,
-	0x00, 0x65, 0xb6, 0x17,
-	0x10, 0x6a, 0x60, 0x00,
-	0x00, 0x65, 0x03, 0x10,
-	0xff, 0x59, 0x90, 0x02,
-	0xff, 0x58, 0xb3, 0x02,
-	0x10, 0x6a, 0x60, 0x00,
-	0x00, 0x65, 0x03, 0x10,
-	0xff, 0x58, 0x6d, 0x02,
-	0xff, 0x4a, 0x90, 0x02,
-	0x10, 0x6a, 0x60, 0x00,
-	0xff, 0x48, 0xba, 0x02,
-	0xff, 0x90, 0x48, 0x02,
-	0xff, 0x48, 0x90, 0x02,
-	0x00, 0x65, 0x2f, 0x16,
-	0x00, 0x65, 0x03, 0x10,
+	0xff, 0x3e, 0x1d, 0x18,
+	0x40, 0x60, 0x60, 0x00,
+	0x00, 0x4d, 0x06, 0x1c,
+	0x01, 0x4e, 0x4e, 0x06,
+	0xbf, 0x60, 0x60, 0x02,
+	0x00, 0x6a, 0xd8, 0x17,
+	0xff, 0x4e, 0x64, 0x06,
+	0x02, 0x6a, 0x93, 0x17,
+	0x0d, 0x6a, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0xff, 0x99, 0x65, 0x02,
+	0xff, 0x65, 0x90, 0x02,
+	0x0d, 0x6a, 0x35, 0x00,
+	0x00, 0x65, 0xb3, 0x17,
+	0xff, 0x3e, 0xba, 0x02,
+	0xff, 0x90, 0x3e, 0x02,
+	0xff, 0x3e, 0x90, 0x02,
+	0x00, 0x65, 0x20, 0x16,
+	0x00, 0x65, 0x05, 0x10,
 	0xf7, 0x1f, 0x65, 0x02,
 	0x08, 0xa1, 0x64, 0x02,
 	0x00, 0x65, 0x65, 0x00,
@@ -57,316 +42,381 @@
 	0x0f, 0x05, 0x05, 0x02,
 	0x00, 0x05, 0x05, 0x00,
 	0x5a, 0x6a, 0x00, 0x01,
-	0xff, 0x6a, 0x34, 0x02,
-	0x20, 0x6a, 0x0b, 0x00,
-	0xf0, 0x19, 0x42, 0x02,
-	0x80, 0x41, 0x41, 0x00,
-	0x00, 0x65, 0x4c, 0x10,
-	0x12, 0x6a, 0x00, 0x00,
-	0x40, 0x6a, 0x0b, 0x00,
-	0xff, 0x48, 0x90, 0x02,
-	0xff, 0xba, 0x48, 0x02,
-	0xff, 0xa1, 0x42, 0x02,
-	0x07, 0xa1, 0x35, 0x02,
-	0x40, 0xa0, 0x64, 0x02,
-	0x00, 0x35, 0x35, 0x00,
-	0x80, 0x35, 0x35, 0x00,
-	0x01, 0x6a, 0x34, 0x00,
-	0x20, 0xa0, 0x4a, 0x1e,
-	0x23, 0xa0, 0x36, 0x02,
-	0xff, 0xb9, 0x37, 0x02,
-	0x02, 0x34, 0x34, 0x06,
-	0x80, 0xa0, 0x4c, 0x1e,
-	0xa1, 0x6a, 0x91, 0x00,
-	0x08, 0x6a, 0x0c, 0x00,
-	0x08, 0x11, 0x11, 0x00,
-	0x1a, 0x01, 0x01, 0x00,
+	0x12, 0x65, 0x64, 0x00,
+	0x00, 0x01, 0x01, 0x00,
 	0x31, 0x6a, 0x65, 0x00,
-	0x80, 0x42, 0x52, 0x1a,
+	0x80, 0x37, 0x2d, 0x1a,
 	0xff, 0x65, 0x65, 0x06,
-	0xff, 0x42, 0x6e, 0x02,
+	0xff, 0x37, 0x6e, 0x02,
 	0xff, 0x6e, 0x64, 0x02,
-	0x00, 0x6c, 0x56, 0x1e,
+	0x00, 0x6c, 0x31, 0x1e,
 	0x20, 0x01, 0x01, 0x00,
-	0x4c, 0x42, 0x64, 0x0a,
-	0x08, 0x1f, 0x5a, 0x1e,
-	0x08, 0x42, 0x42, 0x00,
+	0x4c, 0x37, 0x64, 0x0a,
+	0x08, 0x1f, 0x35, 0x1e,
+	0x08, 0x37, 0x37, 0x00,
 	0x08, 0x64, 0x64, 0x00,
 	0x20, 0x64, 0x65, 0x06,
-	0xff, 0x6c, 0x04, 0x02,
-	0x01, 0x0c, 0x5c, 0x1e,
-	0x04, 0x0c, 0x5c, 0x1a,
-	0xe0, 0x03, 0x64, 0x02,
-	0xff, 0x64, 0x4c, 0x02,
-	0xff, 0x64, 0x03, 0x02,
-	0x00, 0x6a, 0x74, 0x1c,
-	0x40, 0x64, 0x79, 0x1c,
-	0x80, 0x64, 0xa5, 0x1c,
-	0xa0, 0x64, 0xb0, 0x1c,
-	0xc0, 0x64, 0xad, 0x1c,
-	0xe0, 0x64, 0xc3, 0x1c,
+	0xff, 0x6c, 0x04, 0x03,
+	0x40, 0x0b, 0x78, 0x1a,
+	0x80, 0x0b, 0x71, 0x1e,
+	0xa4, 0x6a, 0x03, 0x00,
+	0x40, 0x6a, 0x0b, 0x00,
+	0x10, 0x03, 0x6f, 0x1e,
+	0xff, 0x50, 0x64, 0x02,
+	0x49, 0x6a, 0xa9, 0x17,
+	0x01, 0x6a, 0x93, 0x00,
+	0xff, 0x6a, 0x65, 0x02,
+	0x08, 0x01, 0x01, 0x00,
+	0x02, 0x0b, 0x41, 0x1e,
+	0xf7, 0x01, 0x01, 0x02,
+	0xff, 0x06, 0x66, 0x02,
+	0xff, 0x66, 0x99, 0x02,
+	0x01, 0x65, 0x65, 0x06,
+	0x80, 0x66, 0x48, 0x1e,
+	0xff, 0x66, 0x51, 0x02,
+	0x10, 0x03, 0x40, 0x1a,
+	0xfc, 0x65, 0x64, 0x06,
+	0x00, 0x65, 0x4c, 0x12,
+	0xff, 0x6a, 0x99, 0x00,
+	0x01, 0x64, 0x8c, 0x06,
+	0x84, 0x6a, 0x03, 0x00,
+	0x08, 0x01, 0x01, 0x00,
+	0x02, 0x0b, 0x4f, 0x1e,
+	0xff, 0x06, 0x64, 0x02,
+	0xff, 0x64, 0x99, 0x02,
+	0xff, 0x6a, 0x65, 0x02,
+	0x5b, 0x64, 0x64, 0x0a,
+	0x00, 0x62, 0x62, 0x06,
+	0xfc, 0x65, 0x65, 0x06,
+	0xff, 0x6a, 0x6a, 0x02,
+	0xfa, 0x65, 0x65, 0x06,
+	0xff, 0x6a, 0x6a, 0x02,
+	0x04, 0x65, 0x65, 0x06,
+	0x0b, 0x65, 0x65, 0x06,
+	0xff, 0x65, 0x64, 0x02,
+	0x00, 0x8c, 0x8c, 0x06,
+	0x02, 0x0b, 0x5d, 0x1e,
+	0x01, 0x65, 0x60, 0x18,
+	0xf7, 0x01, 0x01, 0x02,
+	0xff, 0x06, 0x99, 0x02,
+	0xff, 0x65, 0x65, 0x06,
+	0xff, 0x65, 0x5d, 0x1a,
+	0x0a, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0x40, 0x51, 0x69, 0x1e,
+	0xe4, 0x6a, 0x03, 0x00,
+	0x08, 0x01, 0x01, 0x00,
+	0x04, 0x6a, 0x5c, 0x17,
+	0x01, 0x50, 0x50, 0x06,
+	0x01, 0x50, 0x6c, 0x98,
+	0xff, 0x6a, 0x50, 0x02,
+	0xff, 0x6a, 0x9d, 0x00,
+	0x02, 0x6a, 0x91, 0x00,
+	0x40, 0x51, 0x6f, 0x1a,
+	0xff, 0x6a, 0x03, 0x02,
+	0x00, 0x65, 0x05, 0x10,
+	0x20, 0x6a, 0x0b, 0x00,
+	0xf0, 0x19, 0x37, 0x02,
+	0x08, 0x6a, 0x0c, 0x00,
+	0x08, 0x11, 0x11, 0x00,
+	0x08, 0x6a, 0x28, 0x16,
+	0x08, 0x6a, 0x34, 0x00,
+	0x00, 0x65, 0x82, 0x10,
+	0x12, 0x6a, 0x00, 0x00,
+	0x40, 0x6a, 0x0b, 0x00,
+	0xff, 0x3e, 0x90, 0x02,
+	0xff, 0xba, 0x3e, 0x02,
+	0xff, 0xa1, 0x37, 0x02,
+	0x08, 0x6a, 0x0c, 0x00,
+	0x08, 0x11, 0x11, 0x00,
+	0x08, 0x6a, 0x28, 0x16,
+	0x80, 0x6a, 0x34, 0x00,
+	0x80, 0x36, 0x36, 0x00,
+	0x00, 0x65, 0x9b, 0x17,
+	0xff, 0x3d, 0x64, 0x02,
+	0xbf, 0x64, 0x9a, 0x1e,
+	0x80, 0x64, 0xc9, 0x1c,
+	0xa0, 0x64, 0xd4, 0x1c,
+	0xc0, 0x64, 0xd1, 0x1c,
+	0xe0, 0x64, 0xf5, 0x1c,
 	0x01, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0x5c, 0x10,
+	0x00, 0x65, 0x82, 0x10,
 	0xf7, 0x11, 0x11, 0x02,
-	0x00, 0x65, 0x6f, 0x16,
+	0x00, 0x65, 0x92, 0x16,
 	0xff, 0x06, 0x6a, 0x02,
-	0x09, 0x0c, 0x6c, 0x1e,
-	0x08, 0x0c, 0x03, 0x1a,
+	0xf7, 0x01, 0x01, 0x02,
+	0x09, 0x0c, 0x8f, 0x1e,
+	0x08, 0x0c, 0x05, 0x1a,
 	0x01, 0x6a, 0x91, 0x00,
 	0xff, 0x6a, 0x93, 0x02,
 	0xff, 0x6a, 0x04, 0x02,
 	0xdf, 0x01, 0x01, 0x02,
-	0x01, 0x6a, 0x4c, 0x00,
-	0x0f, 0x41, 0x41, 0x03,
-	0x7d, 0x6a, 0x3d, 0x00,
-	0x00, 0x65, 0x7a, 0x10,
+	0x01, 0x6a, 0x3d, 0x00,
+	0x03, 0x36, 0x36, 0x03,
 	0x08, 0x6a, 0x66, 0x00,
-	0xa9, 0x6a, 0x74, 0x17,
-	0x00, 0x65, 0x82, 0x10,
-	0x79, 0x6a, 0x3d, 0x00,
-	0x00, 0x65, 0x4f, 0x17,
-	0x10, 0x41, 0x76, 0x1a,
+	0xa9, 0x6a, 0xa6, 0x17,
+	0x00, 0x65, 0xa5, 0x10,
+	0x79, 0x6a, 0x35, 0x00,
+	0x40, 0x3d, 0x9d, 0x1a,
+	0x04, 0x35, 0x35, 0x00,
+	0x00, 0x65, 0x6c, 0x17,
+	0x10, 0x36, 0x97, 0x1a,
 	0x88, 0x6a, 0x66, 0x00,
-	0xac, 0x6a, 0x70, 0x17,
-	0x00, 0x65, 0x6d, 0x17,
-	0xff, 0xa3, 0x43, 0x02,
-	0x44, 0x6a, 0x66, 0x00,
-	0xa4, 0x6a, 0x73, 0x17,
-	0xff, 0x43, 0x88, 0x1a,
+	0xac, 0x6a, 0xa2, 0x17,
+	0x00, 0x65, 0x9f, 0x17,
+	0xff, 0xa3, 0x38, 0x02,
+	0x39, 0x6a, 0x66, 0x00,
+	0xa4, 0x6a, 0xa5, 0x17,
+	0xff, 0x38, 0xac, 0x1a,
 	0x80, 0x02, 0x02, 0x00,
 	0xff, 0x6a, 0x8c, 0x00,
 	0xff, 0x6a, 0x8d, 0x00,
 	0xff, 0x6a, 0x8e, 0x00,
-	0x00, 0x65, 0x6d, 0x17,
-	0x01, 0x43, 0x8a, 0x18,
-	0xbf, 0x3d, 0x3d, 0x02,
-	0x00, 0x3d, 0x44, 0x17,
-	0x80, 0x02, 0xa2, 0x1a,
-	0xff, 0x65, 0x9c, 0x1e,
-	0xff, 0x43, 0x43, 0x06,
-	0xff, 0x43, 0x9c, 0x1e,
+	0x00, 0x65, 0x9f, 0x17,
+	0xe7, 0x35, 0x35, 0x02,
+	0x01, 0x38, 0xae, 0x18,
+	0xbf, 0x35, 0x35, 0x02,
+	0x00, 0x35, 0x61, 0x17,
+	0x80, 0x02, 0xc6, 0x1a,
+	0xff, 0x65, 0xc0, 0x1e,
+	0xff, 0x38, 0x38, 0x06,
+	0xff, 0x38, 0xc0, 0x1e,
 	0xff, 0x6a, 0x64, 0x02,
-	0x08, 0x44, 0x44, 0x06,
-	0x00, 0x45, 0x45, 0x08,
+	0x08, 0x39, 0x39, 0x06,
+	0x00, 0x3a, 0x3a, 0x08,
 	0x88, 0x6a, 0x66, 0x00,
-	0x44, 0x6a, 0x73, 0x17,
+	0x39, 0x6a, 0xa5, 0x17,
 	0x08, 0x6a, 0x8c, 0x00,
 	0xff, 0x6a, 0x8d, 0x02,
 	0xff, 0x6a, 0x8e, 0x02,
 	0x0d, 0x93, 0x93, 0x00,
-	0x00, 0x65, 0x9d, 0x17,
-	0x88, 0x6a, 0x95, 0x17,
-	0x00, 0x65, 0x6d, 0x17,
-	0x10, 0x0c, 0x82, 0x1e,
+	0x00, 0x65, 0xd1, 0x17,
+	0x88, 0x6a, 0xc9, 0x17,
+	0x00, 0x65, 0x9f, 0x17,
+	0x10, 0x0c, 0xa5, 0x1e,
 	0xff, 0x08, 0xa9, 0x02,
 	0xff, 0x09, 0xaa, 0x02,
 	0xff, 0x0a, 0xab, 0x02,
-	0xff, 0x43, 0xa8, 0x02,
-	0x10, 0x41, 0x41, 0x00,
-	0x00, 0x65, 0x5c, 0x10,
+	0xff, 0x38, 0xa8, 0x02,
+	0x10, 0x36, 0x36, 0x00,
+	0x00, 0x65, 0x82, 0x10,
 	0x7f, 0x02, 0x02, 0x02,
 	0xe1, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0x5c, 0x10,
-	0x00, 0x65, 0x4f, 0x17,
+	0x00, 0x65, 0x82, 0x10,
+	0x00, 0x65, 0x6c, 0x17,
 	0x88, 0x6a, 0x66, 0x00,
-	0xb4, 0x6a, 0x72, 0x17,
+	0xb4, 0x6a, 0xa4, 0x17,
 	0xff, 0x6a, 0x8d, 0x02,
 	0xff, 0x6a, 0x8e, 0x02,
-	0x00, 0x65, 0x6d, 0x17,
-	0x3d, 0x6a, 0x44, 0x17,
-	0x00, 0x65, 0x5c, 0x10,
-	0x00, 0x65, 0x4f, 0x17,
+	0x00, 0x65, 0x9f, 0x17,
+	0x3d, 0x6a, 0x61, 0x17,
+	0x00, 0x65, 0x82, 0x10,
+	0x00, 0x65, 0x6c, 0x17,
 	0xff, 0x06, 0xa2, 0x02,
-	0x00, 0x65, 0x5c, 0x10,
-	0xff, 0x34, 0xb2, 0x1a,
-	0x08, 0x6a, 0x32, 0x17,
-	0x35, 0x6a, 0x65, 0x00,
-	0xff, 0x34, 0x66, 0x02,
-	0x01, 0x0c, 0xb4, 0x1e,
-	0x04, 0x0c, 0xb4, 0x1a,
-	0xe0, 0x03, 0x4c, 0x02,
-	0xa0, 0x4c, 0xc0, 0x18,
-	0xff, 0x66, 0xbb, 0x1a,
-	0x10, 0x4c, 0x03, 0x00,
-	0x00, 0x65, 0xb2, 0x10,
-	0x01, 0x66, 0xbd, 0x18,
+	0x00, 0x65, 0x82, 0x10,
+	0xff, 0x34, 0x65, 0x02,
+	0x80, 0x65, 0xe6, 0x18,
+	0x0f, 0xa1, 0x65, 0x02,
+	0x07, 0xa1, 0x65, 0x02,
+	0x40, 0xa0, 0x64, 0x02,
+	0x00, 0x65, 0x65, 0x00,
+	0x80, 0x65, 0x65, 0x00,
+	0x80, 0xa0, 0xde, 0x1e,
+	0xff, 0x65, 0x06, 0x02,
+	0x00, 0x65, 0xe7, 0x10,
+	0x20, 0xa0, 0xe9, 0x1e,
+	0xff, 0x65, 0x06, 0x02,
+	0x00, 0x65, 0x9b, 0x17,
+	0xa0, 0x3d, 0xef, 0x18,
+	0x23, 0xa0, 0x06, 0x02,
+	0x00, 0x65, 0x9b, 0x17,
+	0xa0, 0x3d, 0xef, 0x18,
+	0x00, 0xb9, 0xe9, 0x10,
+	0xff, 0x65, 0xe9, 0x18,
+	0xa1, 0x6a, 0x91, 0x00,
+	0x10, 0x51, 0xef, 0x1c,
 	0x40, 0x6a, 0x0c, 0x00,
-	0xff, 0x66, 0x66, 0x06,
-	0xff, 0x6c, 0x06, 0x02,
-	0x00, 0x65, 0xb4, 0x10,
+	0xff, 0x65, 0x06, 0x02,
+	0x00, 0x65, 0x9b, 0x17,
+	0xa0, 0x3d, 0xef, 0x18,
+	0x10, 0x3d, 0x03, 0x00,
+	0x00, 0x65, 0xd4, 0x10,
 	0x40, 0x6a, 0x0c, 0x00,
-	0xff, 0x6a, 0x34, 0x02,
-	0x00, 0x65, 0x5c, 0x10,
-	0x64, 0x6a, 0x3f, 0x17,
-	0xff, 0x64, 0x4b, 0x02,
-	0x80, 0x64, 0x0e, 0x1b,
-	0x04, 0x64, 0x01, 0x1d,
-	0x02, 0x64, 0x04, 0x1d,
-	0x00, 0x6a, 0xd1, 0x1c,
-	0x03, 0x64, 0x0c, 0x1d,
-	0x01, 0x64, 0xf5, 0x1c,
-	0x07, 0x64, 0x30, 0x1d,
-	0x08, 0x64, 0xcf, 0x1c,
+	0xff, 0x34, 0x52, 0x02,
+	0x80, 0x34, 0xf3, 0x18,
+	0x7f, 0xa0, 0xa0, 0x02,
+	0x08, 0x6a, 0x34, 0x00,
+	0x00, 0x65, 0x82, 0x10,
+	0x64, 0x6a, 0x59, 0x17,
+	0x80, 0x64, 0x2f, 0x1b,
+	0x04, 0x64, 0x22, 0x1d,
+	0x02, 0x64, 0x25, 0x1d,
+	0x00, 0x6a, 0x02, 0x1d,
+	0x03, 0x64, 0x2d, 0x1d,
+	0x01, 0x64, 0x20, 0x1d,
+	0x07, 0x64, 0x50, 0x1d,
+	0x08, 0x64, 0x00, 0x1d,
 	0x11, 0x6a, 0x91, 0x00,
-	0x07, 0x6a, 0x32, 0x17,
+	0x07, 0x6a, 0x52, 0x17,
 	0xff, 0x06, 0x6a, 0x02,
-	0x00, 0x65, 0x5c, 0x10,
-	0xff, 0xa8, 0xd3, 0x1a,
-	0xff, 0xa2, 0xda, 0x1e,
-	0x01, 0x6a, 0x3d, 0x00,
-	0x00, 0xb9, 0x77, 0x17,
-	0xff, 0xa2, 0xda, 0x1e,
+	0x00, 0x65, 0x82, 0x10,
+	0xff, 0xa8, 0x04, 0x1b,
+	0xff, 0xa2, 0x0f, 0x1f,
+	0x01, 0x6a, 0x35, 0x00,
+	0x00, 0xb9, 0xb3, 0x17,
+	0xff, 0xa2, 0x0f, 0x1f,
 	0x71, 0x6a, 0x91, 0x00,
-	0x40, 0x59, 0xda, 0x18,
-	0xff, 0xb9, 0xb3, 0x02,
-	0x00, 0x65, 0xe7, 0x10,
-	0x20, 0xa0, 0xe0, 0x1a,
-	0xff, 0x90, 0x4a, 0x02,
-	0xff, 0xb3, 0x49, 0x02,
-	0x00, 0xa1, 0xa1, 0x17,
-	0xff, 0x49, 0x6d, 0x02,
-	0xff, 0x4a, 0x90, 0x02,
-	0xff, 0x5b, 0x64, 0x02,
-	0x00, 0x5a, 0xe1, 0x1c,
-	0x01, 0x5a, 0x5a, 0x06,
-	0xff, 0xb9, 0x9d, 0x02,
+	0x40, 0x51, 0x0f, 0x19,
+	0x0d, 0x6a, 0x35, 0x00,
+	0x00, 0xb9, 0xb3, 0x17,
+	0xff, 0x3e, 0xba, 0x02,
+	0xff, 0x90, 0x3e, 0x02,
+	0x00, 0x65, 0x20, 0x16,
+	0x00, 0x65, 0x8b, 0x10,
+	0x20, 0xa0, 0x16, 0x1b,
+	0xff, 0x37, 0x64, 0x02,
+	0x00, 0x6a, 0x93, 0x17,
+	0x01, 0x6a, 0x93, 0x00,
+	0xff, 0x6a, 0x99, 0x00,
+	0x0a, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0xff, 0x4f, 0x64, 0x02,
+	0x01, 0x6a, 0x93, 0x17,
+	0x01, 0x6a, 0x93, 0x00,
+	0xff, 0xb9, 0x99, 0x02,
+	0x0a, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0x01, 0x4f, 0x4f, 0x06,
 	0x02, 0x6a, 0x91, 0x00,
-	0x08, 0xa0, 0xe7, 0x1e,
-	0x91, 0x6a, 0x91, 0x00,
-	0xff, 0xb3, 0xf3, 0x1c,
-	0xff, 0xb3, 0x64, 0x02,
-	0x00, 0xb9, 0xed, 0x1c,
-	0x00, 0x65, 0xaa, 0x17,
-	0xff, 0x64, 0x90, 0x02,
-	0x00, 0x65, 0xef, 0x10,
-	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0xb3, 0x77, 0x17,
-	0xff, 0x48, 0xba, 0x02,
-	0xff, 0x90, 0x48, 0x02,
-	0x00, 0x65, 0x2f, 0x16,
-	0x00, 0x65, 0x69, 0x10,
-	0x00, 0x65, 0xaa, 0x17,
-	0x00, 0x65, 0x69, 0x10,
-	0x4d, 0x6a, 0x3a, 0x17,
-	0xff, 0x4d, 0x64, 0x02,
-	0x00, 0x66, 0x3a, 0x17,
-	0xff, 0x64, 0x64, 0x06,
-	0x52, 0x66, 0xfb, 0x18,
-	0xff, 0x66, 0x66, 0x06,
-	0xff, 0x64, 0xf7, 0x1a,
+	0x00, 0x65, 0xd5, 0x17,
+	0x00, 0x65, 0x8b, 0x10,
 	0x41, 0x6a, 0x91, 0x00,
-	0x20, 0x59, 0xcd, 0x1c,
-	0x80, 0x59, 0xcf, 0x18,
-	0x10, 0x4c, 0x03, 0x00,
-	0x00, 0x65, 0xcf, 0x10,
+	0x00, 0x65, 0x82, 0x10,
 	0x04, 0xa0, 0xa0, 0x00,
-	0x00, 0x65, 0xb6, 0x17,
-	0x00, 0x65, 0x69, 0x10,
-	0x10, 0x41, 0xcf, 0x1e,
-	0xff, 0x43, 0xa3, 0x02,
+	0x00, 0x65, 0xe1, 0x17,
+	0x00, 0x65, 0x8b, 0x10,
+	0x10, 0x36, 0x00, 0x1f,
+	0xff, 0x38, 0xa3, 0x02,
 	0xa4, 0x6a, 0x66, 0x00,
-	0x44, 0x6a, 0x73, 0x17,
+	0x39, 0x6a, 0xa5, 0x17,
 	0xac, 0x6a, 0x66, 0x00,
-	0x14, 0x6a, 0x73, 0x17,
-	0xa9, 0x6a, 0x74, 0x17,
-	0x00, 0x65, 0xcf, 0x10,
-	0xef, 0x41, 0x41, 0x02,
-	0x00, 0x65, 0xcf, 0x10,
-	0x78, 0x64, 0xcd, 0x1a,
+	0x14, 0x6a, 0xa5, 0x17,
+	0xa9, 0x6a, 0xa6, 0x17,
+	0x00, 0x65, 0x00, 0x11,
+	0xef, 0x36, 0x36, 0x02,
+	0x00, 0x65, 0x00, 0x11,
+	0x0f, 0x64, 0x64, 0x02,
 	0x07, 0x64, 0x64, 0x02,
-	0x00, 0x42, 0x42, 0x00,
-	0x00, 0x42, 0xa1, 0x17,
-	0xff, 0x6c, 0x59, 0x02,
-	0xff, 0x59, 0x28, 0x19,
-	0xff, 0x59, 0x18, 0x1d,
-	0xff, 0x59, 0x90, 0x02,
-	0x04, 0xa0, 0x2d, 0x1f,
-	0x00, 0x65, 0x2a, 0x11,
+	0x00, 0x37, 0x37, 0x00,
+	0x00, 0x65, 0x8b, 0x17,
+	0xff, 0x51, 0x37, 0x1d,
+	0x20, 0x36, 0x3f, 0x1f,
+	0x00, 0x90, 0x7d, 0x17,
+	0x00, 0x65, 0x40, 0x11,
 	0xff, 0x06, 0x6a, 0x02,
-	0x01, 0x0c, 0x19, 0x1f,
-	0x04, 0x0c, 0x19, 0x1b,
-	0xe0, 0x03, 0x4c, 0x02,
-	0xe0, 0x4c, 0x2d, 0x19,
-	0x20, 0x12, 0x2d, 0x19,
-	0x20, 0x41, 0x41, 0x00,
-	0x59, 0x6a, 0x3a, 0x17,
-	0xff, 0x3f, 0x64, 0x02,
-	0x00, 0x59, 0x65, 0x06,
-	0x00, 0x65, 0x2d, 0x13,
-	0xff, 0x59, 0x90, 0x02,
-	0xff, 0x42, 0x64, 0x02,
-	0x00, 0xa1, 0x2d, 0x19,
-	0x20, 0xa0, 0x2d, 0x1f,
-	0x04, 0xa0, 0x2d, 0x1f,
-	0x00, 0x6a, 0x52, 0x17,
-	0xff, 0x65, 0x2d, 0x1d,
+	0x00, 0x65, 0x9b, 0x17,
+	0xe0, 0x3d, 0x4d, 0x19,
+	0x20, 0x12, 0x4d, 0x19,
+	0x51, 0x6a, 0x54, 0x17,
+	0xff, 0x51, 0x90, 0x02,
+	0x20, 0xa0, 0x4d, 0x1f,
+	0x00, 0x90, 0x7d, 0x17,
+	0x00, 0x65, 0x7a, 0x17,
+	0xff, 0x37, 0x64, 0x02,
+	0x00, 0xa1, 0x49, 0x19,
+	0x04, 0xa0, 0x49, 0x1f,
 	0xfb, 0xa0, 0xa0, 0x02,
-	0x40, 0x41, 0x41, 0x00,
-	0x00, 0x65, 0xcf, 0x10,
+	0x80, 0x36, 0x36, 0x00,
+	0x80, 0xa0, 0x00, 0x1f,
+	0x7f, 0xa0, 0xa0, 0x02,
+	0xff, 0x6a, 0x52, 0x17,
+	0x00, 0x65, 0x00, 0x11,
+	0x04, 0xa0, 0x4c, 0x1f,
+	0x00, 0x65, 0xe1, 0x17,
+	0x00, 0x65, 0x4d, 0x11,
+	0x00, 0x65, 0xd5, 0x17,
 	0x31, 0x6a, 0x91, 0x00,
-	0x0c, 0x6a, 0x32, 0x17,
-	0x00, 0x65, 0xcf, 0x10,
+	0x0c, 0x6a, 0x52, 0x17,
+	0x00, 0x65, 0x00, 0x11,
 	0x61, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0xcf, 0x10,
-	0x50, 0x6a, 0x60, 0x00,
-	0xff, 0x34, 0x36, 0x1f,
-	0x10, 0x6a, 0x60, 0x00,
-	0xc1, 0x6a, 0x91, 0x00,
-	0x10, 0x4c, 0x03, 0x00,
-	0x01, 0x6a, 0x34, 0x00,
-	0xff, 0x65, 0x35, 0x02,
-	0x10, 0x6a, 0x60, 0x01,
+	0x00, 0x65, 0x00, 0x11,
+	0x10, 0x3d, 0x03, 0x00,
+	0xff, 0x65, 0x34, 0x03,
 	0xff, 0x06, 0x6a, 0x02,
-	0x01, 0x0c, 0x3b, 0x1f,
-	0x04, 0x0c, 0x3b, 0x1b,
-	0xe0, 0x03, 0x4c, 0x02,
-	0xe0, 0x4c, 0x42, 0x19,
+	0x01, 0x0c, 0x55, 0x1f,
+	0x04, 0x0c, 0x55, 0x1b,
+	0xe0, 0x03, 0x3d, 0x02,
+	0xe0, 0x3d, 0x5f, 0x19,
 	0xff, 0x65, 0x66, 0x02,
 	0xff, 0x12, 0x6d, 0x03,
 	0xff, 0x06, 0x6a, 0x03,
+	0xff, 0x65, 0x06, 0x02,
+	0x02, 0x0b, 0x5d, 0x1f,
+	0xff, 0x6a, 0x6a, 0x03,
 	0xd1, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0x5c, 0x10,
+	0x00, 0x65, 0x82, 0x10,
 	0xff, 0x65, 0x93, 0x02,
-	0x01, 0x0b, 0x4c, 0x1b,
-	0x10, 0x0c, 0x45, 0x1f,
-	0x04, 0x0b, 0x49, 0x1b,
+	0x01, 0x0b, 0x69, 0x1b,
+	0x10, 0x0c, 0x62, 0x1f,
+	0x04, 0x0b, 0x66, 0x1b,
 	0xff, 0x6a, 0x65, 0x02,
-	0x04, 0x93, 0x4b, 0x1b,
-	0x01, 0x94, 0x4a, 0x1f,
-	0x10, 0x94, 0x4b, 0x1b,
+	0x04, 0x93, 0x68, 0x1b,
+	0x01, 0x94, 0x67, 0x1f,
+	0x10, 0x94, 0x68, 0x1b,
 	0xc7, 0x93, 0x93, 0x02,
-	0x38, 0x93, 0x4d, 0x1b,
+	0x38, 0x93, 0x6a, 0x1b,
 	0xff, 0x6a, 0x6a, 0x03,
-	0x80, 0x41, 0x4e, 0x1f,
-	0x40, 0x41, 0x4e, 0x1b,
+	0x80, 0x36, 0x6b, 0x1b,
 	0x21, 0x6a, 0x91, 0x01,
 	0xff, 0x65, 0x90, 0x02,
-	0xff, 0x59, 0x64, 0x02,
-	0x00, 0xb9, 0x56, 0x19,
-	0x04, 0xa0, 0x60, 0x1b,
-	0x01, 0x65, 0x65, 0x06,
-	0xff, 0x3e, 0x64, 0x02,
-	0x00, 0x65, 0x52, 0x19,
-	0x00, 0x6a, 0xad, 0x17,
-	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0x59, 0x77, 0x17,
-	0xff, 0xa8, 0x5e, 0x1f,
-	0x10, 0xa0, 0xa0, 0x00,
-	0x08, 0xa0, 0x4e, 0x1f,
+	0xff, 0x51, 0x72, 0x19,
+	0xff, 0x37, 0x64, 0x02,
+	0xa1, 0x6a, 0x77, 0x11,
+	0xff, 0x51, 0x64, 0x02,
+	0xb9, 0x6a, 0x77, 0x11,
+	0xff, 0xba, 0x79, 0x1d,
+	0xff, 0xba, 0x90, 0x02,
+	0xff, 0x65, 0x65, 0x06,
+	0x00, 0x6c, 0x74, 0x19,
+	0xff, 0x90, 0x65, 0x03,
 	0xff, 0x6a, 0x65, 0x01,
-	0x08, 0xa0, 0x5f, 0x1b,
-	0xff, 0xba, 0x66, 0x1d,
-	0xff, 0xbb, 0x49, 0x02,
+	0x20, 0x36, 0x88, 0x1f,
+	0x00, 0x90, 0x6e, 0x17,
+	0xff, 0x65, 0x88, 0x1d,
+	0xff, 0xba, 0x82, 0x1d,
+	0xff, 0xbb, 0x66, 0x02,
 	0xff, 0xba, 0x90, 0x02,
-	0xff, 0x49, 0xbb, 0x02,
+	0xff, 0x66, 0xbb, 0x02,
 	0xff, 0x65, 0x90, 0x02,
-	0xff, 0xbb, 0x6b, 0x1d,
-	0xff, 0xba, 0x49, 0x02,
+	0xff, 0xbb, 0x87, 0x1d,
+	0xff, 0xba, 0x66, 0x02,
 	0xff, 0xbb, 0x90, 0x02,
-	0xff, 0x49, 0xba, 0x02,
+	0xff, 0x66, 0xba, 0x02,
 	0xff, 0x65, 0x90, 0x03,
-	0xff, 0xba, 0x52, 0x03,
-	0xff, 0x6a, 0x6a, 0x03,
+	0xff, 0xba, 0x3f, 0x03,
+	0x00, 0x6a, 0xd8, 0x17,
+	0x0d, 0x6a, 0x35, 0x00,
+	0x00, 0x51, 0xb3, 0x11,
+	0xff, 0x3f, 0x96, 0x1d,
+	0xff, 0x6a, 0x51, 0x00,
+	0x00, 0x3f, 0x6e, 0x17,
+	0xff, 0x65, 0x96, 0x1d,
+	0x20, 0x36, 0x36, 0x00,
+	0x20, 0xa0, 0x92, 0x1b,
+	0xff, 0xb9, 0x51, 0x03,
+	0xff, 0x6a, 0x51, 0x01,
+	0xff, 0x65, 0x66, 0x02,
+	0x45, 0x6a, 0xab, 0x17,
+	0x01, 0x6a, 0x8c, 0x01,
+	0xff, 0x37, 0x64, 0x02,
+	0x00, 0x6a, 0x93, 0x17,
+	0x0d, 0x6a, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0xff, 0x99, 0x51, 0x03,
+	0x01, 0x0c, 0x9b, 0x1f,
+	0x04, 0x0c, 0x9b, 0x1b,
+	0xe0, 0x03, 0x3d, 0x02,
+	0xff, 0x3d, 0x03, 0x03,
 	0xff, 0x8c, 0x08, 0x02,
 	0xff, 0x8d, 0x09, 0x02,
 	0xff, 0x8e, 0x0a, 0x03,
@@ -377,19 +427,21 @@
 	0xff, 0x6c, 0x6d, 0x02,
 	0xff, 0x6c, 0x6d, 0x02,
 	0xff, 0x6c, 0x6d, 0x03,
-	0x3d, 0x65, 0x66, 0x0a,
-	0x55, 0x65, 0x64, 0x0a,
-	0x00, 0x54, 0x88, 0x06,
+	0x3d, 0x64, 0x66, 0x0a,
+	0x55, 0x64, 0x64, 0x0a,
+	0x00, 0x6c, 0x88, 0x06,
 	0xff, 0x66, 0x64, 0x02,
-	0x00, 0x55, 0x89, 0x08,
+	0x00, 0x6c, 0x89, 0x08,
 	0xff, 0x6a, 0x64, 0x02,
-	0x00, 0x56, 0x8a, 0x08,
-	0x00, 0x57, 0x8b, 0x08,
-	0x1c, 0x6a, 0x8c, 0x00,
+	0x00, 0x6c, 0x8a, 0x08,
+	0x00, 0x6c, 0x8b, 0x08,
 	0xff, 0x6a, 0x8d, 0x02,
-	0xff, 0x6a, 0x8e, 0x02,
-	0xff, 0x3d, 0x93, 0x02,
-	0x04, 0x3d, 0x8f, 0x1b,
+	0xff, 0x6a, 0x8e, 0x03,
+	0xff, 0x65, 0x64, 0x02,
+	0x41, 0x6a, 0xa9, 0x17,
+	0x1c, 0x6a, 0x8c, 0x00,
+	0xff, 0x35, 0x93, 0x02,
+	0x04, 0x35, 0xc3, 0x1b,
 	0xa0, 0x6a, 0x65, 0x00,
 	0x1c, 0x65, 0x64, 0x06,
 	0xff, 0x6c, 0x99, 0x02,
@@ -399,14 +451,14 @@
 	0xff, 0x6c, 0x99, 0x02,
 	0xff, 0x6c, 0x99, 0x02,
 	0xff, 0x6c, 0x99, 0x02,
-	0x00, 0x65, 0x86, 0x19,
+	0x00, 0x65, 0xba, 0x19,
 	0x0a, 0x93, 0x93, 0x00,
-	0x00, 0x65, 0x9d, 0x17,
-	0x04, 0x3d, 0x4e, 0x1f,
-	0xa0, 0x6a, 0x95, 0x17,
-	0x00, 0x65, 0x96, 0x17,
-	0x00, 0x65, 0x96, 0x17,
-	0x00, 0x65, 0x96, 0x11,
+	0x00, 0x65, 0xd1, 0x17,
+	0x04, 0x35, 0x6b, 0x1f,
+	0xa0, 0x6a, 0xc9, 0x17,
+	0x00, 0x65, 0xca, 0x17,
+	0x00, 0x65, 0xca, 0x17,
+	0x00, 0x65, 0xca, 0x11,
 	0xff, 0x65, 0x66, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
@@ -415,64 +467,58 @@
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x03,
-	0x08, 0x94, 0x9d, 0x1f,
+	0x08, 0x94, 0xd1, 0x1f,
 	0xf7, 0x93, 0x93, 0x02,
-	0x08, 0x93, 0x9f, 0x1b,
+	0x08, 0x93, 0xd3, 0x1b,
 	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x65, 0x66, 0x02,
-	0x4c, 0x66, 0x66, 0x0a,
-	0x03, 0x66, 0x66, 0x02,
-	0xbc, 0x66, 0x66, 0x06,
-	0x6a, 0x65, 0x64, 0x0a,
-	0x08, 0x65, 0xa8, 0x1f,
-	0x02, 0x64, 0x64, 0x06,
-	0xff, 0x64, 0x90, 0x02,
-	0xff, 0x66, 0x65, 0x03,
-	0xff, 0x53, 0xba, 0x02,
-	0xff, 0x6a, 0xb9, 0x00,
-	0xff, 0x90, 0x53, 0x03,
-	0xff, 0x53, 0xb4, 0x19,
-	0xff, 0x52, 0xb0, 0x19,
+	0xff, 0x40, 0xba, 0x02,
+	0xff, 0x90, 0x40, 0x02,
+	0xff, 0x6a, 0xb9, 0x01,
+	0xff, 0x40, 0xdf, 0x19,
+	0xff, 0x3f, 0xdb, 0x19,
 	0xff, 0x6a, 0x65, 0x01,
-	0xff, 0x52, 0x90, 0x02,
-	0x01, 0x6a, 0x3d, 0x00,
-	0x00, 0xb9, 0x77, 0x17,
-	0x00, 0x90, 0x61, 0x11,
-	0xff, 0x53, 0x90, 0x02,
-	0xff, 0xba, 0x53, 0x03,
+	0xff, 0x3f, 0x90, 0x02,
+	0x01, 0x6a, 0x35, 0x00,
+	0x00, 0xb9, 0xb3, 0x17,
+	0x00, 0x90, 0x7d, 0x11,
+	0xff, 0x40, 0x90, 0x02,
+	0xff, 0xba, 0x40, 0x03,
 	0xff, 0x6a, 0xbb, 0x00,
-	0xff, 0x52, 0xba, 0x02,
-	0xff, 0x90, 0x52, 0x02,
-	0xff, 0xba, 0x4e, 0x1d,
+	0xff, 0x3f, 0xba, 0x02,
+	0xff, 0x90, 0x3f, 0x02,
+	0xff, 0xba, 0x6b, 0x1d,
 	0xff, 0xba, 0x90, 0x02,
-	0xff, 0x52, 0xbb, 0x02,
-	0xff, 0x52, 0x90, 0x03,
+	0xff, 0x3f, 0xbb, 0x02,
+	0xff, 0x3f, 0x90, 0x03,
 };
-#define	ULTRA           	0x8
-#define	SCB_PAGING      	0x4
-#define	TWIN_CHANNEL    	0x2
+#define	WIDE            	0x20
+#define	ULTRA           	0x10
+#define	SCB_PAGING      	0x8
+#define	TWIN_CHANNEL    	0x4
+#define	TARGET_MODE     	0x2
 struct patch {
 	int	options;
 	int	negative;
 	int	begin;
 	int	end;
 } patches[] = {
-	{ 0x00000002, 0, 0x006, 0x00b },
-	{ 0x00000004, 0, 0x00e, 0x010 },
-	{ 0x00000004, 1, 0x011, 0x012 },
-	{ 0x00000004, 0, 0x01a, 0x023 },
-	{ 0x00000004, 1, 0x023, 0x027 },
-	{ 0x00000002, 0, 0x02f, 0x033 },
-	{ 0x00000008, 0, 0x04f, 0x056 },
-	{ 0x00000004, 0, 0x0e0, 0x0e3 },
-	{ 0x00000004, 1, 0x0e8, 0x0ed },
-	{ 0x00000004, 0, 0x102, 0x103 },
-	{ 0x00000004, 0, 0x113, 0x114 },
-	{ 0x00000004, 1, 0x114, 0x118 },
-	{ 0x00000004, 1, 0x123, 0x128 },
-	{ 0x00000004, 0, 0x128, 0x12a },
-	{ 0x00000004, 0, 0x152, 0x16c },
-	{ 0x00000004, 1, 0x16c, 0x16d },
-	{ 0x00000004, 0, 0x1ad, 0x1bd },
+	{ 0x00000002, 0, 0x001, 0x002 },
+	{ 0x00000002, 1, 0x002, 0x003 },
+	{ 0x00000004, 0, 0x009, 0x00d },
+	{ 0x00000008, 0, 0x012, 0x013 },
+	{ 0x00000008, 1, 0x018, 0x019 },
+	{ 0x00000004, 0, 0x020, 0x024 },
+	{ 0x00000010, 0, 0x02a, 0x031 },
+	{ 0x00000002, 0, 0x038, 0x071 },
+	{ 0x00000020, 0, 0x0d6, 0x0d7 },
+	{ 0x00000020, 1, 0x0d7, 0x0d8 },
+	{ 0x00000020, 0, 0x12f, 0x130 },
+	{ 0x00000020, 1, 0x130, 0x131 },
+	{ 0x00000008, 0, 0x134, 0x135 },
+	{ 0x00000008, 1, 0x13c, 0x13f },
+	{ 0x00000008, 0, 0x13f, 0x140 },
+	{ 0x00000002, 0, 0x15c, 0x15f },
+	{ 0x00000008, 0, 0x1d5, 0x1d7 },
+	{ 0x00000008, 0, 0x1d8, 0x1e1 },
 	{ 0x00000000, 0, 0x000, 0x000 }
 };
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h
--- v2.0.33/linux/drivers/scsi/dc390.h	Wed Oct 15 15:12:17 1997
+++ linux/drivers/scsi/dc390.h	Wed Jun  3 15:17:48 1998
@@ -68,7 +68,7 @@
 	NULL,	/* *usage_count */	\
 	&proc_scsi_tmscsim,	/* *proc_dir */ 	\
 	tmscsim_proc_info,	/* (*proc_info)() */	\
-	"Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
+	"Tekram DC390(T) V1.11 Feb-05-1997",  /* *name */ \
 	DC390_detect,			\
 	DC390_release,	/* (*release)() */	\
 	NULL,	/* *(*info)() */	\
@@ -96,7 +96,7 @@
 	NULL,	/* *usage_count */	\
 	&proc_scsi_tmscsim,	/* *proc_dir */ 	\
 	tmscsim_proc_info,	/* (*proc_info)() */	\
-	"Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
+	"Tekram DC390(T) V1.11 Feb-05-1997",  /* *name */ \
 	DC390_detect,			\
 	DC390_release,	/* (*release)() */	\
 	NULL,	/* *(*info)() */	\
@@ -122,7 +122,7 @@
 #define DC390_T     {		\
 	NULL,			\
 	NULL,			\
-	"Tekram DC390(T) V1.10 Dec-05-1996",\
+	"Tekram DC390(T) V1.11 Feb-05-1997",\
 	DC390_detect,		\
 	DC390_release,			\
 	NULL, /* info */	\
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c
--- v2.0.33/linux/drivers/scsi/dtc.c	Tue Apr  9 04:25:37 1996
+++ linux/drivers/scsi/dtc.c	Wed Jun  3 15:17:48 1998
@@ -94,23 +94,23 @@
 
 
 static struct override {
-   unsigned char *address;
+   __u32 address;
    int irq;
 } overrides
 #ifdef OVERRIDE
 [] = OVERRIDE;
 #else
-[4] = {{NULL, IRQ_AUTO}, {NULL, IRQ_AUTO}, {NULL, IRQ_AUTO},
-     {NULL, IRQ_AUTO}};
+[4] = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO},
+       {0, IRQ_AUTO}};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
 static struct base {
-   unsigned char *address;
+   __u32 address;
    int noauto;
-} bases[] = {{(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0},
-{(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}};
+} bases[] = {{0xcc000, 0}, {0xc8000, 0},
+{0xdc000, 0}, {0xd8000, 0}};
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
@@ -138,10 +138,10 @@
       printk("dtc_setup: usage dtc=address,irq\n");
    else
       if (commandline_current < NO_OVERRIDES) {
-      overrides[commandline_current].address = (unsigned char *) ints[1];
+      overrides[commandline_current].address = ints[1];
       overrides[commandline_current].irq = ints[2];
       for (i = 0; i < NO_BASES; ++i)
-	 if (bases[i].address == (unsigned char *) ints[1]) {
+	 if (bases[i].address == ints[1]) {
 	 bases[i].noauto = 1;
 	 break;
       }
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.0.33/linux/drivers/scsi/eata.c	Mon Sep 15 09:41:28 1997
+++ linux/drivers/scsi/eata.c	Wed Jun  3 15:17:48 1998
@@ -1,6 +1,41 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
- *   
+ *
+ *      16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
+ *          Improved abort handling during the eh recovery process.
+ *
+ *      13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
+ *          The driver is now fully SMP safe, including the
+ *          abort and reset routines.
+ *          Added command line options (eh:[y|n]) to choose between
+ *          new_eh_code and the old scsi code.
+ *          If linux verion >= 2.1.101 the default is eh:y, while the eh
+ *          option is ignored for previous releases and the old scsi code
+ *          is used.
+ *
+ *      18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
+ *          Reworked interrupt handler.
+ *
+ *      11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
+ *          Major reliability improvement: when a batch with overlapping
+ *          requests is detected, requests are queued one at a time
+ *          eliminating any possible board or drive reordering.
+ *
+ *      10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ *          Improved SMP support (if linux version >= 2.1.95).
+ *
+ *       9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ *          Added support for new PCI code and IO-APIC remapping of irqs.
+ *          Performance improvement: when sequential i/o is detected,
+ *          always use direct sort instead of reverse sort.
+ *
+ *       4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
+ *          io_port is now unsigned long.
+ *
+ *      17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
+ *          Use new scsi error handling code (if linux version >= 2.1.88).
+ *          Use new interrupt code.
+ *
  *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
  *          Use of udelay inside the wait loops to avoid timeout
  *          problems with fast cpus.
@@ -14,7 +49,7 @@
  *          Use of serial_number_at_timeout in abort and reset processing.
  *          Use of the __initfunc and __initdata macro in setup code.
  *          Minor cleanups in the list_statistics code.
- *          Increased controller busy timeout in order to better support 
+ *          Increased controller busy timeout in order to better support
  *          slow SCSI devices.
  *
  *      24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
@@ -23,7 +58,7 @@
  *          Fixed data transfer direction for some SCSI opcodes.
  *          Immediate acknowledge to request sense commands.
  *          Linked commands to each disk device are now reordered by elevator
- *          sorting. Rare cases in which reordering of write requests could 
+ *          sorting. Rare cases in which reordering of write requests could
  *          cause wrong results are managed.
  *          Fixed spurious timeouts caused by long simple queue tag sequences.
  *          New command line option (tm:[0-3]) to choose the type of tags:
@@ -89,7 +124,7 @@
  *
  *      28 Jan 1995 rev. 1.14 for linux 1.1.86
  *          Added module support.
- *          Log and do a retry when a disk drive returns a target status 
+ *          Log and do a retry when a disk drive returns a target status
  *          different from zero on a recovered error.
  *
  *      24 Jan 1995 rev. 1.13 for linux 1.1.85
@@ -103,7 +138,7 @@
  *
  *      17 Dec 1994 rev. 1.11 for linux 1.1.74
  *          Use the scsicam_bios_param routine. This allows an easy
- *          migration path from disk partition tables created using 
+ *          migration path from disk partition tables created using
  *          different SCSI drivers and non optimal disk geometry.
  *
  *      15 Dec 1994 rev. 1.10 for linux 1.1.74
@@ -127,7 +162,7 @@
  *          This driver is based on the CAM (Common Access Method Committee)
  *          EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
  *
- *  Copyright (C) 1994-1997 Dario Ballabio (dario@milano.europe.dg.com)
+ *  Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com)
  *
  *  Redistribution and use in source and binary forms, with or without
  *  modification, are permitted provided that redistributions of source
@@ -157,10 +192,10 @@
  *  The DPT PM2001 provides only the EATA/PIO interface and hence is not
  *  supported by this driver.
  *
- *  This code has been tested with up to 3 Distributed Processing Technology 
+ *  This code has been tested with up to 3 Distributed Processing Technology
  *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers,
  *  in any combination of private and shared IRQ.
- *  PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS 
+ *  PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS
  *  v003.D0, firmware v07G.0).
  *
  *  DPT SmartRAID boards support "Hardware Array" - a group of disk drives
@@ -170,14 +205,14 @@
  *
  *  WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix"
  *  as the current OS in the DPTMGR "Initial System Installation" menu.
- *  Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0), 
+ *  Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0),
  *  which is not supported by the actual SCSI subsystem.
  *  To get the "Array Group" functionality, the Linux MD driver must be used
  *  instead of the DPT "Array Group" feature.
  *
  *  Multiple ISA, EISA and PCI boards can be configured in the same system.
  *  It is suggested to put all the EISA boards on the same IRQ level, all
- *  the PCI  boards on another IRQ level, while ISA boards cannot share 
+ *  the PCI  boards on another IRQ level, while ISA boards cannot share
  *  interrupts.
  *
  *  If you configure multiple boards on the same IRQ, the interrupt must
@@ -190,7 +225,7 @@
  *  bus, or even if you system has no EISA bus at all.
  *  Do not force any ISA address on EATA PCI boards.
  *
- *  If PCI bios support is configured into the kernel, BIOS32 is used to 
+ *  If PCI bios support is configured into the kernel, BIOS32 is used to
  *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
  *
  *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
@@ -199,11 +234,11 @@
  *
  *  The sequence of detection probes is:
  *
- *  - ISA 0x1F0; 
+ *  - ISA 0x1F0;
  *  - PCI SCSI controllers (only if BIOS32 is available);
  *  - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
  *  - ISA  0x170, 0x230, 0x330.
- * 
+ *
  *  The above list of detection probes can be totally replaced by the
  *  boot command line option: "eata=port0,port1,port2,...", where the
  *  port0, port1... arguments are ISA/EISA/PCI addresses to be probed.
@@ -214,6 +249,8 @@
  *  After the optional list of detection probes, other possible command line
  *  options are:
  *
+ *  eh:y  use new scsi code (linux 2.2 only);
+ *  eh:n  use old scsi code;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  tc:y  enables tagged commands;
@@ -225,13 +262,14 @@
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
  *
  *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using
- *  the list of detection probes could be: "eata=0x7410,0x230,lc:y,tc:n,mq:4".
+ *  the list of detection probes could be:
+ *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \
- *                max_queue_depth=4 tag_mode=0
+ *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -245,15 +283,15 @@
  *  in the elevator sorting queue. When the active command completes, the
  *  commands in this queue are sorted by sector address. The sort is chosen
  *  between increasing or decreasing by minimizing the seek distance between
- *  the sector of the commands just completed and the sector of the first 
- *  command in the list to be sorted. 
+ *  the sector of the commands just completed and the sector of the first
+ *  command in the list to be sorted.
  *  Trivial math assures that the unsorted average seek distance when doing
  *  random seeks over S sectors is S/3.
  *  When (Q-1) requests are uniformly distributed over S sectors, the average
  *  distance between two adjacent requests is S/((Q-1) + 1), so the sorted
  *  average seek distance for (Q-1) random requests over S sectors is S/Q.
  *  The elevator sorting hence divides the seek distance by a factor Q/3.
- *  The above pure geometric remarks are valid in all cases and the 
+ *  The above pure geometric remarks are valid in all cases and the
  *  driver effectively reduces the seek distance by the predicted factor
  *  when there are Q concurrent read i/o operations on the device, but this
  *  does not necessarily results in a noticeable performance improvement:
@@ -261,7 +299,7 @@
  *
  *  Note: command reordering inside a batch of queued commands could cause
  *        wrong results only if there is at least one write request and the
- *        intersection (sector-wise) of all requests is not empty. 
+ *        intersection (sector-wise) of all requests is not empty.
  *        When the driver detects a batch including overlapping requests
  *        (a really rare event) strict serial (pid) order is enforced.
  *  ----------------------------------------------------------------------------
@@ -272,11 +310,14 @@
  *  the driver sets host->wish_block = TRUE for all ISA boards.
  */
 
+#include <linux/version.h>
+
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #define MAX_INT_PARAM 10
+
 #if defined(MODULE)
 #include <linux/module.h>
-#include <linux/version.h>
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
 MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
 MODULE_PARM(linked_comm, "i");
@@ -284,8 +325,10 @@
 MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(tag_mode, "i");
+MODULE_PARM(use_new_eh_code, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
+
 #endif
 
 #include <linux/string.h>
@@ -306,9 +349,12 @@
 #include "eata.h"
 #include <linux/stat.h>
 #include <linux/config.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,93)
+#include <linux/bios32.h>
+#endif
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
 #include <linux/init.h>
 #else
@@ -317,6 +363,34 @@
 #define __init
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+#include <asm/spinlock.h>
+#define IRQ_FLAGS
+#define IRQ_LOCK
+#define IRQ_LOCK_SAVE
+#define IRQ_UNLOCK
+#define IRQ_UNLOCK_RESTORE
+#define SPIN_FLAGS unsigned long spin_flags;
+#define SPIN_LOCK spin_lock_irq(&io_request_lock);
+#define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags);
+#define SPIN_UNLOCK spin_unlock_irq(&io_request_lock);
+#define SPIN_UNLOCK_RESTORE \
+                  spin_unlock_irqrestore(&io_request_lock, spin_flags);
+static int use_new_eh_code = TRUE;
+#else
+#define IRQ_FLAGS unsigned long irq_flags;
+#define IRQ_LOCK cli();
+#define IRQ_LOCK_SAVE do {save_flags(irq_flags); cli();} while (0);
+#define IRQ_UNLOCK sti();
+#define IRQ_UNLOCK_RESTORE do {restore_flags(irq_flags);} while (0);
+#define SPIN_FLAGS
+#define SPIN_LOCK
+#define SPIN_LOCK_SAVE
+#define SPIN_UNLOCK
+#define SPIN_UNLOCK_RESTORE
+static int use_new_eh_code = FALSE;
+#endif
+
 struct proc_dir_entry proc_scsi_eata2x = {
     PROC_SCSI_EATA2X, 6, "eata2x",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
@@ -330,28 +404,28 @@
 
 #undef  DEBUG_LINKED_COMMANDS
 #undef  DEBUG_DETECT
+#undef  DEBUG_PCI_DETECT
 #undef  DEBUG_INTERRUPT
-#undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
-#undef  DEBUG_SMP
+#undef  DEBUG_GENERATE_ERRORS
+#undef  DEBUG_GENERATE_ABORTS
 
 #define MAX_ISA 4
-#define MAX_VESA 0 
+#define MAX_VESA 0
 #define MAX_EISA 15
 #define MAX_PCI 16
 #define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
 #define MAX_CHANNEL 4
 #define MAX_LUN 32
 #define MAX_TARGET 32
-#define MAX_IRQ 16
 #define MAX_MAILBOXES 64
 #define MAX_SGLIST 64
-#define MAX_LARGE_SGLIST 252
+#define MAX_LARGE_SGLIST 122
 #define MAX_INTERNAL_RETRIES 64
 #define MAX_CMD_PER_LUN 2
 #define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
 
-#define SKIP UINT_MAX
+#define SKIP ULONG_MAX
 #define FALSE 0
 #define TRUE 1
 #define FREE 0
@@ -415,15 +489,15 @@
    ulong  data_len;     /* Number of valid bytes after this field */
    ulong  sign;         /* ASCII "EATA" signature */
    unchar        :4,    /* unused low nibble */
-	  version:4;    /* EATA version, should be 0x1 */
+          version:4;    /* EATA version, should be 0x1 */
    unchar  ocsena:1,    /* Overlap Command Support Enabled */
-	   tarsup:1,    /* Target Mode Supported */
+           tarsup:1,    /* Target Mode Supported */
            trnxfr:1,    /* Truncate Transfer Cmd NOT Necessary */
            morsup:1,    /* More Supported */
-	   dmasup:1,    /* DMA Supported */
-	   drqvld:1,    /* DRQ Index (DRQX) is valid */
-	      ata:1,    /* This is an ATA device */
-	   haaval:1;    /* Host Adapter Address Valid */
+           dmasup:1,    /* DMA Supported */
+           drqvld:1,    /* DRQ Index (DRQX) is valid */
+              ata:1,    /* This is an ATA device */
+           haaval:1;    /* Host Adapter Address Valid */
    ushort cp_pad_len;   /* Number of pad bytes after cp_len */
    unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */
    ulong  cp_len;       /* Number of valid bytes in cp */
@@ -432,19 +506,19 @@
    ushort unused;
    ushort scatt_size;   /* Max number of entries in scatter/gather table */
    unchar     irq:4,    /* Interrupt Request assigned to this controller */
-	   irq_tr:1,    /* 0 for edge triggered, 1 for level triggered */
-	   second:1,    /* 1 if this is a secondary (not primary) controller */
-	     drqx:2;    /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
+           irq_tr:1,    /* 0 for edge triggered, 1 for level triggered */
+           second:1,    /* 1 if this is a secondary (not primary) controller */
+             drqx:2;    /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
    unchar  sync;        /* 1 if scsi target id 7...0 is running sync scsi */
 
    /* Structure extension defined in EATA 2.0B */
    unchar  isaena:1,    /* ISA i/o addressing is disabled/enabled */
-	 forcaddr:1,    /* Port address has been forced */
+         forcaddr:1,    /* Port address has been forced */
          large_sg:1,    /* 1 if large SG lists are supported */
              res1:1,
-		 :4;
+                 :4;
    unchar  max_id:5,    /* Max SCSI target ID number */
-	 max_chan:3;    /* Max SCSI channel number on this board */
+         max_chan:3;    /* Max SCSI channel number on this board */
 
    /* Structure extension defined in EATA 2.0C */
    unchar   max_lun;    /* Max SCSI LUN number */
@@ -463,21 +537,21 @@
 struct eata_config {
    ushort len;          /* Number of bytes following this field */
    unchar edis:1,       /* Disable EATA interface after config command */
-	 ocena:1,       /* Overlapped Commands Enabled */
-	mdpena:1,       /* Transfer all Modified Data Pointer Messages */
-	tarena:1,       /* Target Mode Enabled for this controller */
-	      :4;
+         ocena:1,       /* Overlapped Commands Enabled */
+        mdpena:1,       /* Transfer all Modified Data Pointer Messages */
+        tarena:1,       /* Target Mode Enabled for this controller */
+              :4;
    unchar cpad[511];
    };
 
 /* Returned status packet structure */
 struct mssp {
    unchar adapter_status:7,    /* State related to current command */
-		     eoc:1;    /* End Of Command (1 = command completed) */
+                     eoc:1;    /* End Of Command (1 = command completed) */
    unchar target_status;       /* SCSI status received after data transfer */
    unchar unused[2];
    ulong inv_res_len;          /* Number of bytes not transferred */
-   Scsi_Cmnd *SCpnt;           /* Address set in cp */
+   struct mscp *cpp;           /* Address set in cp */
    char mess[12];
    };
 
@@ -489,13 +563,13 @@
 /* MailBox SCSI Command Packet */
 struct mscp {
    unchar  sreset:1,     /* SCSI Bus Reset Signal should be asserted */
-	     init:1,     /* Re-initialize controller and self test */
-	   reqsen:1,     /* Transfer Request Sense Data to addr using DMA */
-	       sg:1,     /* Use Scatter/Gather */
-		 :1,
-	   interp:1,     /* The controller interprets cp, not the target */ 
-	     dout:1,     /* Direction of Transfer is Out (Host to Target) */
-	      din:1;     /* Direction of Transfer is In (Target to Host) */
+             init:1,     /* Re-initialize controller and self test */
+           reqsen:1,     /* Transfer Request Sense Data to addr using DMA */
+               sg:1,     /* Use Scatter/Gather */
+                 :1,
+           interp:1,     /* The controller interprets cp, not the target */
+             dout:1,     /* Direction of Transfer is Out (Host to Target) */
+              din:1;     /* Direction of Transfer is In (Target to Host) */
    unchar sense_len;     /* Request Sense Length */
    unchar unused[3];
    unchar  fwnest:1,     /* Send command to a component of an Array Group */
@@ -507,16 +581,17 @@
    unchar  target:5,     /* SCSI target ID */
           channel:3;     /* SCSI channel number */
    unchar     lun:5,     /* SCSI logical unit number */
-	   luntar:1,     /* This cp is for Target (not LUN) */
-	   dispri:1,     /* Disconnect Privilege granted */
-	      one:1;     /* 1 */
+           luntar:1,     /* This cp is for Target (not LUN) */
+           dispri:1,     /* Disconnect Privilege granted */
+              one:1;     /* 1 */
    unchar mess[3];       /* Massage to/from Target */
    unchar cdb[12];       /* Command Descriptor Block */
    ulong  data_len;      /* If sg=0 Data Length, if sg=1 sglist length */
-   Scsi_Cmnd *SCpnt;     /* Address to be returned in sp */
+   struct mscp *cpp;     /* Address to be returned in sp */
    ulong  data_address;  /* If sg=0 Data Address, if sg=1 sglist address */
    ulong  sp_addr;       /* Address where sp is DMA'ed when cp completes */
    ulong  sense_addr;    /* Address where Sense Data is DMA'ed on error */
+   Scsi_Cmnd *SCpnt;
    unsigned int index;   /* cp index */
    struct sg_list *sglist;
    };
@@ -526,7 +601,6 @@
    unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
    unsigned int last_cp_used;           /* Index of last mailbox used */
    unsigned int iocount;                /* Total i/o done for this board */
-   unsigned int multicount;             /* Total ... in second ihdlr loop */
    int board_number;                    /* Number of this board */
    char board_name[16];                 /* Name of this board */
    char board_id[256];                  /* data from INQUIRY on this board */
@@ -537,14 +611,17 @@
    unsigned long last_retried_pid;      /* Pid of last retried command */
    unsigned char subversion;            /* Bus type, either ISA or EISA/PCI */
    unsigned char protocol_rev;          /* EATA 2.0 rev., 'A' or 'B' or 'C' */
-   struct mssp sp[MAX_MAILBOXES];       /* Returned status for this board */
+   struct mssp sp[2];                   /* Returned status for this board */
    };
 
 static struct Scsi_Host *sh[MAX_BOARDS + 1];
 static const char *driver_name = "EATA";
-static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
+static char sha[MAX_BOARDS];
+
+/* Initialize num_boards so that ihdlr can work while detect is in progress */
+static unsigned int num_boards = MAX_BOARDS;
 
-static unsigned int io_port[] __initdata = { 
+static unsigned long io_port[] __initdata = {
 
    /* Space for MAX_INT_PARAM ports usable while loading as a module */
    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
@@ -559,11 +636,11 @@
 
    /* MAX_EISA ports */
    0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
-   0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
+   0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88,
 
    /* Other (MAX_ISA - 1) ports */
    0x170,  0x230,  0x330,
- 
+
    /* End of list */
    0x0
    };
@@ -576,26 +653,26 @@
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
 #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
-static void eata2x_interrupt_handler(int, void *, struct pt_regs *);
+static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
 static int link_statistics = 0;
 static int tag_mode = TAG_MIXED;
 
-#if defined (CONFIG_SCSI_EATA_TAGGED_QUEUE)
+#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
 static int tagged_comm = TRUE;
 #else
 static int tagged_comm = FALSE;
 #endif
 
-#if defined (CONFIG_SCSI_EATA_LINKED_COMMANDS)
+#if defined(CONFIG_SCSI_EATA_LINKED_COMMANDS)
 static int linked_comm = TRUE;
 #else
 static int linked_comm = FALSE;
 #endif
 
-#if defined CONFIG_SCSI_EATA_MAX_TAGS
+#if defined(CONFIG_SCSI_EATA_MAX_TAGS)
 static int max_queue_depth = CONFIG_SCSI_EATA_MAX_TAGS;
 #else
 static int max_queue_depth = MAX_CMD_PER_LUN;
@@ -603,12 +680,10 @@
 
 static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
    Scsi_Device *dev;
-   int j, ntag = 0, nuntag = 0, tqd, utqd; 
-   unsigned long flags;
-
-   save_flags(flags);
-   cli();
+   int j, ntag = 0, nuntag = 0, tqd, utqd;
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    j = ((struct hostdata *) host->hostdata)->board_number;
 
    for(dev = devlist; dev; dev = dev->next) {
@@ -661,11 +736,11 @@
              dev->queue_depth, link_suffix, tag_suffix);
       }
 
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return;
 }
 
-static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
+static inline int wait_on_busy(unsigned long iobase, unsigned int loop) {
 
    while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) {
       udelay(1L);
@@ -675,7 +750,7 @@
    return FALSE;
 }
 
-static inline int do_dma(unsigned int iobase, unsigned int addr, unchar cmd) {
+static inline int do_dma(unsigned long iobase, unsigned int addr, unchar cmd) {
 
    if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE;
 
@@ -690,7 +765,7 @@
    return FALSE;
 }
 
-static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
+static inline int read_pio(unsigned long iobase, ushort *start, ushort *end) {
    unsigned int loop = MAXLOOP;
    ushort *p;
 
@@ -698,7 +773,7 @@
 
       while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) {
          udelay(1L);
-	 if (--loop == 0) return TRUE;
+         if (--loop == 0) return TRUE;
          }
 
       loop = MAXLOOP;
@@ -708,10 +783,48 @@
    return FALSE;
 }
 
+__initfunc (static inline int
+            get_pci_irq(unsigned long port_base, unsigned char *apic_irq)) {
+
+#if defined(CONFIG_PCI)
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+   unsigned int addr;
+   struct pci_dev *dev = NULL;
+
+   if (!pci_present()) return FALSE;
+
+   while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+
+      if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+      printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n",
+             driver_name, dev->bus->number, dev->devfn, addr, dev->irq);
+#endif
+
+      if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+             continue;
+
+      if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) {
+         *apic_irq = dev->irq;
+         return TRUE;
+         }
+
+      }
+
+#endif /* end new style PCI code */
+
+#endif /* end CONFIG_PCI */
+
+   return FALSE;
+}
+
 __initfunc (static inline int port_detect \
-      (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
    unsigned char irq, dma_channel, subversion, i;
-   unsigned char protocol_rev;
+   unsigned char protocol_rev, apic_irq;
    struct eata_info info;
    char *bus_type, dma_name[16], tag_type;
 
@@ -723,22 +836,22 @@
    sprintf(name, "%s%d", driver_name, j);
 
    if(check_region(port_base, REGION_SIZE)) {
-      printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
+      printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);
       return FALSE;
       }
 
    if (do_dma(port_base, 0, READ_CONFIG_PIO)) return FALSE;
 
    /* Read the info structure */
-   if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) 
+   if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0]))
       return FALSE;
 
    /* Check the controller "EATA" signature */
    if (info.sign != EATA_SIGNATURE) return FALSE;
 
    if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
-      printk("%s: config structure size (%ld bytes) too short, detaching.\n", 
-	     name, DEV2H(info.data_len));
+      printk("%s: config structure size (%ld bytes) too short, detaching.\n",
+             name, DEV2H(info.data_len));
       return FALSE;
       }
    else if (DEV2H(info.data_len) == EATA_2_0A_SIZE)
@@ -774,7 +887,7 @@
       }
 
    if (!info.haaval || info.ata) {
-      printk("%s: address 0x%03x, unusable %s board (%d%d), detaching.\n",
+      printk("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n",
              name, port_base, bus_type, info.haaval, info.ata);
       return FALSE;
       }
@@ -782,7 +895,7 @@
    if (info.drqvld) {
 
       if (subversion ==  ESA)
-	 printk("%s: warning, weird %s board using DMA.\n", name, bus_type);
+         printk("%s: warning, weird %s board using DMA.\n", name, bus_type);
 
       subversion = ISA;
       dma_channel = dma_channel_table[3 - info.drqx];
@@ -790,7 +903,7 @@
    else {
 
       if (subversion ==  ISA)
-	 printk("%s: warning, weird %s board not using DMA.\n", name, bus_type);
+         printk("%s: warning, weird %s board not using DMA.\n", name, bus_type);
 
       subversion = ESA;
       dma_channel = NO_DMA;
@@ -803,23 +916,29 @@
 
    if (subversion == ESA && !info.irq_tr)
       printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
-	     name, irq);
+             name, irq);
+
+   if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) {
+      printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq);
+      irq = apic_irq;
+      }
 
-   /* Board detected, allocate its IRQ if not already done */
-   if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
-              eata2x_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+   /* Board detected, allocate its IRQ */
+   if (request_irq(irq, do_interrupt_handler,
+             SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+             driver_name, (void *) &sha[j])) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
 
    if (subversion == ISA && request_dma(dma_channel, driver_name)) {
       printk("%s: unable to allocate DMA channel %u, detaching.\n",
-	     name, dma_channel);
-      free_irq(irq, NULL);
+             name, dma_channel);
+      free_irq(irq, &sha[j]);
       return FALSE;
       }
 
-#if defined (FORCE_CONFIG)
+#if defined(FORCE_CONFIG)
    {
    struct eata_config config;
 
@@ -840,7 +959,7 @@
    if (sh[j] == NULL) {
       printk("%s: unable to register host, detaching.\n", name);
 
-      if (!irqlist[irq]) free_irq(irq, NULL);
+      free_irq(irq, &sha[j]);
 
       if (subversion == ISA) free_dma(dma_channel);
 
@@ -865,7 +984,6 @@
    HD(j)->subversion = subversion;
    HD(j)->protocol_rev = protocol_rev;
    HD(j)->board_number = j;
-   irqlist[irq]++;
 
    if (HD(j)->subversion == ESA)
       sh[j]->unchecked_isa_dma = FALSE;
@@ -889,7 +1007,7 @@
 
    /* DPT PM2012 does not allow to detect can_queue correctly */
    if (sh[j]->can_queue > MAX_MAILBOXES || sh[j]->can_queue  < 2) {
-      printk("%s: detect, wrong n. of Mbox %d, fixed.\n",
+      printk("%s: detect, wrong n. of mbox %d, fixed.\n",
              BN(j), sh[j]->can_queue);
       sh[j]->can_queue = MAX_MAILBOXES;
       }
@@ -917,14 +1035,14 @@
 
    for (i = 0; i < sh[j]->can_queue; i++)
       if (! ((&HD(j)->cp[i])->sglist = kmalloc(
-            sh[j]->sg_tablesize * sizeof(struct sg_list), 
+            sh[j]->sg_tablesize * sizeof(struct sg_list),
             (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
          printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
          eata2x_release(sh[j]);
          return FALSE;
          }
-      
-   if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) 
+
+   if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
        max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
 
    if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
@@ -937,20 +1055,32 @@
       }
    else                                 tag_type = 'n';
 
-   printk("%s: 2.0%c, %s 0x%03x, IRQ %u, %s, SG %d, MB %d, tc:%c, lc:%c, "\
-          "mq:%d.\n", BN(j), HD(j)->protocol_rev, bus_type, sh[j]->io_port,
-          sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue,
-          tag_type, YESNO(linked_comm), max_queue_depth);
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+   sh[j]->hostt->use_new_eh_code = use_new_eh_code;
+#else
+   use_new_eh_code = FALSE;
+#endif
+
+   if (j == 0) {
+      printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
+      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c.\n",
+             driver_name, tag_type, YESNO(linked_comm),
+             max_queue_depth, YESNO(use_new_eh_code));
+      }
+
+   printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
+          BN(j), HD(j)->protocol_rev, bus_type, (unsigned long)sh[j]->io_port,
+          sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
 
    if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
       printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
    for (i = 0; i <= sh[j]->max_channel; i++)
-      printk("%s: SCSI channel %u enabled, host target ID %u.\n",
+      printk("%s: SCSI channel %u enabled, host target ID %d.\n",
              BN(j), i, info.host_addr[3 - i]);
 
-#if defined (DEBUG_DETECT)
+#if defined(DEBUG_DETECT)
    printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "\
           "sec. %u, infol %ld, cpl %ld spl %ld.\n", name, info.version,
           info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync,
@@ -964,7 +1094,7 @@
 
    if (protocol_rev == 'C')
       printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, "\
-             "raidnum %u.\n", name, info.max_lun, info.m1, info.idquest, 
+             "raidnum %u.\n", name, info.max_lun, info.m1, info.idquest,
              info.pci, info.eisa, info.raidnum);
 #endif
 
@@ -979,8 +1109,8 @@
 
       if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
 
-      for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; 
-   
+      for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
+
       io_port[i] = 0;
       setup_done = TRUE;
       }
@@ -997,6 +1127,7 @@
       else if (!strncmp(cur, "tm:", 3)) tag_mode = val;
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
+      else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1008,9 +1139,37 @@
 
 #if defined(CONFIG_PCI)
 
+   unsigned int addr, k;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+   struct pci_dev *dev = NULL;
+
+   if (!pci_present()) return;
+
+   for (k = 0; k < MAX_PCI; k++) {
+
+      if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
+
+      if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+      printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
+             driver_name, k, dev->bus->number, dev->devfn, addr);
+#endif
+
+      if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+             continue;
+
+      /* Reverse the returned address order */
+      io_port[MAX_INT_PARAM + MAX_PCI - k] =
+             (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
+      }
+
+#else  /* else old style PCI code */
+
    unsigned short i = 0;
    unsigned char bus, devfn;
-   unsigned int addr, k;
 
    if (!pcibios_present()) return;
 
@@ -1022,7 +1181,7 @@
       if (pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr)
              != PCIBIOS_SUCCESSFUL) continue;
 
-#if defined(DEBUG_DETECT)
+#if defined(DEBUG_PCI_DETECT)
       printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
              driver_name, k, bus, devfn, addr);
 #endif
@@ -1031,23 +1190,24 @@
              continue;
 
       /* Reverse the returned address order */
-      io_port[MAX_INT_PARAM + MAX_PCI - k] = 
+      io_port[MAX_INT_PARAM + MAX_PCI - k] =
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
-#endif
+
+#endif /* end old style PCI code */
+
+#endif /* end CONFIG_PCI */
 
    return;
 }
 
 __initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
-   unsigned long flags;
    unsigned int j = 0, k;
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    tpnt->proc_dir = &proc_scsi_eata2x;
 
-   save_flags(flags);
-   cli();
-
 #if defined(MODULE)
    /* io_port could have been modified when loading as a module */
    if(io_port[0] != SKIP) {
@@ -1056,11 +1216,6 @@
       }
 #endif
 
-   for (k = 0; k < MAX_IRQ; k++) {
-      irqlist[k] = 0;
-      calls[k] = 0;
-      }
-
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
    if (!setup_done) add_pci_ports();
@@ -1072,10 +1227,8 @@
       if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
       }
 
-   if (j > 0) 
-      printk("EATA/DMA 2.0x: Copyright (C) 1994-1997 Dario Ballabio.\n");
-
-   restore_flags(flags);
+   num_boards = j;
+   IRQ_UNLOCK_RESTORE
    return j;
 }
 
@@ -1094,15 +1247,14 @@
    cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
-int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned long flags;
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    unsigned int i, j, k;
    struct mscp *cpp;
    struct mssp *spp;
 
    static const unsigned char data_out_cmds[] = {
       0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
-      0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, 
+      0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
       0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
       };
 
@@ -1112,24 +1264,14 @@
       0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
       };
 
-   save_flags(flags);
-   cli();
    /* j is the board number */
    j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
 
-   if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
+   if (SCpnt->host_scribble)
+      panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
+            BN(j), SCpnt->pid, SCpnt);
 
-   if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
-      SCpnt->result = DID_OK << 16; 
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
-             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);    
-      return 0;
-      }
-
-   /* i is the mailbox number, look for the first free mailbox 
+   /* i is the mailbox number, look for the first free mailbox
       starting from last_cp_used */
    i = HD(j)->last_cp_used + 1;
 
@@ -1138,26 +1280,14 @@
       if (i >= sh[j]->can_queue) i = 0;
 
       if (HD(j)->cp_stat[i] == FREE) {
-	 HD(j)->last_cp_used = i;
-	 break;
-	 }
+         HD(j)->last_cp_used = i;
+         break;
+         }
       }
 
    if (k == sh[j]->can_queue) {
-      printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
-
-      if (HD(j)->in_reset) 
-	 printk("%s: qcomm, already in reset.\n", BN(j));
-      else if (eata2x_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
-               == SCSI_RESET_SUCCESS) 
-	 panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
-
-      SCpnt->result = DID_BUS_BUSY << 16; 
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);    
-      return 0;
+      printk("%s: qcomm, no free mailbox.\n", BN(j));
+      return 1;
       }
 
    /* Set pointer to control packet structure */
@@ -1166,33 +1296,32 @@
    memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
 
    /* Set pointer to status packet structure */
-   spp = &HD(j)->sp[i];
-
-   memset(spp, 0, sizeof(struct mssp));
+   spp = &HD(j)->sp[0];
 
    /* The EATA protocol uses Big Endian format */
    cpp->sp_addr = V2DEV(spp);
 
+   cpp->cpp = cpp;
    SCpnt->scsi_done = done;
    cpp->index = i;
    SCpnt->host_scribble = (unsigned char *) &cpp->index;
 
    if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
-			BN(j), i, SCpnt->channel, SCpnt->target,
+                        BN(j), i, SCpnt->channel, SCpnt->target,
                         SCpnt->lun, SCpnt->pid);
 
    for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
-	cpp->dout = TRUE;
-	break;
-	}
+        cpp->dout = TRUE;
+        break;
+        }
 
    if ((cpp->din = !cpp->dout))
       for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
         if (SCpnt->cmnd[0] == data_none_cmds[k]) {
-	   cpp->din = FALSE;
-	   break;
-	   }
+           cpp->din = FALSE;
+           break;
+           }
 
    cpp->reqsen = TRUE;
    cpp->dispri = TRUE;
@@ -1202,11 +1331,11 @@
    cpp->one = TRUE;
    cpp->channel = SCpnt->channel;
    cpp->target = SCpnt->target;
-   cpp->lun = SCpnt->lun;  
+   cpp->lun = SCpnt->lun;
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = V2DEV(SCpnt->sense_buffer); 
+   cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
    cpp->sense_len = sizeof SCpnt->sense_buffer;
-   
+
    if (SCpnt->device->tagged_queue) {
 
       if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] ||
@@ -1240,59 +1369,58 @@
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
       flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
-      restore_flags(flags);
       return 0;
       }
 
    /* Send control packet to the board */
    if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
-      SCpnt->result = DID_ERROR << 16; 
       SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
-             " done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
-             SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);    
-      return 0;
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
+             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
+      return 1;
       }
 
    HD(j)->cp_stat[i] = IN_USE;
-   restore_flags(flags);
    return 0;
 }
 
-int eata2x_abort(Scsi_Cmnd *SCarg) {
-   unsigned long flags;
+int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_qcomm(SCpnt, done);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+static inline int do_old_abort(Scsi_Cmnd *SCarg) {
    unsigned int i, j;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
-   if (SCarg->host_scribble == NULL
-       || SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->host_scribble == NULL ||
+       (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout))) {
       printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
-	     BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-      restore_flags(flags);
+             BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
    i = *(unsigned int *)SCarg->host_scribble;
-   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n", 
-	  BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+          BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: abort, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == FREE) {
       printk("%s: abort, mbox %d is free.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1300,25 +1428,22 @@
       printk("%s: abort, mbox %d is in use.\n", BN(j), i);
 
       if (SCarg != HD(j)->cp[i].SCpnt)
-	 panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
-	       BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+         panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+               BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
       if (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
          printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
 
-      restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
       }
 
    if (HD(j)->cp_stat[i] == IN_RESET) {
       printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == LOCKED) {
       printk("%s: abort, mbox %d is locked.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1327,47 +1452,130 @@
       SCarg->host_scribble = NULL;
       HD(j)->cp_stat[i] = FREE;
       printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
-	     BN(j), i, SCarg->pid);
+             BN(j), i, SCarg->pid);
       SCarg->scsi_done(SCarg);
-      restore_flags(flags);
       return SCSI_ABORT_SUCCESS;
       }
 
-   restore_flags(flags);
    panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned long flags;
+int eata2x_old_abort(Scsi_Cmnd *SCarg) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_abort(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_abort(Scsi_Cmnd *SCarg) {
+   unsigned int i, j;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+
+   if (SCarg->host_scribble == NULL) {
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+             BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+      return SUCCESS;
+      }
+
+   i = *(unsigned int *)SCarg->host_scribble;
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+          BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (i >= sh[j]->can_queue)
+      panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: abort, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: abort, mbox %d is free.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_USE) {
+      printk("%s: abort, mbox %d is in use.\n", BN(j), i);
+
+      if (SCarg != HD(j)->cp[i].SCpnt)
+         panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+               BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+
+      if (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
+         printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
+
+      if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         SCarg->host_scribble = NULL;
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
+                BN(j), i, SCarg->pid);
+         return SUCCESS;
+         }
+
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_RESET) {
+      printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == LOCKED) {
+      printk("%s: abort, mbox %d is locked.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      SCarg->result = DID_ABORT << 16;
+      SCarg->host_scribble = NULL;
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
+             BN(j), i, SCarg->pid);
+      SCarg->scsi_done(SCarg);
+      return SUCCESS;
+      }
+
+   panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
+}
+
+int eata2x_abort(Scsi_Cmnd *SCarg) {
+
+   return do_abort(SCarg);
+}
+
+#endif /* new_eh_code */
+
+static inline int do_old_reset(Scsi_Cmnd *SCarg) {
    unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-   printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n", 
-	  BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
-          reset_flags);
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
 
-   if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout)) {
       printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
-      restore_flags(flags);
       return SCSI_RESET_NOT_RUNNING;
       }
 
    if (HD(j)->in_reset) {
       printk("%s: reset, exit, already in reset.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: reset, exit, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
@@ -1384,13 +1592,13 @@
       if (HD(j)->cp_stat[i] == FREE) continue;
 
       if (HD(j)->cp_stat[i] == LOCKED) {
-	 HD(j)->cp_stat[i] = FREE;
-	 printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
-	 continue;
-	 }
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+         continue;
+         }
 
       if (!(SCpnt = HD(j)->cp[i].SCpnt))
-	 panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
 
       if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
          HD(j)->cp_stat[i] = ABORTING;
@@ -1405,34 +1613,35 @@
          }
 
       if (SCpnt->host_scribble == NULL)
-	 panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
 
-      if (*(unsigned int *)SCpnt->host_scribble != i) 
-	 panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+      if (*(unsigned int *)SCpnt->host_scribble != i)
+         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
 
-      if (SCpnt->scsi_done == NULL) 
-	 panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+      if (SCpnt->scsi_done == NULL)
+         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
 
       if (SCpnt == SCarg) arg_done = TRUE;
       }
 
    if (do_dma(sh[j]->io_port, 0, RESET_PIO)) {
       printk("%s: reset, cannot reset, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
 
-#if defined (DEBUG_RESET)
+#if defined(DEBUG_RESET)
    do_trace = TRUE;
 #endif
 
    HD(j)->in_reset = TRUE;
-   sti();
+   SPIN_UNLOCK
+   IRQ_UNLOCK
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
-   cli();
+   IRQ_LOCK
+   SPIN_LOCK
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
    for (i = 0; i < sh[j]->can_queue; i++) {
@@ -1446,7 +1655,7 @@
          HD(j)->cp_stat[i] = LOCKED;
 
          printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
-	        BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->pid);
          }
 
       else if (HD(j)->cp_stat[i] == ABORTING) {
@@ -1458,7 +1667,7 @@
          HD(j)->cp_stat[i] = FREE;
 
          printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
-	        BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->pid);
          }
 
       else
@@ -1466,14 +1675,12 @@
          /* Any other mailbox has already been set free by interrupt */
          continue;
 
-      restore_flags(flags);
       SCpnt->scsi_done(SCpnt);
-      cli();
+      IRQ_LOCK
       }
 
    HD(j)->in_reset = FALSE;
    do_trace = FALSE;
-   restore_flags(flags);
 
    if (arg_done) {
       printk("%s: reset, exit, success.\n", BN(j));
@@ -1485,6 +1692,156 @@
       }
 }
 
+int eata2x_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_reset(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_reset(Scsi_Cmnd *SCarg) {
+   unsigned int i, j, time, k, c, limit = 0;
+   int arg_done = FALSE;
+   Scsi_Cmnd *SCpnt;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (SCarg->host_scribble == NULL)
+      printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+
+   if (HD(j)->in_reset) {
+      printk("%s: reset, exit, already in reset.\n", BN(j));
+      return FAILED;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, exit, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   HD(j)->retries = 0;
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == FREE) continue;
+
+      if (HD(j)->cp_stat[i] == LOCKED) {
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+         continue;
+         }
+
+      if (!(SCpnt = HD(j)->cp[i].SCpnt))
+         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+      if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+         HD(j)->cp_stat[i] = ABORTING;
+         printk("%s: reset, mbox %d aborting, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else {
+         HD(j)->cp_stat[i] = IN_RESET;
+         printk("%s: reset, mbox %d in reset, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      if (SCpnt->host_scribble == NULL)
+         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+
+      if (*(unsigned int *)SCpnt->host_scribble != i)
+         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+
+      if (SCpnt->scsi_done == NULL)
+         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+
+      if (SCpnt == SCarg) arg_done = TRUE;
+      }
+
+   if (do_dma(sh[j]->io_port, 0, RESET_PIO)) {
+      printk("%s: reset, cannot reset, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
+
+#if defined(DEBUG_RESET)
+   do_trace = TRUE;
+#endif
+
+   HD(j)->in_reset = TRUE;
+   SPIN_UNLOCK
+   IRQ_UNLOCK
+   time = jiffies;
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
+   IRQ_LOCK
+   SPIN_LOCK
+   printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == IN_RESET) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox is still waiting for its interrupt */
+         HD(j)->cp_stat[i] = LOCKED;
+
+         printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else if (HD(j)->cp_stat[i] == ABORTING) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox was never queued to the adapter */
+         HD(j)->cp_stat[i] = FREE;
+
+         printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else
+
+         /* Any other mailbox has already been set free by interrupt */
+         continue;
+
+      SCpnt->scsi_done(SCpnt);
+      IRQ_LOCK
+      }
+
+   HD(j)->in_reset = FALSE;
+   do_trace = FALSE;
+
+   if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+   else          printk("%s: reset, exit.\n", BN(j));
+
+   return SUCCESS;
+}
+
+int eata2x_reset(Scsi_Cmnd *SCarg) {
+
+   return do_reset(SCarg);
+}
+
+#endif /* new_eh_code */
+
 static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
                  unsigned int rev) {
    unsigned int i, j, k, y;
@@ -1493,7 +1850,7 @@
    for (i = 0; i < n - 1; i++) {
       k = i;
 
-      for (j = k + 1; j < n; j++) 
+      for (j = k + 1; j < n; j++)
          if (rev) {
             if (sk[j] > sk[k]) k = j;
             }
@@ -1510,7 +1867,7 @@
    return;
    }
 
-static inline void reorder(unsigned int j, unsigned long cursec,
+static inline int reorder(unsigned int j, unsigned long cursec,
                  unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
    Scsi_Cmnd *SCpnt;
    struct mscp *cpp;
@@ -1519,6 +1876,7 @@
    unsigned int input_only = TRUE, overlap = FALSE;
    unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
    unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+   unsigned long ioseek = 0;
 
    static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
    static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1529,10 +1887,10 @@
       printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
              " av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
              ovlcount, readycount, readysorted, sortcount, revcount,
-             seeknosort / (readycount + 1), 
+             seeknosort / (readycount + 1),
              seeksorted / (readycount + 1));
 
-   if (n_ready <= 1) return;
+   if (n_ready <= 1) return FALSE;
 
    for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
@@ -1543,12 +1901,13 @@
       if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
 
       sl[n] = SCpnt->request.sector;
+      ioseek += SCpnt->request.nr_sectors;
 
       if (!n) continue;
 
       if (sl[n] < sl[n - 1]) s = FALSE;
       if (sl[n] > sl[n - 1]) r = FALSE;
-   
+
       if (link_statistics) {
          if (sl[n] > sl[n - 1])
             seek += sl[n] - sl[n - 1];
@@ -1564,6 +1923,8 @@
 
    if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
 
+   if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
    if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
@@ -1571,7 +1932,7 @@
       ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
 
       if (!n) continue;
- 
+
       if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
           || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
       }
@@ -1580,15 +1941,15 @@
 
    if (link_statistics) {
       if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
-      batchcount++; readycount += n_ready, seeknosort += seek / 1024; 
+      batchcount++; readycount += n_ready, seeknosort += seek / 1024;
       if (input_only) inputcount++;
-      if (overlap) { ovlcount++; seeksorted += seek / 1024; }
+      if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
       else seeksorted += (iseek + maxsec - minsec) / 1024;
       if (rev && !r)     {  revcount++; readysorted += n_ready; }
       if (!rev && !s)    { sortcount++; readysorted += n_ready; }
       }
 
-#if defined (DEBUG_LINKED_COMMANDS)
+#if defined(DEBUG_LINKED_COMMANDS)
    if (link_statistics && (overlap || !(flushcount % link_statistics)))
       for (n = 0; n < n_ready; n++) {
          k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
@@ -1597,10 +1958,11 @@
                 (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
                 SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
                 SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
-                YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), 
+                YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
                 YESNO(overlap), cpp->din);
          }
 #endif
+   return overlap;
 }
 
 static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
@@ -1622,13 +1984,13 @@
       il[n_ready++] = k;
       }
 
-   reorder(j, cursec, ihdlr, il, n_ready);
-  
+   if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
+
    for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
 
       if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
-         printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
+         printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
                 " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
                 SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
          HD(j)->cp_stat[k] = ABORTING;
@@ -1640,254 +2002,258 @@
 
 }
 
-static void eata2x_interrupt_handler(int irq, void *dev_id,
-                                     struct pt_regs *regs) {
+static inline void ihdlr(int irq, unsigned int j) {
    Scsi_Cmnd *SCpnt;
-   unsigned long flags;
-   unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, reg;
-   struct mssp *spp;
+   unsigned int i, k, c, status, tstatus, reg;
+   struct mssp *dspp, *spp;
    struct mscp *cpp;
 
-   save_flags(flags);
-   cli();
+   if (sh[j]->irq != irq)
+       panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
 
-   if (!irqlist[irq]) {
-      printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
-      restore_flags(flags);
+   /* Check if this board need to be serviced */
+   if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) return;
+
+   HD(j)->iocount++;
+
+   if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
+                        HD(j)->iocount);
+
+   /* Check if this board is still busy */
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      reg = inb(sh[j]->io_port + REG_STATUS);
+      printk("%s: ihdlr, busy timeout error,  irq %d, reg 0x%x, count %d.\n",
+             BN(j), irq, reg, HD(j)->iocount);
       return;
       }
 
-   if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n", 
-			driver_name, irq, calls[irq]);
+   dspp = &HD(j)->sp[0];
+   spp  = &HD(j)->sp[1];
 
-   /* Service all the boards configured on this irq */
-   for (j = 0; sh[j] != NULL; j++) {
+   /* Make a local copy just before clearing the interrupt indication */
+   memcpy(spp, dspp, sizeof(struct mssp));
 
-      if (sh[j]->irq != irq) continue;
+   /* Clear the completion flag and cp pointer on the dynamic copy of sp */
+   memset(dspp, 0, sizeof(struct mssp));
 
-      loops = 0;
-
-      /* Loop until all interrupts for a board are serviced */
-      while (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) {
-	 total_loops++;
-	 loops++;
-
-	 if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
-			      BN(j), HD(j)->iocount);
-   
-	 /* Read the status register to clear the interrupt indication */
-	 reg = inb(sh[j]->io_port + REG_STATUS);
-   
-	 /* Service all mailboxes of this board */
-	 for (i = 0; i < sh[j]->can_queue; i++) {
-	    spp = &HD(j)->sp[i];
-   
-	    /* Check if this mailbox has completed the operation */
-	    if (spp->eoc == FALSE) continue;
-   
-	    spp->eoc = FALSE;
-   
-	    if (HD(j)->cp_stat[i] == IGNORE) {
-	       HD(j)->cp_stat[i] = FREE;
-	       continue;
-	       }
-	    else if (HD(j)->cp_stat[i] == LOCKED) {
-	       HD(j)->cp_stat[i] = FREE;
-	       printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
-		      BN(j), i, HD(j)->iocount);
-	       continue;
-	       }
-	    else if (HD(j)->cp_stat[i] == FREE) {
-	       printk("%s: ihdlr, mbox %d is free, count %d.\n", 
-		      BN(j), i, HD(j)->iocount);
-	       continue;
-	       }
-	    else if (HD(j)->cp_stat[i] == IN_RESET)
-	       printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
-	    else if (HD(j)->cp_stat[i] != IN_USE) 
-	       panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
-   
-	    HD(j)->cp_stat[i] = FREE;
-	    cpp = &HD(j)->cp[i];
-	    SCpnt = spp->SCpnt;
-   
-	    if (SCpnt == NULL)
-	       panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
-   
-	    if (SCpnt != cpp->SCpnt)
-	       panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n",
-		     BN(j), i, SCpnt, cpp->SCpnt);
-   
-	    if (SCpnt->host_scribble == NULL)
-	       panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
-		     BN(j), i, SCpnt->pid, SCpnt);
-   
-	    if (*(unsigned int *)SCpnt->host_scribble != i) 
-	       panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
-		     " irq %d.\n", BN(j), i, SCpnt->pid, 
-		     *(unsigned int *)SCpnt->host_scribble, irq);
-   
-         if (linked_comm && SCpnt->device->queue_depth > 2
-                                           && TLDEV(SCpnt->device->type))
-            flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
-
-	    tstatus = status_byte(spp->target_status);
-   
-	    switch (spp->adapter_status) {
-	       case ASOK:     /* status OK */
-   
-		  /* Forces a reset if a disk drive keeps returning BUSY */
-		  if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
-		     status = DID_ERROR << 16;
-   
-		  /* If there was a bus reset, redo operation on each target */
-		  else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
-     		           && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
-		     status = DID_BUS_BUSY << 16;
-   
-		  /* Works around a flaw in scsi.c */
-		  else if (tstatus == CHECK_CONDITION
-			   && SCpnt->device->type == TYPE_DISK
-			   && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
-		     status = DID_BUS_BUSY << 16;
-
-		  else
-		     status = DID_OK << 16;
-   
-		  if (tstatus == GOOD)
-		     HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
-   
-		  if (spp->target_status && SCpnt->device->type == TYPE_DISK)
-		     printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
-                            "target_status 0x%x, sense key 0x%x.\n", BN(j), 
-			    SCpnt->channel, SCpnt->target, SCpnt->lun, 
-                            SCpnt->pid, spp->target_status, 
-                            SCpnt->sense_buffer[2]);
-   
-		  HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
-   
-                  if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
-
-		  break;
-	       case ASST:     /* Selection Time Out */
-	       case 0x02:     /* Command Time Out   */
-   
-		  if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
-		     status = DID_ERROR << 16;
-		  else {
-		     status = DID_TIME_OUT << 16;
-		     HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
-		     }
-   
-		  break;
-
-               /* Perform a limited number of internal retries */
-	       case 0x03:     /* SCSI Bus Reset Received */
-	       case 0x04:     /* Initial Controller Power-up */
-   
-		  for (c = 0; c <= sh[j]->max_channel; c++) 
-		     for (k = 0; k < sh[j]->max_id; k++) 
-		        HD(j)->target_redo[k][c] = TRUE;
-   
-	          if (SCpnt->device->type != TYPE_TAPE
-                      && HD(j)->retries < MAX_INTERNAL_RETRIES) {
-		     status = DID_BUS_BUSY << 16;
-		     HD(j)->retries++;
-                     HD(j)->last_retried_pid = SCpnt->pid;
-                     }
-	          else 
-		     status = DID_ERROR << 16;
-
-		  break;
-	       case 0x05:     /* Unexpected Bus Phase */
-	       case 0x06:     /* Unexpected Bus Free */
-	       case 0x07:     /* Bus Parity Error */
-	       case 0x08:     /* SCSI Hung */
-	       case 0x09:     /* Unexpected Message Reject */
-	       case 0x0a:     /* SCSI Bus Reset Stuck */
-	       case 0x0b:     /* Auto Request-Sense Failed */
-	       case 0x0c:     /* Controller Ram Parity Error */
-	       default:
-		  status = DID_ERROR << 16;
-		  break;
-	       }
-   
-	    SCpnt->result = status | spp->target_status;
-	    HD(j)->iocount++;
+   /* Read the status register to clear the interrupt indication */
+   reg = inb(sh[j]->io_port + REG_STATUS);
+
+   /* Reject any sp with supspect data */
+   if (spp->eoc == FALSE)
+      printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n",
+             BN(j), irq, reg, HD(j)->iocount);
+   if (spp->cpp == NULL)
+      printk("%s: ihdlr, spp->cpp == NULL,  irq %d, reg 0x%x, count %d.\n",
+             BN(j), irq, reg, HD(j)->iocount);
+   if (spp->eoc == FALSE || spp->cpp == NULL) return;
 
-	    if (loops > 1) HD(j)->multicount++;
+   cpp = spp->cpp;
 
-#if defined (DEBUG_INTERRUPT)
-	    if (SCpnt->result || do_trace)
-#else
-	    if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
-		(spp->adapter_status != ASOK && 
-		spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
-		do_trace || msg_byte(spp->target_status))
+#if defined(DEBUG_GENERATE_ABORTS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
 #endif
-	       printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
-		      " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
-		      BN(j), i, spp->adapter_status, spp->target_status,
-		      SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
-                      reg, HD(j)->iocount);
-   
-	    /* Set the command state to inactive */
-	    SCpnt->host_scribble = NULL;
-   
-	    restore_flags(flags);
-	    SCpnt->scsi_done(SCpnt);
-	    cli();
 
-	    }   /* Mailbox loop */
+   /* Find the mailbox to be serviced on this board */
+   i = cpp - HD(j)->cp;
 
-	 }   /* Multiple command loop */
+   if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
+                                     || i >= sh[j]->can_queue)
+      panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
+            cpp, HD(j)->cp);
 
-      }   /* Boards loop */
+   if (HD(j)->cp_stat[i] == IGNORE) {
+      HD(j)->cp_stat[i] = FREE;
+      return;
+      }
+   else if (HD(j)->cp_stat[i] == LOCKED) {
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
+             HD(j)->iocount);
+      return;
+      }
+   else if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
+             HD(j)->iocount);
+      return;
+      }
+   else if (HD(j)->cp_stat[i] == IN_RESET)
+      printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+   else if (HD(j)->cp_stat[i] != IN_USE)
+      panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
+            BN(j), i, HD(j)->cp_stat[i]);
+
+   HD(j)->cp_stat[i] = FREE;
+   SCpnt = cpp->SCpnt;
+
+   if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+   if (SCpnt->host_scribble == NULL)
+      panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
+            SCpnt->pid, SCpnt);
+
+   if (*(unsigned int *)SCpnt->host_scribble != i)
+      panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
+            BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
 
-   calls[irq]++;
+   if (linked_comm && SCpnt->device->queue_depth > 2
+                                     && TLDEV(SCpnt->device->type))
+      flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
 
-#if defined (DEBUG_SMP)
-   if (total_loops == 0) 
-     printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
-	    driver_name, irq, calls[irq]);
+   tstatus = status_byte(spp->target_status);
+
+#if defined(DEBUG_GENERATE_ERRORS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2))
+                                           spp->adapter_status = 0x01;
 #endif
 
-   if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n", 
-			driver_name, irq, calls[irq]);
+   switch (spp->adapter_status) {
+      case ASOK:     /* status OK */
+
+         /* Forces a reset if a disk drive keeps returning BUSY */
+         if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
+            status = DID_ERROR << 16;
+
+         /* If there was a bus reset, redo operation on each target */
+         else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+                  && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
+            status = DID_BUS_BUSY << 16;
+
+         /* Works around a flaw in scsi.c */
+         else if (tstatus == CHECK_CONDITION
+                  && SCpnt->device->type == TYPE_DISK
+                  && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+            status = DID_BUS_BUSY << 16;
+
+         else
+            status = DID_OK << 16;
+
+         if (tstatus == GOOD)
+            HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
+
+         if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+            printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
+                   "target_status 0x%x, sense key 0x%x.\n", BN(j),
+                   SCpnt->channel, SCpnt->target, SCpnt->lun,
+                   SCpnt->pid, spp->target_status,
+                   SCpnt->sense_buffer[2]);
+
+         HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
+
+         if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
+
+         break;
+      case ASST:     /* Selection Time Out */
+      case 0x02:     /* Command Time Out   */
+
+         if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
+            status = DID_ERROR << 16;
+         else {
+            status = DID_TIME_OUT << 16;
+            HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
+            }
 
-#if defined (DEBUG_STATISTICS)
-   if ((calls[irq] % 100000) == 10000)
-      for (j = 0; sh[j] != NULL; j++)
-	 printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
-		calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
+         break;
+
+      /* Perform a limited number of internal retries */
+      case 0x03:     /* SCSI Bus Reset Received */
+      case 0x04:     /* Initial Controller Power-up */
+
+         for (c = 0; c <= sh[j]->max_channel; c++)
+            for (k = 0; k < sh[j]->max_id; k++)
+               HD(j)->target_redo[k][c] = TRUE;
+
+         if (SCpnt->device->type != TYPE_TAPE
+             && HD(j)->retries < MAX_INTERNAL_RETRIES) {
+
+#if defined(DID_SOFT_ERROR)
+            status = DID_SOFT_ERROR << 16;
+#else
+            status = DID_BUS_BUSY << 16;
+#endif
+            HD(j)->retries++;
+            HD(j)->last_retried_pid = SCpnt->pid;
+            }
+         else
+            status = DID_ERROR << 16;
+
+         break;
+      case 0x05:     /* Unexpected Bus Phase */
+      case 0x06:     /* Unexpected Bus Free */
+      case 0x07:     /* Bus Parity Error */
+      case 0x08:     /* SCSI Hung */
+      case 0x09:     /* Unexpected Message Reject */
+      case 0x0a:     /* SCSI Bus Reset Stuck */
+      case 0x0b:     /* Auto Request-Sense Failed */
+      case 0x0c:     /* Controller Ram Parity Error */
+      default:
+         status = DID_ERROR << 16;
+         break;
+      }
+
+   SCpnt->result = status | spp->target_status;
+
+#if defined(DEBUG_INTERRUPT)
+   if (SCpnt->result || do_trace)
+#else
+   if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
+       (spp->adapter_status != ASOK &&
+        spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+        do_trace || msg_byte(spp->target_status))
 #endif
+      printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
+             " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
+             BN(j), i, spp->adapter_status, spp->target_status,
+             SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
+             reg, HD(j)->iocount);
+
+   /* Set the command state to inactive */
+   SCpnt->host_scribble = NULL;
+
+   SCpnt->scsi_done(SCpnt);
+
+   if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
+                        HD(j)->iocount);
 
-   restore_flags(flags);
    return;
 }
 
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+   unsigned int j;
+   IRQ_FLAGS
+   SPIN_FLAGS
+
+   /* Check if the interrupt must be processed by this handler */
+   if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
+
+   SPIN_LOCK_SAVE
+   IRQ_LOCK_SAVE
+   ihdlr(irq, j);
+   IRQ_UNLOCK_RESTORE
+   SPIN_UNLOCK_RESTORE
+}
+
 int eata2x_release(struct Scsi_Host *shpnt) {
-   unsigned long flags;
    unsigned int i, j;
+   IRQ_FLAGS
 
-   save_flags(flags);
-   cli();
+   IRQ_LOCK_SAVE
 
    for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
-    
+
    if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
                             driver_name);
 
-   for (i = 0; i < sh[j]->can_queue; i++) 
+   for (i = 0; i < sh[j]->can_queue; i++)
       if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
 
-   if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+   free_irq(sh[j]->irq, &sha[j]);
 
    if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
 
    release_region(sh[j]->io_port, sh[j]->n_io_port);
    scsi_unregister(sh[j]);
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return FALSE;
 }
 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v2.0.33/linux/drivers/scsi/eata.h	Mon Sep 15 09:41:28 1997
+++ linux/drivers/scsi/eata.h	Wed Jun  3 15:17:48 1998
@@ -1,41 +1,59 @@
 /*
- *	eata.h - used by the low-level driver for EATA/DMA SCSI host adapters.
+ *        eata.h - used by the low-level driver for EATA/DMA SCSI host adapters.
  */
 #ifndef _EATA_H
 #define _EATA_H
 
 #include <scsi/scsicam.h>
+#include <linux/version.h>
 
 int eata2x_detect(Scsi_Host_Template *);
 int eata2x_release(struct Scsi_Host *);
 int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int eata2x_abort(Scsi_Cmnd *);
-int eata2x_reset(Scsi_Cmnd *, unsigned int);
+int eata2x_old_abort(Scsi_Cmnd *);
+int eata2x_reset(Scsi_Cmnd *);
+int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
 
-#define EATA_VERSION "3.11.00"
+#define EATA_VERSION "4.31.00"
 
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+#define EATA {                                                               \
+                name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
+                detect:                  eata2x_detect,                      \
+                release:                 eata2x_release,                     \
+                queuecommand:            eata2x_queuecommand,                \
+                abort:                   eata2x_old_abort,                   \
+                reset:                   eata2x_old_reset,                   \
+                eh_abort_handler:        eata2x_abort,                       \
+                eh_device_reset_handler: NULL,                               \
+                eh_bus_reset_handler:    NULL,                               \
+                eh_host_reset_handler:   eata2x_reset,                       \
+                bios_param:              scsicam_bios_param,                 \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING,                  \
+                use_new_eh_code:         1    /* Enable new error code */    \
+             }
+
+#else /* Use old scsi code */
+
+#define EATA {                                                               \
+                name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
+                detect:                  eata2x_detect,                      \
+                release:                 eata2x_release,                     \
+                queuecommand:            eata2x_queuecommand,                \
+                abort:                   eata2x_old_abort,                   \
+                reset:                   eata2x_old_reset,                   \
+                bios_param:              scsicam_bios_param,                 \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING                   \
+             }
+
+#endif
 
-#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                              \
-		}
 #endif
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.0.33/linux/drivers/scsi/ide-scsi.c	Mon Aug  4 11:45:55 1997
+++ linux/drivers/scsi/ide-scsi.c	Wed Jun  3 15:17:48 1998
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.3 - ALPHA	Jul  24, 1997
+ * linux/drivers/scsi/ide-scsi.c	Version 0.31 - ALPHA	Apr   3, 1998
  *
  * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
@@ -17,6 +17,8 @@
  *                       Avoid using bitfields in structures for m68k.
  *                       Added Scather/Gather and DMA support.
  * Ver 0.3   Jul 24 97   Add support for ATAPI PD/CD drives.
+ * Ver 0.31  Apr  3 98   Remove buggy MODE_SENSE6/MODE_SELECT6 translation.
+ *                       Add variable irq timeout support.
  */
 
 #include <linux/module.h>
@@ -55,6 +57,7 @@
 	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
 	void (*done)(Scsi_Cmnd *);		/* Scsi completion routine */
 	unsigned int flags;			/* Status/Action flags */
+	unsigned long timeout;			/* Command timeout */
 } idescsi_pc_t;
 
 /*
@@ -151,8 +154,7 @@
 static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->scsi;
-	u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
-	int i;
+	u8 *c = pc->c;
 
 	if (scsi->media == TYPE_ROM) {
 		if (c[0] == READ_6 || c[0] == WRITE_6) {
@@ -160,14 +162,6 @@
 			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
 			c[0] += (READ_10 - READ_6);
 		}
-		if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) {
-			pc->request_transfer -= 4;
-			memset (c, 0, 12);
-			c[0] = sc[0] | 0x40;	c[2] = sc[2];		c[8] = sc[4] - 4;
-			if (c[0] == MODE_SENSE_10) return;
-			for (i = 0; i <= 7; i++) buf[i] = 0;
-			for (i = 8; i < pc->buffer_size - 4; i++) buf[i] = buf[i + 4];
-		}
 	}
 }
 
@@ -175,15 +169,8 @@
 {
 	idescsi_scsi_t *scsi = drive->scsi;
 	u8 *buf = pc->buffer;
-	int i;
 
 	if (scsi->media == TYPE_ROM) {
-		if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) {
-			buf[0] = buf[1];	buf[1] = buf[2];
-			buf[2] = 0;		buf[3] = 8;
-			for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4];
-			for (i = 11; i >= 4; i--) buf[i] = 0;
-		}
 		if (pc->c[0] == INQUIRY)
 			buf[2] |= 2;
 	}
@@ -235,6 +222,11 @@
 	scsi->pc = NULL;
 }
 
+static inline unsigned long get_timeout(idescsi_pc_t *pc)
+{
+	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+}
+
 /*
  *	Our interrupt handler.
  */
@@ -285,7 +277,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
 				idescsi_discard_data (drive,bcount);
-				ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD);
+				ide_set_handler (drive, &idescsi_pc_intr, get_timeout(pc));
 				return;
 			}
 #if IDESCSI_DEBUG_LOG
@@ -307,12 +299,13 @@
 	pc->actually_transferred+=bcount;				/* Update the current position */
 	pc->current_position+=bcount;
 
-	ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD);		/* And set the interrupt handler again */
+	ide_set_handler (drive,&idescsi_pc_intr,get_timeout(pc));	/* And set the interrupt handler again */
 }
 
 static void idescsi_transfer_pc (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->scsi;
+	idescsi_pc_t *pc=scsi->pc;
 	byte ireason;
 
 	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
@@ -325,8 +318,8 @@
 		ide_do_reset (drive);
 		return;
 	}
-	ide_set_handler (drive, &idescsi_pc_intr, WAIT_CMD);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, scsi->pc->c, 12);		/* Send the actual packet */
+	ide_set_handler (drive, &idescsi_pc_intr, get_timeout(pc));	/* Set the interrupt routine */
+	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
 }
 
 /*
@@ -358,7 +351,7 @@
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 	}
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ide_set_handler (drive, &idescsi_transfer_pc, WAIT_CMD);
+		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc));
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -431,6 +424,8 @@
 	scsi->media = (drive->id->config >> 8) & 0x1f;
 	if (drive->id && (drive->id->config & 0x0060) == 0x20)
 		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
+	printk ("ATAPI overlap supported: %s\n",
+		drive->id->capability & 0x20 ? "Yes" : "No");	
 }
 
 int idescsi_detect (Scsi_Host_Template *host_template)
@@ -562,6 +557,7 @@
 	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
 	pc->scsi_cmd = cmd;
 	pc->done = done;
+	pc->timeout = jiffies + cmd->timeout_per_command;
 	idescsi_transform_pc1 (drive, pc);
 
 	ide_init_drive_cmd (rq);
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v2.0.33/linux/drivers/scsi/in2000.c	Tue Aug  5 13:26:17 1997
+++ linux/drivers/scsi/in2000.c	Wed Jun  3 15:17:48 1998
@@ -123,8 +123,8 @@
 #include "hosts.h"
 
 
-#define IN2000_VERSION    "1.31"
-#define IN2000_DATE       "06/July/1997"
+#define IN2000_VERSION    "1.32"
+#define IN2000_DATE       "28/March/1998"
 
 /*
  * Note - the following defines have been moved to 'in2000.h':
@@ -2031,18 +2031,12 @@
          continue;
          }
 
-/* Let's expect only known legal hardware version here. There
- * can't be THAT many of them, and it's easy to add new ones
- * as we hear about them.
+/* Let's assume any hardware version will work, although the driver
+ * has only been tested on 0x21, 0x22, 0x25, 0x26, and 0x27. We'll
+ * print out the rev number for reference later, but accept them all.
  */
 
       hrev = inb(base + IO_HARDWARE);
-      if ((hrev != 0x27) && (hrev != 0x26) && (hrev != 0x25)) {
-         printk("The IN-2000 SCSI card at IOport 0x%03x ",base);
-         printk("has unknown version %02x hardware - ",hrev);
-         printk("Sorry, cancelling detection.\n");
-         continue;
-         }
 
   /* Bit 2 tells us if interrupts are disabled */
       if (switches & SW_DISINT) {
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- v2.0.33/linux/drivers/scsi/in2000.h	Tue Aug  5 13:26:17 1997
+++ linux/drivers/scsi/in2000.h	Wed Jun  3 15:17:48 1998
@@ -2,7 +2,7 @@
  *    in2000.h -  Linux device driver definitions for the
  *                Always IN2000 ISA SCSI card.
  *
- *    IMPORTANT: This file is for version 1.31 - 06/Jul/1997
+ *    IMPORTANT: This file is for version 1.32 - 28/Mar/1998
  *
  * Copyright (c) 1996 John Shifflett, GeoLog Consulting
  *    john@geolog.com
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/in2000.readme linux/drivers/scsi/in2000.readme
--- v2.0.33/linux/drivers/scsi/in2000.readme	Tue Aug 12 13:46:28 1997
+++ linux/drivers/scsi/in2000.readme	Wed Dec 31 16:00:00 1969
@@ -1,155 +0,0 @@
-
-UPDATE NEWS: version 1.28 - 07 May 96
-
-   Tightened up the "interrupts enabled/disabled" discipline
-   in 'in2000_queuecommand()' and maybe 1 or 2 other places.
-   I _think_ it may have been a little too lax, causing an
-   occasional crash during full moon. A fully functional
-   /proc interface is now in place - if you want to play
-   with it, start by doing 'cat /proc/scsi/in2000/0'. You
-   can also use it to change a few run-time parameters on
-   the fly, but it's mostly for debugging. The curious
-   should take a good look at 'in2000_proc_info()' in the
-   in2000.c file to get an understanding of what it's all
-   about; I figure that people who are really into it will
-   want to add features suited to their own needs...
-   Also, sync is now DISABLED by default.
-
-UPDATE NEWS: version 1.27 - 10 Apr 96
-
-   Fixed a well-hidden bug in the adaptive-disconnect code
-   that would show up every now and then during extreme
-   heavy loads involving 2 or more simultaneously active
-   devices. Thanks to Joe Mack for keeping my nose to the
-   grindstone on this one.
-
-UPDATE NEWS: version 1.26 - 07 Mar 96
-
-   1.25 had a nasty bug that bit people with swap partitions
-   and tape drives. Also, in my attempt to guess my way
-   through Intel assembly language, I made an error in the
-   inline code for IO writes. Made a few other changes and
-   repairs - this version (fingers crossed) should work well.
-
-UPDATE NEWS: version 1.25 - 05 Mar 96
-
-   Kernel 1.3.70 interrupt mods added; old kernels still OK.
-   Big help from Bill Earnest and David Willmore on speed
-   testing and optimizing: I think there's a real improvement
-   in this area.
-   New! User-friendly command-line interface for LILO and
-   module loading - the old method is gone, so you'll need
-   to read the comments for 'setup_strings' near the top
-   of in2000.c. For people with CDROM's or other devices
-   that have a tough time with sync negotiation, you can
-   now selectively disable sync on individual devices -
-   search for the 'nosync' keyword in the command-line
-   comments. Some of you disable the BIOS on the card, which
-   caused the auto-detect function to fail; there is now a
-   command-line option to force detection of a ROM-less card.
-
-UPDATE NEWS: version 1.24a - 24 Feb 96
-
-   There was a bug in the synchronous transfer code. Only
-   a few people downloaded before I caught it - could have
-   been worse.
-
-UPDATE NEWS: version 1.24 - 23 Feb 96
-
-   Lots of good changes. Advice from Bill Earnest resulted
-   in much better detection of cards, more efficient usage
-   of the fifo, and (hopefully) faster data transfers. The
-   jury is still out on speed - I hope it's improved some.
-   One nifty new feature is a cool way of doing disconnect/
-   reselect. The driver defaults to what I'm calling
-   'adaptive disconnect' - meaning that each command is
-   evaluated individually as to whether or not it should be
-   run with the option to disconnect/reselect (if the device
-   chooses), or as a "SCSI-bus-hog". When several devices
-   are operating simultaneously, disconnects are usually an
-   advantage. In a single device system, or if only 1 device
-   is being accessed, transfers usually go faster if disconnects
-   are not allowed.
-
-
-
-The default arguments (you get these when you don't give an 'in2000'
-command-line argument, or you give a blank argument) will cause
-the driver to do adaptive disconnect, synchronous transfers, and a
-minimum of debug messages. If you want to fool with the options,
-search for 'setup_strings' near the top of the in2000.c file and
-check the 'hostdata->args' section in in2000.h - but be warned! Not
-everything is working yet (some things will never work, probably).
-I believe that disabling disconnects (DIS_NEVER) will allow you
-to choose a LEVEL2 value higher than 'L2_BASIC', but I haven't
-spent a lot of time testing this. You might try 'ENABLE_CLUSTERING'
-to see what happens: my tests showed little difference either way.
-There's also a define called 'DEFAULT_SX_PER'; this sets the data
-transfer speed for the asynchronous mode. I've put it at 500 ns
-despite the fact that the card could handle settings of 376 or
-252, because I'm not really sure if certain devices or maybe bad
-cables might have trouble at higher speeds. I couldn't find any
-info in my various SCSI references that talk about this in language
-I could understand, so decided to compromise with 500. This is still
-faster than the old driver was set at (I think). Can someone explain
-the significance of the bus transfer speed setting? Do devices on
-the bus ever care what it is? Is cable quality a factor here?
-Regardless, you can choose your own default through the command-
-line with the 'period' keyword.
-
-
-------------------------------------------------
-***********  DIP switch settings  **************
-------------------------------------------------
-
-   sw1-1 sw1-2    BIOS address (hex)
-   -----------------------------------------
-    off   off     C8000 - CBFF0
-    on    off     D8000 - DBFF0
-    off   on      D0000 - D3FF0
-    on    on      BIOS disabled
-
-   sw1-3 sw1-4    IO port address (hex)
-   ------------------------------------
-    off   off     220 - 22F
-    on    off     200 - 20F
-    off   on      110 - 11F
-    on    on      100 - 10F
-
-   sw1-5 sw1-6 sw1-7    Interrupt
-   ------------------------------
-    off   off   off     15
-    off   on    off     14
-    off   off   on      11
-    off   on    on      10
-    on    -     -       disabled
-
-   sw1-8 function depends on BIOS version. In earlier versions this
-   controlled synchronous data transfer support for MSDOS:
-      off = disabled
-      on  = enabled
-   In later ROMs (starting with 01.3 in April 1994) sw1-8 controls
-   the "greater than 2 disk drive" feature that first appeared in
-   MSDOS 5.0 (ignored by linux):
-      off = 2 drives maximum
-      on  = 7 drives maximum
-
-   sw1-9    Floppy controller
-   --------------------------
-    off     disabled
-    on      enabled
-
-------------------------------------------------
-
-   I should mention that Drew Eckhardt's 'Generic NCR5380' sources
-   were my main inspiration, with lots of reference to the IN2000
-   driver currently distributed in the kernel source. I also owe
-   much to a driver written by Hamish Macdonald for Linux-m68k(!).
-   And to Eric Wright for being an ALPHA guinea pig. And to Bill
-   Earnest for 2 tons of great input and information. And to David
-   Willmore for extensive 'bonnie' testing. And to Joe Mack for
-   continual testing and feedback.
-
-
-            John Shifflett    jshiffle@netcom.com
-
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.0.33/linux/drivers/scsi/ncr53c8xx.c	Thu Aug 21 15:13:05 1997
+++ linux/drivers/scsi/ncr53c8xx.c	Wed Jun  3 15:17:49 1998
@@ -60,11 +60,14 @@
 **  May 19 1997 by Richard Waltham <dormouse@farsrobt.demon.co.uk>:
 **     Support for NvRAM detection and reading.
 **
+**  August 18 1997 by Cort <cort@cs.nmt.edu>:
+**     Support for Power/PC (Big Endian).
+**
 *******************************************************************************
 */
 
 /*
-**	21 August 1997, version 2.4a
+**	30 January 1998, version 2.5f.1
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -306,6 +309,7 @@
 **	architecture.
 */
 
+#ifndef NCR_IOMAPPED
 __initfunc(
 static vm_offset_t remap_pci_mem(u_long base, u_long size)
 )
@@ -332,6 +336,7 @@
 		vfree((void *) (vaddr & PAGE_MASK));
 #endif
 }
+#endif	/* !NCR_IOMAPPED */
 
 #else /* linux-1.2.13 */
 
@@ -452,9 +457,9 @@
 /*
 **	Head of list of NCR boards
 **
-**	Host is retrieved by its irq level.
-**	If interrupts are shared, the internal host control block 
-**	address (struct ncb) is used as device id.
+**	For kernel version < 1.3.70, host is retrieved by its irq level.
+**	For later kernels, the internal host control block address 
+**	(struct ncb) is used as device id parameter of the irq stuff.
 */
 
 static struct Scsi_Host		*first_host	= NULL;
@@ -499,7 +504,7 @@
 	unsigned master_parity	: 1;
 	unsigned scsi_parity	: 1;
 	unsigned disconnection	: 1;
-	unsigned special_features : 1;
+	unsigned special_features : 2;
 	unsigned ultra_scsi	: 2;
 	unsigned force_sync_nego: 1;
 	unsigned reverse_probe: 1;
@@ -515,6 +520,7 @@
 	u_char	settle_delay;
 	u_char	diff_support;
 	u_char	irqm;
+	u_char	bus_check;
 };
 
 static struct ncr_driver_setup
@@ -523,6 +529,9 @@
 #ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 static struct ncr_driver_setup
 	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
+#ifdef	MODULE
+char *ncr53c8xx = 0;	/* command line passed by insmod */
+#endif
 #endif
 
 /*
@@ -570,7 +579,8 @@
 	u_short	flags1;
 #define SYMBIOS_SCAN_HI_LO	(1)
 	u_short	word10;		/* 0x00 */
-	u_short	word12;		/* 0x00 */
+	u_short	flags3;		/* 0x00 */
+#define SYMBIOS_REMOVABLE_FLAGS	(3)		/* 0=none, 1=bootable, 2=all */
 	u_char	host_id;
 	u_char	byte15;		/* 0x04 */
 	u_short	word16;		/* 0x0410 */
@@ -657,6 +667,7 @@
 	int	bus;
 	u_char	device_fn;
 	u_int	base;
+	u_int	base_2;
 	u_int	io_port;
 	int	irq;
 /* port and reg fields to use INB, OUTB macros */
@@ -684,7 +695,7 @@
 	ncr_slot  slot;
 	ncr_chip  chip;
 	ncr_nvram *nvram;
-	int attached;
+	int attach_done;
 } ncr_device;
 
 /*==========================================================
@@ -743,79 +754,156 @@
 
 /*==========================================================
 **
-**	Access to the controller chip.
-**
-**	If NCR_IOMAPPED is defined, only IO are used by the driver.
+**	Big/Little endian support.
 **
 **==========================================================
 */
 
 /*
-**	IO mapped only input / ouput
+**	If the NCR uses big endian addressing mode over the 
+**	PCI, actual io register addresses for byte and word 
+**	accesses must be changed according to lane routing.
+**	Btw, ncr_offb() and ncr_offw() macros only apply to 
+**	constants and so donnot generate bloated code.
 */
 
-#define	IOM_INB(r)		inb (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INB_OFF(o)		inb (np->port + (o))
-#define	IOM_INW(r)		inw (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL(r)		inl (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL_OFF(o)		inl (np->port + (o))
-
-#define	IOM_OUTB(r, val)	outb ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTW(r, val)	outw ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL(r, val)	outl ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL_OFF(o, val)	outl ((val), np->port + (o))
+#if	defined(SCSI_NCR_BIG_ENDIAN)
+
+#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
+#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
+
+#else
+
+#define ncr_offb(o)	(o)
+#define ncr_offw(o)	(o)
+
+#endif
 
 /*
-**	MEMORY mapped IO input / output
+**	If the CPU and the NCR use same endian-ness adressing,
+**	no byte reordering is needed for script patching.
+**	Macro cpu_to_scr() is to be used for script patching.
+**	Macro scr_to_cpu() is to be used for getting a DWORD 
+**	from the script.
 */
 
-#define MMIO_INB(r)		readb(&np->reg->r)
-#define MMIO_INB_OFF(o)		readb((char *)np->reg + (o))
-#define MMIO_INW(r)		readw(&np->reg->r)
-#define MMIO_INL(r)		readl(&np->reg->r)
-#define MMIO_INL_OFF(o)		readl((char *)np->reg + (o))
-
-#define MMIO_OUTB(r, val)	writeb((val), &np->reg->r)
-#define MMIO_OUTW(r, val)	writew((val), &np->reg->r)
-#define MMIO_OUTL(r, val)	writel((val), &np->reg->r)
-#define MMIO_OUTL_OFF(o, val)	writel((val), (char *)np->reg + (o))
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_le32(dw)
+#define scr_to_cpu(dw)	le32_to_cpu(dw)
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_be32(dw)
+#define scr_to_cpu(dw)	be32_to_cpu(dw)
+
+#else
+
+#define cpu_to_scr(dw)	(dw)
+#define scr_to_cpu(dw)	(dw)
+
+#endif
+
+/*==========================================================
+**
+**	Access to the controller chip.
+**
+**	If NCR_IOMAPPED is defined, only IO are used by the driver.
+**
+**==========================================================
+*/
 
 /*
-**	IO mapped input / output
+**	If the CPU and the NCR use same endian-ness adressing,
+**	no byte reordering is needed for accessing chip io 
+**	registers. Functions suffixed by '_raw' are assumed 
+**	to access the chip over the PCI without doing byte 
+**	reordering. Functions suffixed by '_l2b' are 
+**	assumed to perform little-endian to big-endian byte 
+**	reordering, those suffixed by '_b2l' blah, blah,
+**	blah, ...
 */
 
 #if defined(NCR_IOMAPPED)
 
-#define INB(r)             IOM_INB(r)
-#define INB_OFF(o)         IOM_INB_OFF(o)
-#define INW(r)             IOM_INW(r)
-#define INL(r)             IOM_INL(r)
-#define INL_OFF(o)         IOM_INL_OFF(o)
-
-#define OUTB(r, val)       IOM_OUTB(r, val)
-#define OUTW(r, val)       IOM_OUTW(r, val)
-#define OUTL(r, val)       IOM_OUTL(r, val)
-#define OUTL_OFF(o, val)   IOM_OUTL_OFF(o, val)
+/*
+**	IO mapped only input / ouput
+*/
+
+#define	INB_OFF(o)		inb (np->port + ncr_offb(o))
+#define	OUTB_OFF(o, val)	outb ((val), np->port + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_l2b (np->port + ncr_offw(o))
+#define	INL_OFF(o)		inl_l2b (np->port + (o))
+
+#define	OUTW_OFF(o, val)	outw_b2l ((val), np->port + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_b2l ((val), np->port + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_b2l (np->port + ncr_offw(o))
+#define	INL_OFF(o)		inl_b2l (np->port + (o))
+
+#define	OUTW_OFF(o, val)	outw_l2b ((val), np->port + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_l2b ((val), np->port + (o))
+
+#else
+
+#define	INW_OFF(o)		inw_raw (np->port + ncr_offw(o))
+#define	INL_OFF(o)		inl_raw (np->port + (o))
+
+#define	OUTW_OFF(o, val)	outw_raw ((val), np->port + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_raw ((val), np->port + (o))
+
+#endif	/* ENDIANs */
+
+#else	/* defined NCR_IOMAPPED */
 
 /*
-**	MEMORY mapped only input / output
+**	MEMORY mapped IO input / output
 */
 
+#define INB_OFF(o)		readb((char *)np->reg + ncr_offb(o))
+#define OUTB_OFF(o, val)	writeb((val), (char *)np->reg + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
+
 #else
 
-#define INB(r)             MMIO_INB(r)
-#define INB_OFF(o)         MMIO_INB_OFF(o)
-#define INW(r)             MMIO_INW(r)
-#define INL(r)             MMIO_INL(r)
-#define INL_OFF(o)         MMIO_INL_OFF(o)
-
-#define OUTB(r, val)       MMIO_OUTB(r, val)
-#define OUTW(r, val)       MMIO_OUTW(r, val)
-#define OUTL(r, val)       MMIO_OUTL(r, val)
-#define OUTL_OFF(o, val)   MMIO_OUTL_OFF(o, val)
+#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
 
 #endif
 
+#endif	/* defined NCR_IOMAPPED */
+
+#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
+#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
+#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
+
+#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
+
 /*
 **	Set bit field ON, OFF 
 */
@@ -827,6 +915,7 @@
 #define OUTONL(r, m)	OUTL(r, INL(r) | (m))
 #define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
 
+
 /*==========================================================
 **
 **	Command control block states.
@@ -1264,27 +1353,36 @@
 	**	status fields.
 	*/
 
-	u_char		status[8];
+	u_char		scr_st[4];	/* script status */
+	u_char		status[4];	/* host status. Must be the last */
+					/* DWORD of the CCB header */
 };
 
 /*
 **	The status bytes are used by the host and the script processor.
 **
-**	The first four byte are copied to the scratchb register
+**	The byte corresponding to the host_status must be stored in the 
+**	last DWORD of the CCB header since it is used for command 
+**	completion (ncr_wakeup()). Doing so, we are sure that the header 
+**	has been entirely copied back to the CCB when the host_status is 
+**	seen complete by the CPU.
+**
+**	The last four bytes (status[4]) are copied to the scratchb register
 **	(declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
 **	and copied back just after disconnecting.
 **	Inside the script the XX_REG are used.
 **
-**	The last four bytes are used inside the script by "COPY" commands.
+**	The first four bytes (scr_st[4]) are used inside the script by 
+**	"COPY" commands.
 **	Because source and destination must have the same alignment
-**	in a longword, the fields HAVE to be at the choosen offsets.
-**		xerr_st	(4)	0	(0x34)	scratcha
-**		sync_st	(5)	1	(0x05)	sxfer
-**		wide_st	(7)	3	(0x03)	scntl3
+**	in a DWORD, the fields HAVE to be at the choosen offsets.
+**		xerr_st		0	(0x34)	scratcha
+**		sync_st		1	(0x05)	sxfer
+**		wide_st		3	(0x03)	scntl3
 */
 
 /*
-**	First four bytes (script)
+**	Last four bytes (script)
 */
 #define  QU_REG	scr0
 #define  HS_REG	scr1
@@ -1293,7 +1391,7 @@
 #define  PS_REG	scr3
 
 /*
-**	First four bytes (host)
+**	Last four bytes (host)
 */
 #define  actualquirks  phys.header.status[0]
 #define  host_status   phys.header.status[1]
@@ -1301,15 +1399,15 @@
 #define  parity_status phys.header.status[3]
 
 /*
-**	Last four bytes (script)
+**	First four bytes (script)
 */
-#define  xerr_st       header.status[4]	/* MUST be ==0 mod 4 */
-#define  sync_st       header.status[5]	/* MUST be ==1 mod 4 */
-#define  nego_st       header.status[6]
-#define  wide_st       header.status[7]	/* MUST be ==3 mod 4 */
+#define  xerr_st       header.scr_st[0]
+#define  sync_st       header.scr_st[1]
+#define  nego_st       header.scr_st[2]
+#define  wide_st       header.scr_st[3]
 
 /*
-**	Last four bytes (host)
+**	First four bytes (host)
 */
 #define  xerr_status   phys.xerr_st
 #define  sync_status   phys.sync_st
@@ -1677,9 +1775,11 @@
 	/*
 	**	Timeout handler
 	*/
+#if 0
 	u_long		heartbeat;
 	u_short		ticks;
 	u_short		latetime;
+#endif
 	u_long		lasttime;
 
 	/*-----------------------------------------------
@@ -1771,7 +1871,7 @@
 **	of 825A, 875 and 895 chips.
 */
 struct script {
-	ncrcmd	start		[  7];
+	ncrcmd	start		[  4];
 	ncrcmd	start0		[  2];
 	ncrcmd	start1		[  3];
 	ncrcmd  startpos	[  1];
@@ -1785,7 +1885,7 @@
 	ncrcmd	prepare2	[ 24];
 	ncrcmd	setmsg		[  5];
 	ncrcmd  clrack		[  2];
-	ncrcmd  dispatch	[ 33];
+	ncrcmd  dispatch	[ 38];
 	ncrcmd	no_data		[ 17];
 	ncrcmd  checkatn	[ 10];
 	ncrcmd  command		[ 15];
@@ -1859,7 +1959,7 @@
 static	void	ncr_getclock	(ncb_p np, int mult);
 static	void	ncr_selectclock	(ncb_p np, u_char scntl3);
 static	ccb_p	ncr_get_ccb	(ncb_p np, u_long t,u_long l);
-static	void	ncr_init	(ncb_p np, char * msg, u_long code);
+static	void	ncr_init	(ncb_p np, int reset, char * msg, u_long code);
 static	int	ncr_int_sbmc	(ncb_p np);
 static	int	ncr_int_par	(ncb_p np);
 static	void	ncr_int_ma	(ncb_p np);
@@ -1887,6 +1987,7 @@
 static	void	ncr_timeout	(ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
 static	void	ncr_start_reset	(ncb_p np, int settle_delay);
+static	int	ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
 
 #ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 static	void	ncr_usercmd	(ncb_p np);
@@ -1917,16 +2018,6 @@
 **==========================================================
 */
 
-#if 0
-static char ident[] =
- 	"\n$Id: ncr.c,v 1.67 1996/03/11 19:36:07 se Exp $\n";
-static u_long	ncr_version = NCR_VERSION	* 11
-	+ (u_long) sizeof (struct ncb)	*  7
-	+ (u_long) sizeof (struct ccb)	*  5
-	+ (u_long) sizeof (struct lcb)	*  3
-	+ (u_long) sizeof (struct tcb)	*  2;
-#endif
-
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
 #endif
@@ -1984,13 +2075,14 @@
 
 static	struct script script0 __initdata = {
 /*--------------------------< START >-----------------------*/ {
+#if 0
 	/*
 	**	Claim to be still alive ...
 	*/
 	SCR_COPY (sizeof (((struct ncb *)0)->heartbeat)),
 		KVAR(SCRIPT_KVAR_JIFFIES),
 		NADDR (heartbeat),
-
+#endif
 	/*
 	**      Make data structure address invalid.
 	**      clear SIGP.
@@ -2291,8 +2383,21 @@
 		0,
 	SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)),
 		0,
-	SCR_RETURN ^ IFTRUE (IF (SCR_DATA_IN)),
+	/*
+	**	DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 4.
+	**	Possible data corruption during Memory Write and Invalidate.
+	**	This work-around resets the addressing logic prior to the 
+	**	start of the first MOVE of a DATA IN phase.
+	**	(See README.ncr53c8xx for more information)
+	*/
+	SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
+		20,
+	SCR_COPY (4),
+		RADDR (scratcha),
+		RADDR (scratcha),
+	SCR_RETURN,
 		0,
+
 	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
 		PADDR (msg_out),
 	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)),
@@ -3603,7 +3708,8 @@
 
 	while (src < end) {
 
-		*dst++ = opcode = *src++;
+		opcode = *src++;
+		*dst++ = cpu_to_scr(opcode);
 
 		/*
 		**	If we forget to change the length
@@ -3648,7 +3754,7 @@
 			**	the NO FLUSH bit if present.
 			*/
 			if ((opcode & SCR_NO_FLUSH) && !(np->features & FE_PFEN)) {
-				dst[-1] = (opcode & ~SCR_NO_FLUSH);
+				dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH);
 				++opchanged;
 			}
 			break;
@@ -3721,10 +3827,10 @@
 					break;
 				}
 
-				*dst++ = new;
+				*dst++ = cpu_to_scr(new);
 			}
 		} else
-			*dst++ = *src++;
+			*dst++ = cpu_to_scr(*src++);
 
 	};
 	if (bootverbose > 1 && opchanged)
@@ -3984,15 +4090,6 @@
 	np->maxsync = period > 2540 ? 254 : period / 10;
 
 	/*
-	**	Get on-board RAM bus address when supported
-	*/
-	if (np->features & FE_RAM) {
-		OUTONB(nc_ctest2, 0x8);
-		np->paddr2 = INL(nc_scr0);
-		OUTOFFB(nc_ctest2, 0x8);
-	}
-
-	/*
 	**	Prepare initial value of other IO registers
 	*/
 #if defined SCSI_NCR_TRUST_BIOS_SETTING
@@ -4348,7 +4445,8 @@
 	**	virtual and physical memory.
 	*/
 
-	np->paddr = device->slot.base;
+	np->paddr	= device->slot.base;
+	np->paddr2	= (np->features & FE_RAM)? device->slot.base_2 : 0;
 
 #ifndef NCR_IOMAPPED
 	np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128);
@@ -4456,17 +4554,20 @@
 	*/
 
 	if (np->features & FE_LED0) {
-		np->script0->reselect[0]  = SCR_REG_REG(gpreg, SCR_OR,  0x01);
-		np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
-		np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+		np->script0->reselect[0]  =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR,  0x01));
+		np->script0->reselect1[0] =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
+		np->script0->reselect2[0] =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
 	}
 
 	/*
 	**	init data structure
 	*/
 
-	np->jump_tcb.l_cmd	= SCR_JUMP;
-	np->jump_tcb.l_paddr	= NCB_SCRIPTH_PHYS (np, abort);
+	np->jump_tcb.l_cmd	= cpu_to_scr(SCR_JUMP);
+	np->jump_tcb.l_paddr	= cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
 
 	/*
 	**	Reset chip.
@@ -4497,7 +4598,7 @@
 			SA_INTERRUPT|SA_SHIRQ, "ncr53c8xx", np)) {
 #else
 	if (request_irq(device->slot.irq, ncr53c8xx_intr,
-			SA_INTERRUPT, "ncr53c8xx", NULL)) {
+			SA_INTERRUPT, "ncr53c8xx", np)) {
 #endif
 #else
 	if (request_irq(device->slot.irq, ncr53c8xx_intr,
@@ -4517,7 +4618,11 @@
 	**	Then enable disconnects.
 	*/
 	save_flags(flags); cli();
-	ncr_start_reset(np, driver_setup.settle_delay);
+	if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) {
+		printf("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np));
+		restore_flags(flags);
+		goto attach_error;
+	}
 	ncr_exception (np);
 	restore_flags(flags);
 
@@ -4585,6 +4690,16 @@
 #endif
 		release_region(np->port, 128);
 	}
+	if (np->irq) {
+#ifdef DEBUG_NCR53C8XX
+		printf("%s: freeing irq %d\n", ncr_name(np), np->irq);
+#endif
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
+		free_irq(np->irq, np);
+#else
+		free_irq(np->irq);
+#endif
+	}
 	scsi_unregister(instance);
 
         return -1;
@@ -4654,7 +4769,9 @@
 
 	/*---------------------------------------------------
 	**
-	**	Assign a ccb / bind cmd
+	**	Assign a ccb / bind cmd.
+	**	If resetting, shorten settle_time if necessary
+	**	in order to avoid spurious timeouts.
 	**	If resetting or no free ccb,
 	**	insert cmd into the waiting list.
 	**
@@ -4662,6 +4779,11 @@
 	*/
 	save_flags(flags); cli();
 
+	if (np->settle_time && cmd->timeout_per_command >= HZ &&
+		np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
+		np->settle_time = jiffies + cmd->timeout_per_command - HZ;
+	}
+
         if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
 		insert_into_waiting_list(np, cmd);
 		restore_flags(flags);
@@ -4933,21 +5055,23 @@
 		u_long endp;
 	default:
 	case XferBoth:
-		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+		cp->phys.header.savep =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, data_io));
 		cp->phys.header.goalp = cp->phys.header.savep;
 		break;
 	case XferIn:
 		endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
-		cp->phys.header.goalp = endp + 8;
-		cp->phys.header.savep = endp - segments*16;
+		cp->phys.header.goalp = cpu_to_scr(endp + 8);
+		cp->phys.header.savep = cpu_to_scr(endp - segments*16);
 		break;
 	case XferOut:
 		endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
-		cp->phys.header.goalp = endp + 8;
-		cp->phys.header.savep = endp - segments*16;
+		cp->phys.header.goalp = cpu_to_scr(endp + 8);
+		cp->phys.header.savep = cpu_to_scr(endp - segments*16);
 		break;
 	case XferNone:
-		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+		cp->phys.header.savep =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, no_data));
 		cp->phys.header.goalp = cp->phys.header.savep;
 		break;
 	}
@@ -4968,8 +5092,9 @@
 	/*
 	**	Startqueue
 	*/
-	cp->phys.header.launch.l_paddr	= NCB_SCRIPT_PHYS (np, select);
-	cp->phys.header.launch.l_cmd	= SCR_JUMP;
+	cp->phys.header.launch.l_paddr	=
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+	cp->phys.header.launch.l_cmd	= cpu_to_scr(SCR_JUMP);
 	/*
 	**	select
 	*/
@@ -4979,21 +5104,21 @@
 	/*
 	**	message
 	*/
-	cp->phys.smsg.addr		= CCB_PHYS (cp, scsi_smsg);
-	cp->phys.smsg.size		= msglen;
+	cp->phys.smsg.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
+	cp->phys.smsg.size		= cpu_to_scr(msglen);
 
-	cp->phys.smsg2.addr		= CCB_PHYS (cp, scsi_smsg2);
-	cp->phys.smsg2.size		= msglen2;
+	cp->phys.smsg2.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
+	cp->phys.smsg2.size		= cpu_to_scr(msglen2);
 	/*
 	**	command
 	*/
-	cp->phys.cmd.addr		= vtophys (&cmd->cmnd[0]);
-	cp->phys.cmd.size		= cmd->cmd_len;
+	cp->phys.cmd.addr		= cpu_to_scr(vtophys (&cmd->cmnd[0]));
+	cp->phys.cmd.size		= cpu_to_scr(cmd->cmd_len);
 	/*
 	**	sense command
 	*/
-	cp->phys.scmd.addr		= CCB_PHYS (cp, sensecmd);
-	cp->phys.scmd.size		= 6;
+	cp->phys.scmd.addr		= cpu_to_scr(CCB_PHYS (cp, sensecmd));
+	cp->phys.scmd.size		= cpu_to_scr(6);
 	/*
 	**	patch requested size into sense command
 	*/
@@ -5003,8 +5128,9 @@
 	/*
 	**	sense data
 	*/
-	cp->phys.sense.addr		= vtophys (&cmd->sense_buffer[0]);
-	cp->phys.sense.size		= sizeof(cmd->sense_buffer);
+	cp->phys.sense.addr		=
+			cpu_to_scr(vtophys (&cmd->sense_buffer[0]));
+	cp->phys.sense.size		= cpu_to_scr(sizeof(cmd->sense_buffer));
 	/*
 	**	status
 	*/
@@ -5029,8 +5155,10 @@
 	**	reselect pattern and activate this job.
 	*/
 
-	cp->jump_ccb.l_cmd	= (SCR_JUMP ^ IFFALSE (DATA (cp->tag)));
-	/* Compute a time limit bigger than the middle-level driver one */
+	cp->jump_ccb.l_cmd	=
+		cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (cp->tag))));
+
+	/* Compute a time limit greater than the middle-level driver one */
 	if (cmd->timeout_per_command > 0)
 		cp->tlimit	= jiffies + cmd->timeout_per_command + NCR_TIMEOUT_INCREASE;
 	else
@@ -5043,14 +5171,14 @@
 
 	qidx = np->squeueput + 1;
 	if (qidx >= MAX_START) qidx=0;
-	np->squeue [qidx	 ] = NCB_SCRIPT_PHYS (np, idle);
-	np->squeue [np->squeueput] = CCB_PHYS (cp, phys);
+	np->squeue [qidx	 ] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	np->squeue [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, phys));
 	np->squeueput = qidx;
 
 	if(DEBUG_FLAGS & DEBUG_QUEUE)
 		printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np),
 		np->squeueput,
-		(unsigned)(np->script->startpos[0]- 
+		(unsigned)(scr_to_cpu(np->script->startpos[0]) - 
 			   (NCB_SCRIPTH_PHYS (np, tryloop))));
 
 	/*
@@ -5093,21 +5221,70 @@
 	save_flags(flags); cli();
 
 	if (!np->settle_time) {
-		if (bootverbose > 1)
-			printf("%s: resetting, command processing suspended for %d seconds\n",
-				ncr_name(np), settle_delay);
-		np->settle_time	= jiffies + settle_delay * HZ;
-		OUTB (nc_istat, SRST);
-		DELAY (1000);
-		OUTB (nc_istat, 0);
-		OUTW (nc_sien, RST);
-		OUTB (nc_scntl1, CRST);
-		DELAY (100);
+		(void) ncr_reset_scsi_bus(np, 1, settle_delay);
 	}
-
 	restore_flags(flags);
 }
 
+static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
+{
+	u_int32 term;
+	int retv = 0;
+
+	np->settle_time	= jiffies + settle_delay * HZ;
+
+	if (bootverbose > 1)
+		printf("%s: resetting, "
+			"command processing suspended for %d seconds\n",
+			ncr_name(np), settle_delay);
+
+	OUTB (nc_istat, SRST);
+	DELAY (1000);
+	OUTB (nc_istat, 0);
+	if (enab_int)
+		OUTW (nc_sien, RST);
+	/*
+	**	Enable Tolerant, reset IRQD if present and 
+	**	properly set IRQ mode, prior to resetting the bus.
+	*/
+	OUTB (nc_stest3, TE);
+	OUTB (nc_dcntl, (np->rv_dcntl & IRQM));
+	OUTB (nc_scntl1, CRST);
+	DELAY (100);
+
+	if (!driver_setup.bus_check)
+		goto out;
+	/*
+	**	Check for no terminators or SCSI bus shorts to ground.
+	**	Read SCSI data bus, data parity bits and control signals.
+	**	We are expecting RESET to be TRUE and other signals to be 
+	**	FALSE.
+	*/
+	term =	INB(nc_sstat0);				/* rst, sdp0 */
+	term =	((term & 2) << 7) + ((term & 1) << 16);
+	term |= ((INB(nc_sstat2) & 0x01) << 25) |	/* sdp1 */
+		(INW(nc_sbdl) << 9) |			/* d15-0 */
+		INB(nc_sbcl);	/* req, ack, bsy, sel, atn, msg, cd, io */
+
+	if (!(np->features & FE_WIDE))
+		term &= 0x3ffff;
+
+	if (term != (2<<7)) {
+		printf("%s: suspicious SCSI data while resetting the BUS.\n",
+			ncr_name(np));
+		printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
+			"0x%lx, expecting 0x%lx\n",
+			ncr_name(np),
+			(np->features & FE_WIDE) ? "dp1,d15-8," : "",
+			(u_long)term, (u_long)(2<<7));
+		if (driver_setup.bus_check == 1)
+			retv = 1;
+	}
+out:
+	OUTB (nc_scntl1, 0);
+	return retv;
+}
+
 /*==========================================================
 **
 **
@@ -5146,7 +5323,7 @@
  * Commands will now be queued in the waiting list until a settle 
  * delay of 2 seconds will be completed.
  */
-	ncr_start_reset(np, 2);
+	ncr_start_reset(np, driver_setup.settle_delay);
 /*
  * First, look in the wakeup list
  */
@@ -5256,10 +5433,12 @@
 	**	this condition in order to complete the canceled command 
 	**	after the script skipped the ccb, if necessary.
 	*/
-	cp->jump_ccb.l_cmd = (SCR_JUMP);
-	if (cp->phys.header.launch.l_paddr == NCB_SCRIPT_PHYS (np, select)) {
+	cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
+	if (cp->phys.header.launch.l_paddr ==
+		cpu_to_scr(NCB_SCRIPT_PHYS (np, select))) {
 		printf ("%s: abort ccb=%p (skip)\n", ncr_name (np), cp);
-		cp->phys.header.launch.l_paddr = NCB_SCRIPT_PHYS (np, skip);
+		cp->phys.header.launch.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, skip));
 	}
 
 	cp->tlimit = 0;
@@ -5292,7 +5471,7 @@
 */
 
 #ifdef MODULE
-static int ncr_detach(ncb_p np, int irq)
+static int ncr_detach(ncb_p np)
 {
 	ccb_p cp;
 	tcb_p tp;
@@ -5331,16 +5510,12 @@
 */
 
 #ifdef DEBUG_NCR53C8XX
-	printf("%s: freeing irq %d\n", ncr_name(np), irq);
+	printf("%s: freeing irq %d\n", ncr_name(np), np->irq);
 #endif
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
-#   ifdef SCSI_NCR_SHARE_IRQ
-	free_irq(irq, np);
-#   else
-	free_irq(irq, NULL);
-#   endif
+	free_irq(np->irq, np);
 #else
-	free_irq(irq);
+	free_irq(np->irq);
 #endif
 
 	/*
@@ -5450,12 +5625,12 @@
 	/*
 	**	No Reselect anymore.
 	*/
-	cp->jump_ccb.l_cmd = (SCR_JUMP);
+	cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
 
 	/*
 	**	No starting.
 	*/
-	cp->phys.header.launch.l_paddr= NCB_SCRIPT_PHYS (np, idle);
+	cp->phys.header.launch.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 
 	/*
 	**	timestamp
@@ -5522,10 +5697,12 @@
 	**	Check the status.
 	*/
 	if (   (cp->host_status == HS_COMPLETE)
-		&& (cp->scsi_status == S_GOOD)) {
-
+		&& (cp->scsi_status == S_GOOD ||
+		    cp->scsi_status == S_COND_MET)) {
 		/*
-		**	All went well.
+		**	All went well (GOOD status).
+		**	CONDITION MET status is returned on 
+		**	`Pre-Fetch' or `Search data' success.
 		*/
 		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
 
@@ -5620,7 +5797,8 @@
 		}
 
 	} else if ((cp->host_status == HS_COMPLETE)
-		&& (cp->scsi_status == S_BUSY)) {
+		&& (cp->scsi_status == S_BUSY ||
+		    cp->scsi_status == S_CONFLICT)) {
 
 		/*
 		**   Target is busy.
@@ -5786,16 +5964,21 @@
 **==========================================================
 */
 
-void ncr_init (ncb_p np, char * msg, u_long code)
+void ncr_init (ncb_p np, int reset, char * msg, u_long code)
 {
 	int	i;
 
 	/*
-	**	Reset chip.
+	**	Reset chip if asked, otherwise just clear fifos.
 	*/
-
-	OUTB (nc_istat,  SRST);
-	DELAY (10000);
+	if (reset) {
+		OUTB (nc_istat,  SRST);
+		DELAY (10000);
+	}
+	else {
+		OUTB (nc_stest3, TE|CSF);
+		OUTONB (nc_ctest3, CLF);
+	}
 
 	/*
 	**	Message.
@@ -5807,14 +5990,14 @@
 	**	Clear Start Queue
 	*/
 	for (i=0;i<MAX_START;i++)
-		np -> squeue [i] = NCB_SCRIPT_PHYS (np, idle);
+		np -> squeue [i] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 
 	/*
 	**	Start at first entry.
 	*/
 	np->squeueput = 0;
-	np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
-	np->script0->start0  [0] = SCR_INT ^ IFFALSE (0);
+	np->script0->startpos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tryloop));
+	np->script0->start0  [0] = cpu_to_scr(SCR_INT ^ IFFALSE (0));
 
 	/*
 	**	Wakeup all pending jobs.
@@ -5866,7 +6049,11 @@
 	if (np->vaddr2) {
 		if (bootverbose)
 			printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np));
-		bcopy(np->script0, np->script, sizeof(struct script));
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
+		memcpy_toio(np->script, np->script0, sizeof(struct script));
+#else
+		memcpy(np->script, np->script0, sizeof(struct script));
+#endif
 	}
 
 	/*
@@ -6150,7 +6337,7 @@
 		if	(tp->period < 500)	scsi = "FAST-40";
 		else if	(tp->period < 1000)	scsi = "FAST-20";
 		else if	(tp->period < 2000)	scsi = "FAST-10";
-		else				scsi = "SLOW";
+		else				scsi = "FAST-5";
 
 		printf ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
 			tp->widedone > 1 ? "WIDE " : "",
@@ -6487,7 +6674,6 @@
 {
 	u_long	thistime = jiffies;
 	u_long	count = 0;
-	long signed   t;
 	ccb_p cp;
 	u_long flags;
 
@@ -6561,10 +6747,12 @@
 		**
 		**----------------------------------------------------
 		*/
-
-		t = (thistime - np->heartbeat) / HZ;
-
-		if (t<2) np->latetime=0; else np->latetime++;
+#if 0
+		if (thistime < np->heartbeat + HZ + HZ)
+			np->latetime = 0;
+		else
+			np->latetime++;
+#endif
 
 		/*----------------------------------------------------
 		**
@@ -6607,7 +6795,7 @@
 				** still in start queue ?
 				*/
 				if (cp->phys.header.launch.l_paddr ==
-					NCB_SCRIPT_PHYS (np, skip))
+					cpu_to_scr(NCB_SCRIPT_PHYS (np, skip)))
 					continue;
 
 				/* fall through */
@@ -6691,14 +6879,20 @@
 		script_base	= (u_char *) np->script;
 		script_name	= "script";
 	}
-	else {
+	else if (np->p_scripth < dsp && 
+		 dsp <= np->p_scripth + sizeof(struct scripth)) {
 		script_ofs	= dsp - np->p_scripth;
 		script_size	= sizeof(struct scripth);
 		script_base	= (u_char *) np->scripth;
 		script_name	= "scripth";
+	} else {
+		script_ofs	= dsp;
+		script_size	= 0;
+		script_base	= 0;
+		script_name	= "mem";
 	}
 
-	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ %s (%x:%08x).\n",
+	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
 		ncr_name (np), (unsigned)INB (nc_ctest0)&0x0f, dstat, sist,
 		(unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl),
 		(unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs,
@@ -6756,15 +6950,18 @@
 
 	/*
 	**	interrupt on the fly ?
-	*/
-	while ((istat = INB (nc_istat)) & INTF) {
+	**	Since the global header may be copied back to a CCB 
+	**	using a posted PCI memory write, the last operation on 
+	**	the istat register is a READ in order to flush posted 
+	**	PCI commands (Btw, the 'do' loop is probably useless).
+	*/
+	istat = INB (nc_istat);
+	if (istat & INTF) {
+		do {
+			OUTB (nc_istat, (istat & SIGP) | INTF);
+			istat = INB (nc_istat);
+		} while (istat & INTF);
 		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	if (np->stalling)
-		OUTB (nc_istat, INTF);
-	else
-#endif
-		OUTB (nc_istat, (istat & SIGP) | INTF);
 		np->profile.num_fly++;
 		ncr_wakeup (np, 0);
 	};
@@ -6819,9 +7016,16 @@
 			ncr_int_sir (np);
 			return;
 		}
-		if (!(sist & (SBMC|PAR)) && !(dstat & SSI))
-			printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n",
-				ncr_name(np), sist, dstat);
+		/*
+		**  DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 2.
+		*/
+		if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) {
+			printf(	"%s: unknown interrupt(s) ignored, "
+				"ISTAT=%x DSTAT=%x SIST=%x\n",
+				ncr_name(np), istat, dstat, sist);
+			return;
+		}
+
 		OUTONB (nc_dcntl, (STD|NOCOM));
 		return;
 	};
@@ -6842,12 +7046,17 @@
 	*/
 
 	if (sist & RST) {
-		ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
+		ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET);
 		return;
 	};
 
 	if ((sist & STO) &&
 		!(dstat & (MDPE|BF|ABRT))) {
+	/*
+	**	DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 1.
+	*/
+		OUTONB (nc_ctest3, CLF);
+
 		ncr_int_sto (np);
 		return;
 	};
@@ -6880,13 +7089,13 @@
 
 	if ((sist & (SGE)) ||
 		(dstat & (MDPE|BF|ABORT|IID))) {
-		ncr_start_reset(np, 2);
+		ncr_start_reset(np, driver_setup.settle_delay);
 		return;
 	};
 
 	if (sist & HTH) {
 		printf ("%s: handshake timeout\n", ncr_name(np));
-		ncr_start_reset(np, 2);
+		ncr_start_reset(np, driver_setup.settle_delay);
 		return;
 	};
 
@@ -6896,7 +7105,7 @@
 			OUTB (nc_scr1, HS_UNEXPECTED);
 			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
 		};
-		ncr_start_reset(np, 2);
+		ncr_start_reset(np, driver_setup.settle_delay);
 		return;
 	};
 
@@ -6954,11 +7163,11 @@
 /*	assert ((diff <= MAX_START * 20) && !(diff % 20));*/
 
 	if ((diff <= MAX_START * 20) && !(diff % 20)) {
-		np->script->startpos[0] = scratcha;
+		np->script->startpos[0] = cpu_to_scr(scratcha);
 		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
 		return;
 	};
-	ncr_init (np, "selection timeout", HS_FAIL);
+	ncr_init (np, 1, "selection timeout", HS_FAIL);
 	np->disc = 1;
 }
 
@@ -6983,11 +7192,17 @@
 {
 	u_char scsi_mode = INB (nc_stest4) & SMODE;
 
-	printf("%s: SCSI bus mode change from %x to %x, resetting ...\n",
+	printf("%s: SCSI bus mode change from %x to %x.\n",
 		ncr_name(np), np->scsi_mode, scsi_mode);
 
 	np->scsi_mode = scsi_mode;
-	ncr_start_reset(np, 2);
+
+	/*
+	**	Suspend command processing for 1 second and 
+	**	reinitialize all except the chip.
+	*/
+	np->settle_time	= jiffies + HZ;
+	ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
 
 	return 1;
 }
@@ -7146,20 +7361,20 @@
 	**	get old startaddress and old length.
 	*/
 
-	oadr = vdsp[1];
+	oadr = scr_to_cpu(vdsp[1]);
 
 	if (cmd & 0x10) {	/* Table indirect */
 		tblp = (u_int32 *) ((char*) &cp->phys + oadr);
-		olen = tblp[0];
-		oadr = tblp[1];
+		olen = scr_to_cpu(tblp[0]);
+		oadr = scr_to_cpu(tblp[1]);
 	} else {
 		tblp = (u_int32 *) 0;
-		olen = vdsp[0] & 0xffffff;
+		olen = scr_to_cpu(vdsp[0]) & 0xffffff;
 	};
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
-			(unsigned) (vdsp[0] >> 24),
+			(unsigned) (scr_to_cpu(vdsp[0]) >> 24),
 			tblp,
 			(unsigned) olen,
 			(unsigned) oadr);
@@ -7169,10 +7384,10 @@
 	**	check cmd against assumed interrupted script command.
 	*/
 
-	if (cmd != (vdsp[0] >> 24)) {
+	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
 		PRINT_ADDR(cp->cmd);
 		printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
-			(unsigned)cmd, (unsigned)vdsp[0] >> 24);
+			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
 		
 		return;
 	}
@@ -7204,25 +7419,25 @@
 	*/
 
 	newcmd = cp->patch;
-	if (cp->phys.header.savep == vtophys (newcmd)) newcmd+=4;
+	if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;
 
 	/*
 	**	fillin the commands
 	*/
 
-	newcmd[0] = ((cmd & 0x0f) << 24) | rest;
-	newcmd[1] = oadr + olen - rest;
-	newcmd[2] = SCR_JUMP;
-	newcmd[3] = nxtdsp;
+	newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest);
+	newcmd[1] = cpu_to_scr(oadr + olen - rest);
+	newcmd[2] = cpu_to_scr(SCR_JUMP);
+	newcmd[3] = cpu_to_scr(nxtdsp);
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		PRINT_ADDR(cp->cmd);
 		printf ("newcmd[%d] %x %x %x %x.\n",
 			(int) (newcmd - cp->patch),
-			(unsigned)newcmd[0],
-			(unsigned)newcmd[1],
-			(unsigned)newcmd[2],
-			(unsigned)newcmd[3]);
+			(unsigned)scr_to_cpu(newcmd[0]),
+			(unsigned)scr_to_cpu(newcmd[1]),
+			(unsigned)scr_to_cpu(newcmd[2]),
+			(unsigned)scr_to_cpu(newcmd[3]));
 	}
 	/*
 	**	fake the return address (to the patch).
@@ -7309,20 +7524,23 @@
 */
 		if (num == SIR_DATA_IO_IS_OUT) {
 			endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
-			cp->phys.header.goalp = endp + 8;
-			cp->phys.header.savep = endp - cp->segments*16;
+			cp->phys.header.goalp = cpu_to_scr(endp + 8);
+			cp->phys.header.savep =
+				cpu_to_scr(endp - cp->segments*16);
 		} else {
 			endp = NCB_SCRIPT_PHYS (np, data_in)  + MAX_SCATTER*16;
-			cp->phys.header.goalp = endp + 8;
-			cp->phys.header.savep = endp - cp->segments*16;
+			cp->phys.header.goalp = cpu_to_scr(endp + 8);
+			cp->phys.header.savep =
+				cpu_to_scr(endp - cp->segments*16);
 		}
 
 		cp->phys.header.lastp	= cp->phys.header.savep;
 		np->header.savep	= cp->phys.header.savep;
 		np->header.goalp	= cp->phys.header.goalp;
 		np->header.lastp	= cp->phys.header.lastp;
-		OUTL (nc_temp,	np->header.savep);
-		OUTL (nc_dsp,	np->header.savep);
+
+		OUTL (nc_temp,	scr_to_cpu(np->header.savep));
+		OUTL (nc_dsp,	scr_to_cpu(np->header.savep));
 		return;
 		/* break; */
 
@@ -7369,7 +7587,7 @@
 		**	no job, resume normal processing
 		*/
 		if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n");
-		np->script->start0[0] =  SCR_INT ^ IFFALSE (0);
+		np->script->start0[0] =  cpu_to_scr(SCR_INT ^ IFFALSE (0));
 		break;
 
 	case SIR_SENSE_FAILED:
@@ -7395,7 +7613,7 @@
 		/*
 		**	And patch code to restart it.
 		*/
-		np->script->start0[0] =  SCR_INT;
+		np->script->start0[0] =  cpu_to_scr(SCR_INT);
 		break;
 
 /*-----------------------------------------------------------------------------
@@ -7752,7 +7970,7 @@
 
 		PRINT_ADDR(cp->cmd);
 		printf ("M_REJECT received (%x:%x).\n",
-			(unsigned)np->lastmsg, np->msgout[0]);
+			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
 		break;
 
 	case SIR_REJECT_SENT:
@@ -7802,8 +8020,8 @@
 		printf ("M_DISCONNECT received, but datapointer not saved: "
 			"data=%x save=%x goal=%x.\n",
 			(unsigned) INL (nc_temp),
-			(unsigned) np->header.savep,
-			(unsigned) np->header.goalp);
+			(unsigned) scr_to_cpu(np->header.savep),
+			(unsigned) scr_to_cpu(np->header.goalp));
 		break;
 
 #if 0   /* This stuff does not work */
@@ -7834,7 +8052,7 @@
 		PRINT_ADDR(cp->cmd);
 		printf ("queue full.\n");
 
-		np->script->start1[0] =  SCR_INT;
+		np->script->start1[0] =  cpu_to_scr(SCR_INT);
 
 		/*
 		**	Try to disable tagged transfers.
@@ -7882,7 +8100,7 @@
 		*/
 
 		printf ("%s: queue empty.\n", ncr_name (np));
-		np->script->start1[0] =  SCR_INT ^ IFFALSE (0);
+		np->script->start1[0] =  cpu_to_scr(SCR_INT ^ IFFALSE (0));
 		break;
 #endif   /* This stuff does not work */
 	};
@@ -8021,33 +8239,37 @@
 	tp=&np->target[target];
 
 	if (!tp->jump_tcb.l_cmd) {
-
 		/*
 		**	initialize it.
 		*/
-		tp->jump_tcb.l_cmd   = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
+		tp->jump_tcb.l_cmd   =
+			cpu_to_scr((SCR_JUMP^IFFALSE (DATA (0x80 + target))));
 		tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
 
-		tp->getscr[0] =
-			(np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
-		tp->getscr[1] = vtophys (&tp->sval);
-		tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
-		tp->getscr[3] =
-			(np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
-		tp->getscr[4] = vtophys (&tp->wval);
-		tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
+		tp->getscr[0] =	(np->features & FE_PFEN) ?
+			cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
+		tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
+		tp->getscr[2] =
+		cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_sxfer));
+
+		tp->getscr[3] =	(np->features & FE_PFEN) ?
+			cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
+		tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
+		tp->getscr[5] =
+		cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_scntl3));
 
 		assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
 			offsetof(struct tcb    , sval    )) &3) == 0);
 		assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
 			offsetof(struct tcb    , wval    )) &3) == 0);
 
-		tp->call_lun.l_cmd   = (SCR_CALL);
-		tp->call_lun.l_paddr = NCB_SCRIPT_PHYS (np, resel_lun);
-
-		tp->jump_lcb.l_cmd   = (SCR_JUMP);
-		tp->jump_lcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
-		np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb);
+		tp->call_lun.l_cmd   = cpu_to_scr(SCR_CALL);
+		tp->call_lun.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun));
+
+		tp->jump_lcb.l_cmd   = cpu_to_scr(SCR_JUMP);
+		tp->jump_lcb.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+		np->jump_tcb.l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
 	}
 
 	/*
@@ -8070,14 +8292,17 @@
 		**	Initialize it
 		*/
 		bzero (lp, sizeof (*lp));
-		lp->jump_lcb.l_cmd   = (SCR_JUMP ^ IFFALSE (DATA (lun)));
+		lp->jump_lcb.l_cmd   =
+			cpu_to_scr(SCR_JUMP ^ IFFALSE (DATA (lun)));
 		lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr;
 
-		lp->call_tag.l_cmd   = (SCR_CALL);
-		lp->call_tag.l_paddr = NCB_SCRIPT_PHYS (np, resel_tag);
-
-		lp->jump_ccb.l_cmd   = (SCR_JUMP);
-		lp->jump_ccb.l_paddr = NCB_SCRIPTH_PHYS (np, aborttag);
+		lp->call_tag.l_cmd   = cpu_to_scr(SCR_CALL);
+		lp->call_tag.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tag));
+
+		lp->jump_ccb.l_cmd   = cpu_to_scr(SCR_JUMP);
+		lp->jump_ccb.l_paddr =
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, aborttag));
 
 		lp->actlink = 1;
 
@@ -8086,7 +8311,7 @@
 		/*
 		**   Chain into LUN list
 		*/
-		tp->jump_lcb.l_paddr = vtophys (&lp->jump_lcb);
+		tp->jump_lcb.l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
 		tp->lp[lun] = lp;
 
 		ncr_setmaxtags (np, tp, driver_setup.default_tags);
@@ -8138,11 +8363,11 @@
 	/*
 	**	Chain into reselect list
 	*/
-	cp->jump_ccb.l_cmd   = SCR_JUMP;
+	cp->jump_ccb.l_cmd   = cpu_to_scr(SCR_JUMP);
 	cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr;
-	lp->jump_ccb.l_paddr = CCB_PHYS (cp, jump_ccb);
-	cp->call_tmp.l_cmd   = SCR_CALL;
-	cp->call_tmp.l_paddr = NCB_SCRIPT_PHYS (np, resel_tmp);
+	lp->jump_ccb.l_paddr = cpu_to_scr(CCB_PHYS (cp, jump_ccb));
+	cp->call_tmp.l_cmd   = cpu_to_scr(SCR_CALL);
+	cp->call_tmp.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tmp));
 
 	/*
 	**	Chain into wakeup list
@@ -8255,9 +8480,9 @@
 	if (!use_sg) {
 		if (cmd->request_bufflen) {
 			data = &data[MAX_SCATTER - 1];
-			data[0].addr	= vtophys(cmd->request_buffer);
-			data[0].size	= cmd->request_bufflen;
-			cp->data_len	= data[0].size;
+			data[0].addr = cpu_to_scr(vtophys(cmd->request_buffer));
+			data[0].size = cpu_to_scr(cmd->request_bufflen);
+			cp->data_len = cmd->request_bufflen;
 			segment = 1;
 		}
 	}
@@ -8266,9 +8491,11 @@
 
 		data = &data[MAX_SCATTER - use_sg];
 		while (segment < use_sg) {
-			data[segment].addr = vtophys(scatter[segment].address);
-			data[segment].size = scatter[segment].length;
-			cp->data_len	   += data[segment].size;
+			data[segment].addr =
+				cpu_to_scr(vtophys(scatter[segment].address));
+			data[segment].size =
+				cpu_to_scr(scatter[segment].length);
+			cp->data_len	   += scatter[segment].length;
 			++segment;
 		}
 	}
@@ -8338,7 +8565,7 @@
 	/*
 	**	Set memory and register.
 	*/
-	np->ncr_cache = host_wr;
+	np->ncr_cache = cpu_to_scr(host_wr);
 	OUTL (nc_temp, ncr_wr);
 	/*
 	**	Start script (exchange values)
@@ -8357,7 +8584,7 @@
 	/*
 	**	Read memory and register.
 	*/
-	host_rd = np->ncr_cache;
+	host_rd = scr_to_cpu(np->ncr_cache);
 	ncr_rd  = INL (nc_scratcha);
 	ncr_bk  = INL (nc_temp);
 	/*
@@ -8575,7 +8802,7 @@
 	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
 	OUTB(nc_scntl3,	scntl3);
 	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
-	OUTB(nc_stest3, 0x00);		/* Restart scsi clock 		*/
+	OUTB(nc_stest3, 0x00|TE);		/* Restart scsi clock 		*/
 }
 
 
@@ -8793,6 +9020,8 @@
 			driver_setup.irqm	= val;
 		else if	(!strncmp(cur, "pcifix:", 7))
 			driver_setup.pci_fix_up	= val;
+		else if	(!strncmp(cur, "buschk:", 7))
+			driver_setup.bus_check	= val;
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 		else if	(!strncmp(cur, "nvram:", 6))
 			driver_setup.use_nvram	= val;
@@ -8803,7 +9032,11 @@
 		else
 			printf("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 
+#ifdef MODULE
+		if ((cur = strchr(cur, ' ')) != NULL)
+#else
 		if ((cur = strchr(cur, ',')) != NULL)
+#endif
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
@@ -8832,9 +9065,9 @@
 )
 {
 #define YesNo(y)	y ? 'y' : 'n'
-	printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+	printk("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
 			YesNo(driver_setup.disconnection),
-			YesNo(driver_setup.special_features),
+			driver_setup.special_features,
 			YesNo(driver_setup.ultra_scsi),
 			driver_setup.default_tags,
 			driver_setup.default_sync,
@@ -8933,10 +9166,10 @@
 			    h->device_id == devp->chip.device_id)
 				break;
 		}
-		if (j < count && !devp->attached &&
-		    !ncr_attach (tpnt, attach_count, devp)) {
-			attach_count++;
-			devp->attached = 1;
+		if (j < count && !devp->attach_done) {
+			if (!ncr_attach (tpnt, attach_count, devp))
+				attach_count++;
+			devp->attach_done = 1;
 		}
 	}
 
@@ -8979,6 +9212,11 @@
 # endif
 #endif
 
+#if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
+if (ncr53c8xx)
+	ncr53c8xx_setup(ncr53c8xx, (int *) 0);
+#endif
+
 	/* 
 	** Detect all 53c8xx hosts and then attach them.
 	**
@@ -9040,8 +9278,6 @@
 #endif
 			printf(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
 				device[count].chip.name, msg);
-
-			device[count].attached = 0;
 			++count;
 		}
 	}
@@ -9054,9 +9290,9 @@
 	** so try to attach them here.
 	*/
 	for (i= 0; i < count; i++) {
-		if ((!device[i].attached) && (!ncr_attach (tpnt, attach_count, &device[i]))) {
+		if (!device[i].attach_done && 
+		    !ncr_attach (tpnt, attach_count, &device[i])) {
  			attach_count++;
-			device[i].attached = 1;
 		}
 	}
 
@@ -9078,11 +9314,11 @@
 	uchar cache_line_size, latency_timer;
 	uchar irq, revision;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-	uint base, io_port; 
+	uint base, base_2, io_port; 
 #else
-	ulong base, io_port; 
+	ulong base, base_2; 
 #endif
-	int i, error;
+	int i;
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	ncr_nvram *nvram = device->nvram;
@@ -9092,20 +9328,32 @@
 	printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
 		bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
 	/*
-	 * Read info from the PCI config space
+	 * Read info from the PCI config space.
+	 * pcibios_read_config_xxx() functions are assumed to be used for 
+	 * successfully detected PCI devices.
+	 * Expecting error conditions from them is just paranoia,
+	 * thus void cast.
 	 */
-	if (
-		(error=pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id))	||
-		(error=pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id))	||
-		(error=pcibios_read_config_word( bus, device_fn, PCI_COMMAND, &command))	||
-		(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,&io_port))	|| 
-		(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))	||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION,&revision))	||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq))	||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, &cache_line_size)) ||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, &latency_timer))
-	)
-		goto err_pcibios;
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_VENDOR_ID, &vendor_id);
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_DEVICE_ID, &device_id);
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_COMMAND, &command);
+	(void) pcibios_read_config_dword(bus, device_fn,
+					PCI_BASE_ADDRESS_0, &io_port);	
+	(void) pcibios_read_config_dword(bus, device_fn,
+					PCI_BASE_ADDRESS_1, &base);
+	(void) pcibios_read_config_dword(bus, device_fn,
+					PCI_BASE_ADDRESS_2, &base_2);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CLASS_REVISION,&revision);	
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_INTERRUPT_LINE, &irq);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CACHE_LINE_SIZE, &cache_line_size);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_LATENCY_TIMER, &latency_timer);
 
 	/*
 	 *	Check if the chip is supported
@@ -9126,6 +9374,28 @@
 		return -1;
 	}
 
+#ifdef __powerpc__
+	/*
+	 *	Severall fix-up for power/pc.
+	 *	Should not be performed by the driver.
+	 */
+	if ((command &
+		(PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) !=
+		(PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) {
+		printk("ncr53c8xx : setting PCI master/io/command bit\n");
+		command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY;
+		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+	}
+	if (io_port >= 0x10000000) {
+		io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+		pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+	}
+	if (base >= 0x10000000) {
+		base = (base & 0x00FFFFFF) | 0x01000000;
+		pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, base);
+	}
+#endif
+
 	/*
 	 * Check availability of IO space, memory space and master capability.
 	 */
@@ -9158,6 +9428,8 @@
 		return -1;
 	}
 
+	base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
+
 	if (io_port && check_region (io_port, 128)) {
 		printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
 			(int) io_port, (int) (io_port + 127));
@@ -9172,8 +9444,12 @@
 	/*
 	 * Fix some features according to driver setup.
 	 */
-	if (!driver_setup.special_features)
+	if (!(driver_setup.special_features & 1))
 		chip->features &= ~FE_SPECIAL_SET;
+	else {
+		if (driver_setup.special_features & 2)
+			chip->features &= ~FE_WRIE;
+	}
 	if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
 		chip->features |=  FE_ULTRA;
 		chip->features &= ~FE_ULTRA2;
@@ -9192,15 +9468,18 @@
 #if defined(__i386) && !defined(MODULE)
 	if ((driver_setup.pci_fix_up & 1) &&
 	    (chip->features & FE_CLSE) && cache_line_size == 0) {
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
 		extern char x86;
 		switch(x86) {
+#else
+		switch(boot_cpu_data.x86) {
+#endif
 		case 4:	cache_line_size = 4; break;
 		case 5:	cache_line_size = 8; break;
 		}
 		if (cache_line_size)
-			error = pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size);
-		if (error)
-			goto err_pcibios;
+			(void) pcibios_write_config_byte(bus, device_fn,
+					PCI_CACHE_LINE_SIZE, cache_line_size);
 		if (initverbose)
 			printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fix-up).\n", cache_line_size);
 	}
@@ -9208,9 +9487,8 @@
 	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
 	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
 		command |= PCI_COMMAND_INVALIDATE;
-		error=pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
-		if (error)
-			goto err_pcibios;
+		(void) pcibios_write_config_word(bus, device_fn,
+						PCI_COMMAND, command);
 		if (initverbose)
 			printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fix-up).\n");
 	}
@@ -9252,10 +9530,8 @@
 			latency_timer = lt;
 			if (initverbose)
 				printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fix-up).\n", latency_timer);
-			error = pcibios_write_config_byte(bus, device_fn,
+			 (void) pcibios_write_config_byte(bus, device_fn,
 					PCI_LATENCY_TIMER, latency_timer);
-			if (error)
-				goto err_pcibios;
 		}
 	}
 
@@ -9281,9 +9557,10 @@
 	device->slot.bus	= bus;
 	device->slot.device_fn	= device_fn;
 	device->slot.base	= base;
+	device->slot.base_2	= base_2;
 	device->slot.io_port	= io_port;
 	device->slot.irq	= irq;
-	device->attached	= 0;
+	device->attach_done	= 0;
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	if (!nvram)
 		goto out;
@@ -9331,11 +9608,6 @@
 
 #endif	/* SCSI_NCR_NVRAM_SUPPORT */
 	return 0;     
-
-err_pcibios:
-	printk("ncr53c8xx: error %s reading configuration space\n",
-		pcibios_strerror(error));
-	return -1;
 }
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
@@ -9394,47 +9666,41 @@
 }
 
 /*
-**   Linux entry point of the interrupt handler
+**   Linux entry point of the interrupt handler.
+**   Fort linux versions > 1.3.70, we trust the kernel for 
+**   passing the internal host descriptor as 'dev_id'.
+**   Otherwise, we scan the host list and call the interrupt 
+**   routine for each host that uses this IRQ.
 */
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+{
+#ifdef DEBUG_NCR53C8XX
+     printk("ncr53c8xx : interrupt received\n");
+#endif
+
+     if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+     ncr_exception((ncb_p) dev_id);
+     if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+}
+
 #else
 static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
-#endif
 {
      struct Scsi_Host *host;
      struct host_data *host_data;
-#if 0
-     u_long flags;
-
-     save_flags(flags); cli();
-#endif
-
-#ifdef DEBUG_NCR53C8XX
-printk("ncr53c8xx : interrupt received\n");
-#endif
 
      for (host = first_host; host; host = host->next) {
 	  if (host->hostt == the_template && host->irq == irq) {
 	       host_data = (struct host_data *) host->hostdata;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
-#   ifdef SCSI_NCR_SHARE_IRQ
-               if (dev_id == host_data->ncb) {
-#else
-               if (1) {
-#   endif
-#endif
-                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-	            ncr_exception(host_data->ncb);
-                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-               }
+               if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+               ncr_exception(host_data->ncb);
+               if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
 	  }
      }
-#if 0
-     restore_flags(flags);
-#endif
 }
+#endif
 
 /*
 **   Linux entry point of the timer handler
@@ -9540,17 +9806,10 @@
 #ifdef MODULE
 int ncr53c8xx_release(struct Scsi_Host *host)
 {
-     struct host_data *host_data;
 #ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : release\n");
 #endif
-
-     for (host = first_host; host; host = host->next) {
-	  if (host->hostt == the_template) {
-	       host_data = (struct host_data *) host->hostdata;
-	       ncr_detach(host_data->ncb, host->irq);
-	  }
-     }
+     ncr_detach(((struct host_data *) host->hostdata)->ncb);
 
      return 1;
 }
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.0.33/linux/drivers/scsi/ncr53c8xx.h	Wed Oct 15 15:24:02 1997
+++ linux/drivers/scsi/ncr53c8xx.h	Wed Jun  3 15:17:49 1998
@@ -45,7 +45,7 @@
 /*
 **	Name and revision of the driver
 */
-#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 2.4a"
+#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 2.5f.1"
 
 /*
 **	Check supported Linux versions
@@ -125,7 +125,7 @@
  * For Ultra2 SCSI support option, use special features and allow 40Mhz 
  * synchronous data transfers.
  */
-#define	SCSI_NCR_SETUP_SPECIAL_FEATURES		(1)
+#define	SCSI_NCR_SETUP_SPECIAL_FEATURES		(3)
 #define SCSI_NCR_SETUP_ULTRA_SCSI		(2)
 #define SCSI_NCR_MAX_SYNC			(40)
 
@@ -155,9 +155,11 @@
 #endif
 
 /*
- * Use normal IO if configured. Forced for alpha.
+ * Use normal IO if configured. Forced for alpha and ppc.
  */
-#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) || defined(__alpha__)
+#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
+#define	SCSI_NCR_IOMAPPED
+#elif defined(__alpha__) || defined(__powerpc__)
 #define	SCSI_NCR_IOMAPPED
 #endif
 
@@ -288,27 +290,44 @@
 #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} 
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75)
 
+#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} 
+  
+#elif	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+
+#define NCR53C8XX {	NULL, NULL, NULL, NULL,				\
+			SCSI_NCR_DRIVER_NAME,	ncr53c8xx_detect,	\
+    			ncr53c8xx_release,	NULL,	NULL,		\
+			ncr53c8xx_queue_command,ncr53c8xx_abort,	\
+			ncr53c8xx_reset, NULL,	scsicam_bios_param,	\
+			SCSI_NCR_CAN_QUEUE,	7,			\
+			SCSI_NCR_SG_TABLESIZE,	SCSI_NCR_CMD_PER_LUN,	\
+			0,	0,	DISABLE_CLUSTERING} 
 
 #else
 
+#define NCR53C8XX {	NULL, NULL,					\
+			SCSI_NCR_DRIVER_NAME,	ncr53c8xx_detect,	\
+			ncr53c8xx_release,	NULL, 	NULL, 		\
+			ncr53c8xx_queue_command,ncr53c8xx_abort,	\
+			ncr53c8xx_reset, NULL,	scsicam_bios_param,	\
+			SCSI_NCR_CAN_QUEUE,	7,			\
+			SCSI_NCR_SG_TABLESIZE,	SCSI_NCR_CMD_PER_LUN,	\
+			0,	0,	DISABLE_CLUSTERING} 
 
-#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) */
+#endif /* LINUX_VERSION_CODE */
 
 #endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
@@ -316,6 +335,45 @@
 #ifndef HOSTS_C
 
 /*
+**	IO functions definition for big/little endian support.
+**	For now, the NCR is only supported in little endian addressing mode, 
+**	and big endian byte ordering is only supported for the PPC.
+**	MMIO is not used on PPC.
+*/
+
+#ifdef	__BIG_ENDIAN
+
+#if	LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+#error	"BIG ENDIAN byte ordering needs kernel version >= 2.1.0"
+#endif
+
+#ifdef	__powerpc__
+#define	inw_l2b		inw
+#define	inl_l2b		inl
+#define	outw_b2l	outw
+#define	outl_b2l	outl
+#else
+#error	"Support for BIG ENDIAN is only available for the PowerPC"
+#endif
+
+#else	/* Assumed x86 or alpha */
+
+#define	inw_raw		inw
+#define	inl_raw		inl
+#define	outw_raw	outw
+#define	outl_raw	outl
+#define	readw_raw	readw
+#define	readl_raw	readl
+#define	writew_raw	writew
+#define	writel_raw	writel
+
+#endif
+
+#ifdef	SCSI_NCR_BIG_ENDIAN
+#error	"The NCR in BIG ENDIAN adressing mode is not (yet) supported"
+#endif
+
+/*
 **	NCR53C8XX Device Ids
 */
 
@@ -395,6 +453,19 @@
 #define FE_SPECIAL_SET	(FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
 } ncr_chip;
 
+/*
+**	DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 3.
+**	Memory Read transaction terminated by a retry followed by 
+**	Memory Read Line command.
+*/
+#define FE_CACHE0_SET	(FE_CACHE_SET & ~FE_ERL)
+
+/*
+**	DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 5.
+**	On paper, this errata is harmless. But it is a good reason for 
+**	using a shorter programmed burst length (64 DWORDS instead of 128).
+*/
+
 #define SCSI_NCR_CHIP_TABLE						\
 {									\
  {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810",  4,  8, 4,			\
@@ -412,23 +483,23 @@
  {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825",  4,  8, 4,			\
  FE_WIDE|FE_ERL|FE_BOF}							\
  ,									\
- {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 7,  8, 4,			\
- FE_WIDE|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}		\
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6,  8, 4,			\
+ FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}		\
  ,									\
  {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,			\
  FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}		\
  ,									\
- {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  7, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  6, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
  ,									\
- {PCI_DEVICE_ID_NCR_53C875, 0xff, "875",  7, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875",  6, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
  ,									\
- {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J",  7, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
  ,									\
- {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  7, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  6, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
  ,									\
  {PCI_DEVICE_ID_NCR_53C895, 0xff, "895",  7, 31, 7,			\
  FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
@@ -478,7 +549,8 @@
 	1,					\
 	SCSI_NCR_SETUP_SETTLE_TIME,		\
 	SCSI_NCR_SETUP_DIFF_SUPPORT,		\
-	0					\
+	0,					\
+	1					\
 }
 
 /*
@@ -505,6 +577,7 @@
 	0,					\
 	0,					\
 	10,					\
+	1,					\
 	1,					\
 	1					\
 }
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.0.33/linux/drivers/scsi/ppa.c	Thu Nov 14 05:20:10 1996
+++ linux/drivers/scsi/ppa.c	Wed Jun  3 15:17:49 1998
@@ -1,504 +1,1550 @@
-/*      ppa.c   --  low level driver for the IOMEGA PPA3 
-                    parallel port SCSI host adapter.
-
-        (The PPA3 is the embedded controller in the ZIP drive.)
-
-        (c) 1995,1996 Grant R. Guenther, grant@torque.net,
-                      under the terms of the GNU Public License.
-
-*/
-
-/*      This driver was developed without the benefit of any technical
-        specifications for the interface.  Instead, a modified version of
-        DOSemu was used to monitor the protocol used by the DOS driver
-        for this adapter.  I have no idea how my programming model relates
-        to IOMEGA's design.
-
-        IOMEGA's driver does not generate linked commands.  I've never
-        observed a SCSI message byte in the protocol transactions, so
-        I am assuming that as long as linked commands are not used
-        we won't see any.  
-
-        So far, this driver has been tested with the embedded PPA3 in the
-        ZIP drive, only.   It can detect and adapt to 4- and 8-bit parallel
-        ports, but there is currently no support for EPP or ECP ports, as
-        I have been unable to make the DOS drivers work in these modes on
-        my test rig.
-
-        For more information, see the file drivers/scsi/README.ppa.
-
-*/
-
-#define   PPA_VERSION   "0.26"
-
-/* Change these variables here or with insmod or with a LILO or LOADLIN
-   command line argument
-*/
-
-static int      ppa_base       = 0x378;  /* parallel port address    */
-static int      ppa_speed_high = 1;      /* port delay in data phase */
-static int      ppa_speed_low  = 6;      /* port delay otherwise     */
-static int      ppa_nybble     = 0;      /* don't force nybble mode  */
-
-
-#define   PPA_CAN_QUEUE         1       /* use "queueing" interface */
-#define   PPA_SELECT_TMO        5000    /* how long to wait for target ? */
-#define   PPA_SPIN_TMO          5000000 /* ppa_wait loop limiter */
-#define   PPA_SECTOR_SIZE       512     /* for a performance hack only */
-
-#include  <linux/stddef.h>
-#include  <linux/module.h>
-#include  <linux/kernel.h>
-#include  <linux/tqueue.h>
-#include  <linux/ioport.h>
-#include  <linux/delay.h>
-#include  <linux/blk.h>
-#include  <linux/proc_fs.h>
-#include  <linux/stat.h>
-#include  <asm/io.h>
-#include  "sd.h"
-#include  "hosts.h"
-#include  "ppa.h"
-
-struct proc_dir_entry proc_scsi_ppa = 
-                { PROC_SCSI_PPA, 3, "ppa", S_IFDIR|S_IRUGO|S_IXUGO, 2 };
-
-static int              ppa_abort_flag = 0;
-static int              ppa_error_code = DID_OK;
-static char             ppa_info_string[132];
-static Scsi_Cmnd        *ppa_current = 0;
-static void             (*ppa_done) (Scsi_Cmnd *);
-static int              ppa_port_delay;
-
-void    out_p( short port, char byte)
-
-{       outb(byte,ppa_base+port);
-        udelay(ppa_port_delay);
-}
-
-char    in_p( short port)
-
-{       return inb(ppa_base+port);
-        udelay(ppa_port_delay);
-}
-
-void    ppa_d_pulse( char b )
-
-{       out_p(0,b);
-        out_p(2,0xc); out_p(2,0xe); out_p(2,0xc); out_p(2,0x4); out_p(2,0xc);
-}
-
-void    ppa_disconnect( void )
-
-{       ppa_d_pulse(0);
-        ppa_d_pulse(0x3c);
-        ppa_d_pulse(0x20);
-        ppa_d_pulse(0xf);
-}
-
-void    ppa_c_pulse( char b )
-
-{       out_p(0,b);
-        out_p(2,0x4); out_p(2,0x6); out_p(2,0x4); out_p(2,0xc);
-}
-
-void    ppa_connect( void )
-
-{       ppa_c_pulse(0);
-        ppa_c_pulse(0x3c);
-        ppa_c_pulse(0x20);
-        ppa_c_pulse(0x8f);
-}
-
-void    ppa_do_reset( void )
-
-{       out_p(2,0);             /* This is really just a guess */
-        udelay(100);
-}
-
-char    ppa_select( int  initiator, int target )
-
-{       char    r;
-        int     k;
-
-        r = in_p(1);
-        out_p(0,(1<<target)); out_p(2,0xe); out_p(2,0xc);
-        out_p(0,(1<<initiator)); out_p(2,0x8);
-
-        k = 0;
-        while ( !(r = (in_p(1) & 0xf0)) && (k++ < PPA_SELECT_TMO)) barrier();
-        return r;
-}
-
-char    ppa_wait( void ) 
-
-/*      Wait for the high bit to be set.
-
-        In principle, this could be tied to an interrupt, but the adapter
-        doesn't appear to be designed to support interrupts.  We spin on
-        the 0x80 ready bit. 
-*/
-
-{       int     k;
-        char    r;
-
-        ppa_error_code = DID_OK;
-        k = 0;
-        while (!((r = in_p(1)) & 0x80) 
-                && (k++ < PPA_SPIN_TMO) && !ppa_abort_flag  ) barrier();
-                        
-        if (ppa_abort_flag) {
-                if (ppa_abort_flag == 1) ppa_error_code = DID_ABORT;
-                else {  ppa_do_reset();
-                        ppa_error_code = DID_RESET;
-                }
-                ppa_disconnect();
-                return 0;
-        }
-        if (k >= PPA_SPIN_TMO) { 
-                ppa_error_code = DID_TIME_OUT;
-                ppa_disconnect();
-                return 0;               /* command timed out */
-        }
-        return (r & 0xf0);
-}
-
-int     ppa_init( void )
-
-/* This is based on a trace of what the Iomega DOS 'guest' driver does.
-   I've tried several different kinds of parallel ports with guest and
-   coded this to react in the same ways that it does.
-
-   The return value from this function is just a hint about where the
-   handshaking failed.
-
-*/
-
-{       char    r, s;
-
-        out_p(0,0xaa); 
-        if (in_p(0) != (char) 0xaa) return 1; 
-        ppa_disconnect();
-        ppa_connect();
-        out_p(2,0x6); 
-        if ((in_p(1) & 0xf0) != 0xf0) return 2; 
-        out_p(2,0x4);
-        if ((in_p(1) & 0xf0) != 0x80) return 3; 
-        ppa_disconnect();
-        s = in_p(2);
-        out_p(2,0xec);
-        out_p(0,0x55); 
-        r = in_p(0);    
-        if (r != (char) 0xff) { 
-                ppa_nybble = 1;
-                if (r != (char) 0x55) return 4; 
-                out_p(0,0xaa); if (in_p(0) != (char) 0xaa) return 5; 
-        }
-        out_p(2,s);
-        ppa_connect();
-        out_p(0,0x40); out_p(2,0x8); out_p(2,0xc);
-        ppa_disconnect();
-
-        return 0;
-}
-
-int     ppa_start( Scsi_Cmnd * cmd )
-
-{       int     k;
-
-        ppa_error_code = DID_OK;
-        ppa_abort_flag = 0;
-
-        if (cmd->target == PPA_INITIATOR) {
-                ppa_error_code = DID_BAD_TARGET;
-                return 0;
-        }
-        ppa_connect();
-        if (!ppa_select(PPA_INITIATOR,cmd->target)) {
-                ppa_disconnect();
-                ppa_error_code = DID_NO_CONNECT;
-                return 0;
-        }
-        out_p(2,0xc);
-
-        for (k=0; k < cmd->cmd_len; k++) {        /* send the command */
-                if (!ppa_wait()) return 0;
-                out_p(0,cmd->cmnd[k]);
-                out_p(2,0xe);
-                out_p(2,0xc);
-        }
-
-#ifdef PPA_DEBUG
-        printk("PPA: command out: ");
-        for (k=0; k < cmd->cmd_len; k++)
-                printk("%3x",(cmd->cmnd[k]) & 0xff );
-        printk("\n");
-#endif
-
-        return 1;
-}
-
-int     ppa_completion( Scsi_Cmnd * cmd )
-
-/* The bulk flag enables some optimisations in the data transfer loops,
-   it should be true for any command that transfers data in integral
-   numbers of sectors.
-
-   The driver appears to remain stable if we speed up the parallel port
-   i/o in this function, but not elsewhere.
-*/
-
-{       char    r, l, h, v;
-        int     dir, cnt, blen, fast, bulk;
-        char    *buffer;
-
-#ifdef PPA_DEBUG
-        int     k;
-#endif
-
-        if (!(r = ppa_wait())) return 0;
-        v = cmd->cmnd[0];
-        bulk = ((v==READ_6)||(v==READ_10)||(v==WRITE_6)||(v==WRITE_10));
-        buffer = cmd->request_buffer;
-        blen = cmd->request_bufflen;
-        cnt = 0;  dir = 0;
-        if (r == (char) 0xc0) dir = 1;  /* d0 = read c0 = write f0 = status */
-
-        ppa_port_delay = ppa_speed_high;
-
-        while (r != (char) 0xf0) {
-                if (((r & 0xc0) != 0xc0 ) || (cnt >= blen)) {
-                        ppa_disconnect();
-                        ppa_error_code = DID_ERROR;
-                        return 0;
-                }
-                fast = bulk && ((blen - cnt) >= PPA_SECTOR_SIZE);
-                if (dir) do {
-                        out_p(0,buffer[cnt++]);
-                        out_p(2,0xe); out_p(2,0xc);
-                        if (!fast) break;
-                } while (cnt % PPA_SECTOR_SIZE);
-                else {  
-                        if (ppa_nybble) do {
-                                out_p(2,0x4); h = in_p(1); 
-                                out_p(2,0x6); l = in_p(1);
-                                v = ((l >> 4) & 0x0f) + (h & 0xf0);
-                                buffer[cnt++] = v;
-                                if (!fast) break;
-                        } while (cnt % PPA_SECTOR_SIZE);
-                        else do {
-                                out_p(2,0x25); v = in_p(0); out_p(2,0x27);
-                                buffer[cnt++] = v;
-                                if (!fast) break;
-                        } while (cnt % PPA_SECTOR_SIZE);
-                        if (!ppa_nybble) {
-                                out_p(2,0x5); out_p(2,0x4);
-                        }
-                        out_p(2,0xc);
-                }
-                if (!(r = ppa_wait())) return 0;
-        }
-
-        ppa_port_delay = ppa_speed_low;
-
-        out_p(2,0x4);            /* now read status byte */
-        h = in_p(1);
-        out_p(2,0x6);
-        l = in_p(1);
-        out_p(2,0xc);
-        r = ((l >> 4) & 0x0f) + (h & 0xf0);
-
-        out_p(2,0xe); out_p(2,0xc);
-        ppa_disconnect();
-
-#ifdef PPA_DEBUG
-        printk("PPA: status: %x, data[%d]: ",r & STATUS_MASK,cnt);
-        if (cnt > 12) cnt = 12;
-        for (k=0; k < cnt; k++)
-           printk("%3x",buffer[k] & 0xff );
-        printk("\n");   
+/* ppa.c   --  low level driver for the IOMEGA PPA3 
+ * parallel port SCSI host adapter.
+ * 
+ * (The PPA3 is the embedded controller in the ZIP drive.)
+ * 
+ * (c) 1995,1996 Grant R. Guenther, grant@torque.net,
+ * under the terms of the GNU Public License.
+ *
+ * Current Maintainer: David Campbell (Perth, Western Australia)
+ *                     campbell@gear.torque.net
+ *                     dcampbel@p01.as17.honeywell.com.au
+ *
+ * My unoffical company acronym list is 21 pages long:
+ *      FLA:    Four letter acronym with built in facility for
+ *              future expansion to five letters.
+ */
+
+#include <linux/config.h>
+
+/* The following #define is to avoid a clash with hosts.c */
+#define PPA_CODE 1
+#ifndef HAVE_PC87332
+#define HAVE_PC87332    0
 #endif
-
-        return (r & STATUS_MASK);
-}
-
-/* deprecated synchronous interface */
-
-int     ppa_command( Scsi_Cmnd * cmd )
-
-{       int     s;
-
-        sti();
-        s = 0;
-        if (ppa_start(cmd))
-           if (ppa_wait()) 
-               s = ppa_completion(cmd);
-        return s + (ppa_error_code << 16);
-}
-
-/* pseudo-interrupt queueing interface */
-
-/* Since the PPA itself doesn't generate interrupts, we use
-   the scheduler's task queue to generate a stream of call-backs and
-   complete the request when the drive is ready.
-*/
-
-static void ppa_interrupt( void *data);
-
-static struct tq_struct ppa_tq = {0,0,ppa_interrupt,NULL};
-
-static void ppa_interrupt( void *data)
-
-{       Scsi_Cmnd *cmd;
-        void  (*done) (Scsi_Cmnd *);
-
-        cmd = ppa_current;
-        done = ppa_done;
-        if (!cmd) return;
-        
-        if (ppa_abort_flag) {
-                ppa_disconnect();
-                if(ppa_abort_flag == 1) cmd->result = DID_ABORT << 16;
-                else { ppa_do_reset();
-                       cmd->result = DID_RESET << 16;
-                }
-                ppa_current = 0;
-                done(cmd);
-                return;
-        }
-        if (!( in_p(1) & 0x80)) {
-                queue_task(&ppa_tq,&tq_scheduler);
-                return;
-        }
-        cmd->result = ppa_completion(cmd) + (ppa_error_code << 16);
-        ppa_current = 0;
-        done(cmd);
-        return;
-}
-
-int     ppa_queuecommand( Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-
-{       if (ppa_current) return 0;
-        sti();
-        ppa_current = cmd;
-        ppa_done = done;
-        if (!ppa_start(cmd)) {
-                cmd->result = ppa_error_code << 16;
-                ppa_current = 0;
-                done(cmd);
-                return 0;
-        }
-        queue_task(&ppa_tq,&tq_scheduler);
-        return 0;
-}
-
-int     ppa_detect( Scsi_Host_Template * host )
-
-{       struct  Scsi_Host       *hreg;
-        int     rs;
-
-        /* can we have the ports ? */
-
-        if (check_region(ppa_base,3)) {
-                printk("PPA: ports at 0x%3x are not available\n",ppa_base);
-                return 0;
-        }
-
-        /* attempt to initialise the controller */
-
-        ppa_port_delay = ppa_speed_low;
-
-        rs = ppa_init();
-        if (rs) {
-            printk("PPA: unable to initialise controller at 0x%x, error %d\n",
-                   ppa_base,rs);
-            return 0;
-        }
-
-        /* now the glue ... */
-
-        host->proc_dir = &proc_scsi_ppa;
-
-        request_region(ppa_base,3,"ppa");
-
-        host->can_queue = PPA_CAN_QUEUE;
-
-        hreg = scsi_register(host,0);
-        hreg->io_port = ppa_base;
-        hreg->n_io_port = 3;
-        hreg->dma_channel = -1;
-
-        sprintf(ppa_info_string,
-                "PPA driver version %s using %d-bit mode on port 0x%x.",
-                PPA_VERSION,8-ppa_nybble*4,ppa_base);
-        host->name = ppa_info_string;
-
-        return 1;       /* 1 host detected */
-}
-
-int     ppa_biosparam( Disk * disk, kdev_t dev, int ip[])
-
-/*  Apparently the the disk->capacity attribute is off by 1 sector 
-    for all disk drives.  We add the one here, but it should really
-    be done in sd.c.  Even if it gets fixed there, this will still
-    work.
-*/
-
-{       ip[0] = 0x40;
-        ip[1] = 0x20;
-        ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
-        if (ip[2] > 1024) {
-                ip[0] = 0xff;
-                ip[1] = 0x3f;
-                ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
-                if (ip[2] > 1023)
-                        ip[2] = 1023;
-        }
-        return 0;
-}
-
-int     ppa_abort( Scsi_Cmnd * cmd )
-
-{       ppa_abort_flag = 1;
-        return SCSI_ABORT_SNOOZE;
-}
-
-int     ppa_reset( Scsi_Cmnd * cmd )
-
-{       ppa_abort_flag = 2;
-        return SCSI_RESET_PUNT;
-}
-
-const char      *ppa_info( struct Scsi_Host * host )
-
-{       return ppa_info_string;
-}
-
+#define PPA_PROBE_SPP   0x0001
+#define PPA_PROBE_PS2   0x0002
+#define PPA_PROBE_ECR   0x0010
+#define PPA_PROBE_EPP17 0x0100
+#define PPA_PROBE_EPP19 0x0200
+int port_probe(unsigned short);
+
+#include <linux/blk.h>
+#include "sd.h"
+#include "hosts.h"
+typedef struct {
+    int base;			/* Actual port address          */
+    int mode;			/* Transfer mode                */
+    int host;			/* Host number (for proc)       */
+    Scsi_Cmnd *cur_cmd;		/* Current queued command       */
+    struct tq_struct ppa_tq;	/* Polling interupt stuff       */
+    unsigned long jstart;	/* Jiffies at start             */
+    unsigned failed:1;		/* Failure flag                 */
+} ppa_struct;
+
+#define PPA_EMPTY \
+{-1,            /* base */      \
+PPA_AUTODETECT, /* mode */      \
+-1,             /* host */      \
+NULL,           /* cur_cmd */   \
+{0, 0, ppa_interrupt, NULL},    \
+0,              /* jstart */    \
+0               /* failed */    \
+}
+
+#include "ppa.h"
+#undef CONFIG_PARPORT
+#define NO_HOSTS 4
+static ppa_struct ppa_hosts[NO_HOSTS] =
+{PPA_EMPTY, PPA_EMPTY, PPA_EMPTY, PPA_EMPTY};
+
+#define PPA_BASE(x)	ppa_hosts[(x)].base
+
+int base[NO_HOSTS] =
+{0x03bc, 0x0378, 0x0278, 0x0000};
+#define parbus_base	base
+#define parbus_no	NO_HOSTS
+
+static inline int ppa_pb_claim(int host_no)
+{
+    if (ppa_hosts[host_no].cur_cmd)
+	ppa_hosts[host_no].cur_cmd->SCp.phase++;
+    return 0;
+}
+
+/***************************************************************************
+ *                   Parallel port probing routines                        *
+ ***************************************************************************/
+  
 #ifndef MODULE
-
-/* Command line parameters (for built-in driver):
-
-   Syntax:  ppa=base[,speed_high[,speed_low[,nybble]]]
-
-   For example:  ppa=0x378   or   ppa=0x378,0,3
-
-*/
-
-void    ppa_setup(char *str, int *ints)
-
-{       if (ints[0] > 0) ppa_base = ints[1];
-        if (ints[0] > 1) ppa_speed_high = ints[2];
-        if (ints[0] > 2) ppa_speed_low = ints[3];
-        if (ints[0] > 3) ppa_nybble = ints[4];
-        if (ints[0] > 4) ppa_nybble = ints[5];
-}
-
+/*
+ * Command line parameters (for built-in driver):
+ *
+ * Syntax:  ppa=base[,mode[,use_sg]]
+ *
+ * For example:  ppa=0x378   or   ppa=0x378,0,3
+ *
+ */
+
+void ppa_setup(char *str, int *ints)
+{
+    static int x = 0;
+
+    if (x == 0) {		/* Disable ALL known ports */
+	int i;
+
+	for (i = 0; i < NO_HOSTS; i++)
+	    parbus_base[i] = 0x0000;
+    }
+    switch (ints[0]) {
+    case 3:
+	ppa_sg = ints[3];
+    case 2:
+	ppa_hosts[x].mode = ints[2];
+	parbus_base[x] = ints[1];
+	break;
+    default:
+	printk("PPA: I only use between 2 to 3 parameters.\n");
+	break;
+    }
+    x++;
+  }
 #else
-
-Scsi_Host_Template      driver_template = PPA;
-
+Scsi_Host_Template driver_template = PPA;
 #include  "scsi_module.c"
-
 #endif
-
-/* end of ppa.c */
+  
+/*
+ * Start of Chipset kludges
+ */
+
+#if HAVE_PC87332 > 0
+#warning PC87332 Kludge code included
+static inline int pc87332_port(int host_no)
+{
+    /* A routine to detect and kludge pc87332 chipsets into the
+     * "optimum" mode for parallel port data transfer.
+     * This assumes EPP is better than ECP...
+     * (Which it is for disk drives but not printers and scanners)
+     */
+    int base = ppa_hosts[host_no].base;
+
+    /* This is where an pc87332 can hide */
+    unsigned short index_addr[4] =
+    {
+	0x0398, 0x026e, 0x015c, 0x002e
+    };
+
+    /* Bits 0&1 of FAR (Function Address Register) which specify where
+     * the LPT port will show up at.
+     */
+    unsigned short port_ref[4] =
+    {
+	0x378, 0x3bc, 0x278, 0xffff
+    };
+
+    unsigned char a;
+    int loop;
+
+    for (loop = 0; loop < 4; loop++) {
+	/* Clear the "wax" out of the pc87332, only needed after hard
+	 * reset.
+	 */
+	inb(index_addr[loop]);
+	inb(index_addr[loop]);
+	inb(index_addr[loop]);
+	inb(index_addr[loop]);
+
+	/* Anyone home ?? */
+	outb(0xff, index_addr[loop]);
+	a = inb(index_addr[loop]);
+	switch (a) {
+	case (0x0f):		/* PC87732 */
+	    break;
+	case (0x1f):		/* PC87306 */
+	    break;
+	case (0x7f):		/* PC87??? */
+	    break;
+	default:
+	    continue;
+	}			/* Is this pc87332 on the desired port */
+	outb(0x01, index_addr[loop]);
+	a = inb(index_addr[loop] + 1);
+	if (port_ref[a & 0x03] != base)
+	    continue;
+
+	/* Found a pc87332 */
+	printk("NatSemi PC87332 (or variant) at 0x%04x\n", base);
+
+	/* Try to enable EPP modes
+	 * with hardware data direction
+	 */
+	if (base != 0x3bc) {
+	    /* EPP 1.9 */
+	    outb(0x04, index_addr[loop]);
+	    a = inb(index_addr[loop] + 1);
+	    printk("Old reg1 = %02x\n", a);
+	    /* 0x01 for EPP 1.7, 0x03 for EPP 1.9, 0x0c for ECP */
+	    a = (a & 0xf0) | 0x03;
+	    outb(a, index_addr[loop] + 1);
+	    outb(a, index_addr[loop] + 1);
+
+	    /* Software data direction selection */
+	    outb(0x02, index_addr[loop]);
+	    a = inb(index_addr[loop] + 1);
+	    printk("Old reg2 = %02x\n", a);
+	    /* 0x80 for software, 0x00 for hardware */
+	    a = (a & 0x7f) | 0x80;
+	    outb(a, index_addr[loop] + 1);
+	    outb(a, index_addr[loop] + 1);
+	    ppa_hosts[host_no].mode = PPA_EPP_32;
+	} else {
+	    /* There is not enough address space for the 0x3bc port
+	     * to have EPP registers so we will kludge it into an
+	     * ECP
+	     * port to allow bi-directional byte mode...
+	     */
+	    /* ECP */
+	    outb(0x04, index_addr[loop]);
+	    a = inb(index_addr[loop] + 1);
+	    a = (a & 0xfb) | 0x06;
+	    outb(a, index_addr[loop] + 1);
+	    outb(a, index_addr[loop] + 1);
+	    ppa_hosts[host_no].mode = PPA_PS2;
+	}
+
+	outb(0x04, index_addr[loop]);
+	a = inb(index_addr[loop] + 1);
+	return ppa_hosts[host_no].mode;
+    }
+    return 0;
+  }
+#else
+#define pc87332_port(x)
+#endif				/* HAVE_PC87332 */
+  
+static inline int generic_port(int host_no)
+{
+    /* Generic parallel port detection
+     * This will try to discover if the port is
+     * EPP, ECP, PS/2 or NIBBLE (In that order, approx....)
+     */
+    unsigned int save_ctr, save_ecr, r;
+    int ppb = PPA_BASE(host_no);
+
+    save_ctr = r_ctr(ppb);
+    save_ecr = r_ecr(ppb);
+    r = port_probe(ppb);
+    w_ecr(ppb, save_ecr);
+    w_ctr(ppb, save_ctr);
+
+    if (r & PPA_PROBE_SPP)
+	ppa_hosts[host_no].mode = PPA_NIBBLE;
+
+    if (r & PPA_PROBE_PS2) {
+	ppa_hosts[host_no].mode = PPA_PS2;
+	if (r & PPA_PROBE_ECR)
+	    w_ecr(ppb, 0x20);
+    }
+    if ((r & PPA_PROBE_EPP17) || (r & PPA_PROBE_EPP19)) {
+	/* ppa_hosts[host_no].mode = PPA_EPP_32; */
+	if (r & PPA_PROBE_ECR)
+	    w_ecr(ppb, 0x80);
+    }
+    return ppa_hosts[host_no].mode;
+}
+
+int ppa_detect(Scsi_Host_Template * host)
+{
+    struct Scsi_Host *hreg;
+    int ports;
+    int i, nhosts;
+    unsigned short ppb;
+
+    printk("ppa: Version %s\n", PPA_VERSION);
+    nhosts = 0;
+
+    for (i = 0; i < parbus_no; i++) {
+	if (parbus_base[i] == 0x0000)
+	    continue;
+	ppb = ppa_hosts[i].base = parbus_base[i];
+
+	/* sanity checks */
+	if (check_region(parbus_base[i],
+			 (parbus_base[i] == 0x03bc) ? 3 : 8))
+	    continue;
+
+	pc87332_port(i);
+	if (!generic_port(i))
+	    continue;
+
+	if (ppa_init(i))
+	    continue;
+
+	/* now the glue ... */
+	switch (ppa_hosts[i].mode) {
+	case PPA_NIBBLE:
+	case PPA_PS2:
+	    ports = 3;
+	    break;
+	case PPA_EPP_8:
+	case PPA_EPP_16:
+	case PPA_EPP_32:
+	    ports = 8;
+	    break;
+	default:		/* Never gets here */
+	    continue;
+	}
+	request_region(ppa_hosts[i].base, ports, "ppa");
+	host->can_queue = PPA_CAN_QUEUE;
+	host->sg_tablesize = ppa_sg;
+	hreg = scsi_register(host, 0);
+	hreg->io_port = ppa_hosts[i].base;
+	hreg->n_io_port = ports;
+	hreg->dma_channel = -1;
+	hreg->unique_id = i;
+	ppa_hosts[i].host = hreg->host_no;
+	nhosts++;
+    }
+    if (nhosts == 0)
+	return 0;
+    else
+	return 1;		/* return number of hosts detected */
+}
+
+/* This is to give the ppa driver a way to modify the timings (and other
+ * parameters) by writing to the /proc/scsi/ppa/0 file.
+ * Very simple method really... (To simple, no error checking :( )
+ * Reason: Kernel hackers HATE having to unload and reload modules for
+ * testing...
+ * Also gives a method to use a script to obtain optimum timings (TODO)
+ */
+
+static inline int ppa_strncmp(const char *a, const char *b, int len)
+{
+    int loop;
+    for (loop = 0; loop < len; loop++)
+	if (a[loop] != b[loop])
+	    return 1;
+
+    return 0;
+}
+static inline int ppa_proc_write(int hostno, char *buffer, int length)
+{
+    unsigned long x;
+
+    if ((length > 5) && (ppa_strncmp(buffer, "mode=", 5) == 0)) {
+	x = simple_strtoul(buffer + 5, NULL, 0);
+	ppa_hosts[hostno].mode = x;
+	return length;
+    }
+    printk("ppa /proc: invalid variable\n");
+    return (-EINVAL);
+}
+
+int ppa_proc_info(char *buffer, char **start, off_t offset,
+		  int length, int hostno, int inout)
+{
+    int i;
+    int len = 0;
+
+    for (i = 0; i < 4; i++)
+	if (ppa_hosts[i].host == hostno)
+	    break;
+
+    if (inout)
+	return ppa_proc_write(i, buffer, length);
+
+    len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
+    len += sprintf(buffer + len, "Port    : 0x%04x\n", ppa_hosts[i].base);
+    len += sprintf(buffer + len, "Mode    : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]);
+
+    /* Request for beyond end of buffer */
+    if (offset > len)
+	return 0;
+
+    *start = buffer + offset;
+    len -= offset;
+    if (len > length)
+	len = length;
+    return len;
+}				/* end of ppa.c */
+static int device_check(int host_no);
+
+#if PPA_DEBUG > 0
+#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
+	   y, __FUNCTION__, __LINE__); ppa_fail_func(x,y);
+static inline void ppa_fail_func(int host_no, int error_code)
+#else
+static inline void ppa_fail(int host_no, int error_code)
+  #endif
+{
+    /* If we fail a device then we trash status / message bytes */
+    if (ppa_hosts[host_no].cur_cmd) {
+	ppa_hosts[host_no].cur_cmd->result = error_code << 16;
+	ppa_hosts[host_no].failed = 1;
+    }
+}
+
+/*
+ * Wait for the high bit to be set.
+ * 
+ * In principle, this could be tied to an interrupt, but the adapter
+ * doesn't appear to be designed to support interrupts.  We spin on
+ * the 0x80 ready bit. 
+ */
+static unsigned char ppa_wait(int host_no)
+{
+    int k;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned char r;
+
+    k = PPA_SPIN_TMO;
+    do {
+	r = r_str(ppb);
+	k--;
+	udelay(1);
+    }
+    while (!(r & 0x80) && (k));
+
+    /*
+     * return some status information.
+     * Semantics: 0xc0 = ZIP wants more data
+     *            0xd0 = ZIP wants to send more data
+     *            0xe0 = ZIP is expecting SCSI command data
+     *            0xf0 = end of transfer, ZIP is sending status
+     */
+    if (k)
+	return (r & 0xf0);
+
+    /* Counter expired - Time out occured */
+    ppa_fail(host_no, DID_TIME_OUT);
+    printk("ppa timeout in ppa_wait\n");
+    return 0;			/* command timed out */
+}
+
+/*
+ * output a string, in whatever mode is available, according to the
+ * PPA protocol. 
+ */
+static inline void epp_reset(unsigned short ppb)
+{
+    int i;
+
+    i = r_str(ppb);
+    w_str(ppb, i);
+    w_str(ppb, i & 0xfe);
+}
+
+static inline void ecp_sync(unsigned short ppb)
+{
+    int i;
+
+    if ((r_ecr(ppb) & 0xe0) != 0x80)
+	return;
+
+    for (i = 0; i < 100; i++) {
+	if (r_ecr(ppb) & 0x01)
+	    return;
+	udelay(5);
+    }
+    printk("ppa: ECP sync failed as data still present in FIFO.\n");
+}
+
+/*
+ * Here is the asm code for the SPP/PS2 protocols for the i386.
+ * This has been optimised for speed on 386/486 machines. There will
+ * be very little improvement on the current 586+ machines as it is the
+ * IO statements which will limit throughput.
+ */
+#ifdef __i386__
+#define BYTE_OUT(reg) \
+	"	movb " #reg ",%%al\n" \
+	"	outb %%al,(%%dx)\n" \
+	"	addl $2,%%edx\n" \
+	"	movb $0x0e,%%al\n" \
+	"	outb %%al,(%%dx)\n" \
+	"	movb $0x0c,%%al\n" \
+	"	outb %%al,(%%dx)\n" \
+	"	subl $2,%%edx\n"
+
+static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int len)
+{
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+	"	jz .no_more_bulk_bo\n" \
+	"	.align 4\n" \
+	".loop_bulk_bo:\n" \
+	"	movl (%%esi),%%ebx\n" \
+	BYTE_OUT(%%bl) \
+	BYTE_OUT(%%bh) \
+	"	rorl $16,%%ebx\n" \
+	BYTE_OUT(%%bl) \
+	BYTE_OUT(%%bh) \
+	"	addl $4,%%esi\n" \
+	"	loop .loop_bulk_bo\n" \
+	"	.align 4\n" \
+	".no_more_bulk_bo:" \
+  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+	"	jz .no_more_loose_bo\n" \
+	"	.align 4\n" \
+	".loop_loose_bo:\n" \
+	BYTE_OUT((%%esi)) \
+	"	incl %%esi\n" \
+	"	loop .loop_loose_bo\n" \
+	".no_more_loose_bo:\n" \
+  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;			/* All went well - we hope! */
+}
+
+#define BYTE_IN(reg) \
+	"	inb (%%dx),%%al\n" \
+	"	movb %%al," #reg "\n" \
+	"	addl $2,%%edx\n" \
+	"	movb $0x27,%%al\n" \
+	"	outb %%al,(%%dx)\n" \
+	"	movb $0x25,%%al\n" \
+	"	outb %%al,(%%dx)\n" \
+	"	subl $2,%%edx\n"
+
+static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
+{
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+	"	jz .no_more_bulk_bi\n" \
+	"	.align 4\n" \
+	".loop_bulk_bi:\n" \
+	BYTE_IN(%%bl) \
+	BYTE_IN(%%bh) \
+	"	rorl $16,%%ebx\n" \
+	BYTE_IN(%%bl) \
+	BYTE_IN(%%bh) \
+	"	rorl $16,%%ebx\n" \
+	"	movl %%ebx,(%%esi)\n" \
+	"	addl $4,%%esi\n" \
+	"	loop .loop_bulk_bi\n" \
+	"	.align 4\n" \
+	".no_more_bulk_bi:" \
+  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+	"	jz .no_more_loose_bi\n" \
+	"	.align 4\n" \
+	".loop_loose_bi:\n" \
+	BYTE_IN((%%esi)) \
+	"	incl %%esi\n" \
+	"	loop .loop_loose_bi\n" \
+	".no_more_loose_bi:\n" \
+  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;			/* All went well - we hope! */
+}
+
+#define NIBBLE_IN(reg) \
+	"	incl %%edx\n" \
+	"	movb $0x04,%%al\n" \
+	"	outb %%al,(%%dx)\n" \
+	"	decl %%edx\n" \
+	"	inb (%%dx),%%al\n" \
+	"	andb $0xf0,%%al\n" \
+	"	movb %%al," #reg "\n" \
+	"	incl %%edx\n" \
+	"	movb $0x06,%%al\n" \
+	"	outb %%al,(%%dx)\n" \
+	"	decl %%edx\n" \
+	"	inb (%%dx),%%al\n" \
+	"	shrb $4,%%al\n" \
+	"	orb %%al," #reg "\n"
+
+static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
+{
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+	"	jz .no_more_bulk_ni\n" \
+	"	.align 4\n" \
+	".loop_bulk_ni:\n" \
+	NIBBLE_IN(%%bl) \
+	NIBBLE_IN(%%bh) \
+	"	rorl $16,%%ebx\n" \
+	NIBBLE_IN(%%bl) \
+	NIBBLE_IN(%%bh) \
+	"	rorl $16,%%ebx\n" \
+	"	movl %%ebx,(%%esi)\n" \
+	"	addl $4,%%esi\n" \
+	"	loop .loop_bulk_ni\n" \
+	"	.align 4\n" \
+	".no_more_bulk_ni:" \
+  : "=S"(buffer): "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+	"	jz .no_more_loose_ni\n" \
+	"	.align 4\n" \
+	".loop_loose_ni:\n" \
+	NIBBLE_IN((%%esi)) \
+	"	incl %%esi\n" \
+	"	loop .loop_loose_ni\n" \
+	".no_more_loose_ni:\n" \
+  : /* no output */ : "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;			/* All went well - we hope! */
+}
+#else				/* Old style C routines */
+
+static inline int ppa_byte_out(unsigned short base, const char *buffer, int len)
+{
+    unsigned short ctr_p = base + 2;
+    int i;
+
+    for (i = len; i; i--) {
+	outb(*buffer++, base);
+	outb(0xe, ctr_p);
+	outb(0xc, ctr_p);
+    }
+    return 1;			/* All went well - we hope! */
+}
+
+static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
+{
+    unsigned short ctr_p = base + 2;
+    int i;
+
+    for (i = len; i; i--) {
+	*buffer++ = inb(base);
+	outb(0x27, ctr_p);
+	outb(0x25, ctr_p);
+    }
+    return 1;			/* All went well - we hope! */
+}
+
+static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
+{
+    unsigned short ctr_p = str_p + 1;
+    unsigned char h, l;
+    int i;
+
+    for (i = len; i; i--) {
+	outb(0x4, ctr_p);
+	h = inb(str_p);
+	outb(0x6, ctr_p);
+	l = inb(str_p);
+	*buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4);
+    }
+    return 1;			/* All went well - we hope! */
+  }
+  #endif
+  
+static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const char *buffer, int len)
+{
+    int i;
+    for (i = len; i; i--) {
+	outb(*buffer++, epp_p);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+	if (inb(str_p) & 0x01)
+	    return 0;
+  #endif
+    }
+    return 1;
+  }
+  
+static int ppa_out(int host_no, char *buffer, int len)
+{
+    int r;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    r = ppa_wait(host_no);
+
+    if ((r & 0x50) != 0x40) {
+	ppa_fail(host_no, DID_ERROR);
+	return 0;
+    }
+    switch (ppa_hosts[host_no].mode) {
+    case PPA_NIBBLE:
+    case PPA_PS2:
+	/* 8 bit output, with a loop */
+	r = ppa_byte_out(ppb, buffer, len);
+	break;
+
+    case PPA_EPP_32:
+    case PPA_EPP_16:
+    case PPA_EPP_8:
+	epp_reset(ppb);
+	w_ctr(ppb, 0x4);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+	r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len);
+#else
+	if (!(((long) buffer | len) & 0x03))
+	    outsl(ppb + 4, buffer, len >> 2);
+	else
+	    outsb(ppb + 4, buffer, len);
+	w_ctr(ppb, 0xc);
+	r = !(r_str(ppb) & 0x01);
+#endif
+	w_ctr(ppb, 0xc);
+	ecp_sync(ppb);
+	break;
+
+    default:
+	printk("PPA: bug in ppa_out()\n");
+	r = 0;
+    }
+    return r;
+}
+
+static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len)
+{
+    int i;
+    for (i = len; i; i--) {
+	*buffer++ = inb(epp_p);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+	if (inb(str_p) & 0x01)
+	    return 0;
+#endif
+    }
+    return 1;
+  }
+  
+static int ppa_in(int host_no, char *buffer, int len)
+{
+    int r;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    r = ppa_wait(host_no);
+
+    if ((r & 0x50) != 0x50) {
+	ppa_fail(host_no, DID_ERROR);
+	return 0;
+    }
+    switch (ppa_hosts[host_no].mode) {
+    case PPA_NIBBLE:
+	/* 4 bit input, with a loop */
+	r = ppa_nibble_in(ppb + 1, buffer, len);
+	w_ctr(ppb, 0xc);
+	break;
+
+    case PPA_PS2:
+	/* 8 bit input, with a loop */
+	w_ctr(ppb, 0x25);
+	r = ppa_byte_in(ppb, buffer, len);
+	w_ctr(ppb, 0x4);
+	w_ctr(ppb, 0xc);
+	break;
+
+    case PPA_EPP_32:
+    case PPA_EPP_16:
+    case PPA_EPP_8:
+	epp_reset(ppb);
+	w_ctr(ppb, 0x24);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+	r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len);
+  #else
+	if (!(((long) buffer | len) & 0x03))
+	    insl(ppb + 4, buffer, len >> 2);
+	else
+	    insb(ppb + 4, buffer, len);
+	w_ctr(ppb, 0x2c);
+	r = !(r_str(ppb) & 0x01);
+#endif
+	w_ctr(ppb, 0x2c);
+	ecp_sync(ppb);
+	break;
+
+    default:
+	printk("PPA: bug in ppa_ins()\n");
+	r = 0;
+	break;
+    }
+    return r;
+}
+
+/* end of ppa_io.h */
+static inline void ppa_d_pulse(unsigned short ppb, unsigned char b)
+{
+    w_dtr(ppb, b);
+    w_ctr(ppb, 0xc);
+    w_ctr(ppb, 0xe);
+    w_ctr(ppb, 0xc);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0xc);
+}
+
+static void ppa_disconnect(int host_no)
+{
+    unsigned short ppb = PPA_BASE(host_no);
+
+    ppa_d_pulse(ppb, 0);
+    ppa_d_pulse(ppb, 0x3c);
+    ppa_d_pulse(ppb, 0x20);
+    ppa_d_pulse(ppb, 0xf);
+}
+
+static inline void ppa_c_pulse(unsigned short ppb, unsigned char b)
+{
+    w_dtr(ppb, b);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0x6);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0xc);
+}
+
+static inline void ppa_connect(int host_no, int flag)
+{
+    unsigned short ppb = PPA_BASE(host_no);
+
+    ppa_c_pulse(ppb, 0);
+    ppa_c_pulse(ppb, 0x3c);
+    ppa_c_pulse(ppb, 0x20);
+    if ((flag == CONNECT_EPP_MAYBE) &&
+	IN_EPP_MODE(ppa_hosts[host_no].mode))
+	ppa_c_pulse(ppb, 0xcf);
+    else
+	ppa_c_pulse(ppb, 0x8f);
+}
+
+static int ppa_select(int host_no, int target)
+{
+    int k;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    /*
+     * Bit 6 (0x40) is the device selected bit.
+     * First we must wait till the current device goes off line...
+     */
+    k = PPA_SELECT_TMO;
+    do {
+	k--;
+    } while ((r_str(ppb) & 0x40) && (k));
+    if (!k)
+	return 0;
+
+    w_dtr(ppb, (1 << target));
+    w_ctr(ppb, 0xe);
+    w_ctr(ppb, 0xc);
+    w_dtr(ppb, 0x80);		/* This is NOT the initator */
+    w_ctr(ppb, 0x8);
+
+    k = PPA_SELECT_TMO;
+    do {
+	k--;
+    }
+    while (!(r_str(ppb) & 0x40) && (k));
+    if (!k)
+	return 0;
+
+    return 1;
+}
+
+/* 
+ * This is based on a trace of what the Iomega DOS 'guest' driver does.
+ * I've tried several different kinds of parallel ports with guest and
+ * coded this to react in the same ways that it does.
+ * 
+ * The return value from this function is just a hint about where the
+ * handshaking failed.
+ * 
+ */
+static int ppa_init(int host_no)
+{
+    int retv;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    ppa_disconnect(host_no);
+    ppa_connect(host_no, CONNECT_NORMAL);
+
+    retv = 2;			/* Failed */
+
+    w_ctr(ppb, 0xe);
+    if ((r_str(ppb) & 0x08) == 0x08)
+	retv--;
+
+    w_ctr(ppb, 0xc);
+    if ((r_str(ppb) & 0x08) == 0x00)
+	retv--;
+
+    /* This is a SCSI BUS reset signal */
+    if (!retv) {
+	w_dtr(ppb, 0x40);
+	w_ctr(ppb, 0x08);
+	udelay(30);
+	w_ctr(ppb, 0x0c);
+	udelay(1000);		/* Allow devices to settle down */
+    }
+    ppa_disconnect(host_no);
+    udelay(1000);		/* Another delay to allow devices to settle */
+
+    if (!retv)
+	retv = device_check(host_no);
+
+    return retv;
+}
+
+static inline int ppa_send_command(Scsi_Cmnd * cmd)
+{
+    int host_no = cmd->host->unique_id;
+    int k;
+
+    w_ctr(PPA_BASE(host_no), 0x0c);
+
+    for (k = 0; k < cmd->cmd_len; k++)
+	if (!ppa_out(host_no, &cmd->cmnd[k], 1))
+	    return 0;
+    return 1;
+}
+
+/*
+ * The bulk flag enables some optimisations in the data transfer loops,
+ * it should be true for any command that transfers data in integral
+ * numbers of sectors.
+ * 
+ * The driver appears to remain stable if we speed up the parallel port
+ * i/o in this function, but not elsewhere.
+ */
+static int ppa_completion(Scsi_Cmnd * cmd)
+{
+    /* Return codes:
+     * -1     Error
+     *  0     Told to schedule
+     *  1     Finished data transfer
+     */
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned long start_jiffies = jiffies;
+
+    unsigned char r, v;
+    int fast, bulk, status;
+
+    v = cmd->cmnd[0];
+    bulk = ((v == READ_6) ||
+	    (v == READ_10) ||
+	    (v == WRITE_6) ||
+	    (v == WRITE_10));
+
+    /*
+     * We only get here if the drive is ready to comunicate,
+     * hence no need for a full ppa_wait.
+     */
+    r = (r_str(ppb) & 0xf0);
+
+    while (r != (unsigned char) 0xf0) {
+	/*
+	 * If we have been running for more than a full timer tick
+	 * then take a rest.
+	 */
+	if (jiffies > start_jiffies + 1)
+	    return 0;
+
+	if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {
+	    ppa_fail(host_no, DID_ERROR);
+	    return -1;		/* ERROR_RETURN */
+	}
+	/* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
+	    ? PPA_BURST_SIZE : 1;
+
+	if (r == (unsigned char) 0xc0)
+	    status = ppa_out(host_no, cmd->SCp.ptr, fast);
+	else
+	    status = ppa_in(host_no, cmd->SCp.ptr, fast);
+
+	cmd->SCp.ptr += fast;
+	cmd->SCp.this_residual -= fast;
+
+	if (!status) {
+	    ppa_fail(host_no, DID_BUS_BUSY);
+	    return -1;		/* ERROR_RETURN */
+	}
+	if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
+	    /* if scatter/gather, advance to the next segment */
+	    if (cmd->SCp.buffers_residual--) {
+		cmd->SCp.buffer++;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		cmd->SCp.ptr = cmd->SCp.buffer->address;
+	    }
+	}
+	/* Now check to see if the drive is ready to comunicate */
+	r = (r_str(ppb) & 0xf0);
+	/* If not, drop back down to the scheduler and wait a timer tick */
+	if (!(r & 0x80))
+	    return 0;
+    }
+    return 1;			/* FINISH_RETURN */
+}
+
+/*
+ * Since the PPA itself doesn't generate interrupts, we use
+ * the scheduler's task queue to generate a stream of call-backs and
+ * complete the request when the drive is ready.
+ */
+static void ppa_interrupt(void *data)
+{
+    ppa_struct *tmp = (ppa_struct *) data;
+    Scsi_Cmnd *cmd = tmp->cur_cmd;
+
+    if (!cmd) {
+	printk("PPA: bug in ppa_interrupt\n");
+	return;
+    }
+    if (ppa_engine(tmp, cmd)) {
+	tmp->ppa_tq.data = (void *) tmp;
+	tmp->ppa_tq.sync = 0;
+	queue_task(&tmp->ppa_tq, &tq_timer);
+	return;
+    }
+    /* Command must of completed hence it is safe to let go... */
+#if PPA_DEBUG > 0
+    switch ((cmd->result >> 16) & 0xff) {
+    case DID_OK:
+	break;
+    case DID_NO_CONNECT:
+	printk("ppa: no device at SCSI ID %i\n", cmd->target);
+	break;
+    case DID_BUS_BUSY:
+	printk("ppa: BUS BUSY - EPP timeout detected\n");
+	break;
+    case DID_TIME_OUT:
+	printk("ppa: unknown timeout\n");
+	break;
+    case DID_ABORT:
+	printk("ppa: told to abort\n");
+	break;
+    case DID_PARITY:
+	printk("ppa: parity error (???)\n");
+	break;
+    case DID_ERROR:
+	printk("ppa: internal driver error\n");
+	break;
+    case DID_RESET:
+	printk("ppa: told to reset device\n");
+	break;
+    case DID_BAD_INTR:
+	printk("ppa: bad interrupt (???)\n");
+	break;
+    default:
+	printk("ppa: bad return code (%02x)\n", (cmd->result >> 16) & 0xff);
+    }
+  #endif
+  
+    if (cmd->SCp.phase > 1)
+	ppa_disconnect(cmd->host->unique_id);
+
+    tmp->cur_cmd = 0;
+    cmd->scsi_done(cmd);
+    return;
+}
+
+static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd)
+{
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned char l = 0, h = 0;
+    int retv;
+
+    /* First check for any errors that may of occured
+     * Here we check for internal errors
+     */
+    if (tmp->failed)
+	return 0;
+
+    switch (cmd->SCp.phase) {
+    case 0:			/* Phase 0 - Waiting for parport */
+	if ((jiffies - tmp->jstart) > HZ) {
+	    /*
+	     * We waited more than a second
+	     * for parport to call us
+	     */
+	    ppa_fail(host_no, DID_BUS_BUSY);
+	    return 0;
+	}
+	return 1;		/* wait until ppa_wakeup claims parport */
+    case 1:			/* Phase 1 - Connected */
+	{			/* Perform a sanity check for cable unplugged */
+	    int retv = 2;	/* Failed */
+
+	    ppa_connect(host_no, CONNECT_EPP_MAYBE);
+
+	    w_ctr(ppb, 0xe);
+	    if ((r_str(ppb) & 0x08) == 0x08)
+		retv--;
+
+	    w_ctr(ppb, 0xc);
+	    if ((r_str(ppb) & 0x08) == 0x00)
+		retv--;
+
+	    if (retv)
+		if ((jiffies - tmp->jstart) > (1 * HZ)) {
+		    printk("ppa: Parallel port cable is unplugged!!\n");
+		    ppa_fail(host_no, DID_BUS_BUSY);
+		    return 0;
+		} else {
+		    ppa_disconnect(host_no);
+		    return 1;	/* Try again in a jiffy */
+		}
+	    cmd->SCp.phase++;
+	}
+
+    case 2:			/* Phase 2 - We are now talking to the scsi bus */
+	if (!ppa_select(host_no, cmd->target)) {
+	    ppa_fail(host_no, DID_NO_CONNECT);
+	    return 0;
+	}
+	cmd->SCp.phase++;
+
+    case 3:			/* Phase 3 - Ready to accept a command */
+	w_ctr(ppb, 0x0c);
+	if (!(r_str(ppb) & 0x80))
+	    return 1;
+
+	if (!ppa_send_command(cmd))
+	    return 0;
+	cmd->SCp.phase++;
+
+    case 4:			/* Phase 4 - Setup scatter/gather buffers */
+	if (cmd->use_sg) {
+	    /* if many buffers are available, start filling the first */
+	    cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+	    cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	    cmd->SCp.ptr = cmd->SCp.buffer->address;
+	} else {
+	    /* else fill the only available buffer */
+	    cmd->SCp.buffer = NULL;
+	    cmd->SCp.this_residual = cmd->request_bufflen;
+	    cmd->SCp.ptr = cmd->request_buffer;
+	}
+	cmd->SCp.buffers_residual = cmd->use_sg;
+	cmd->SCp.phase++;
+
+    case 5:			/* Phase 5 - Data transfer stage */
+	w_ctr(ppb, 0x0c);
+	if (!(r_str(ppb) & 0x80))
+	    return 1;
+
+	retv = ppa_completion(cmd);
+	if (retv == -1)
+	    return 0;
+	if (retv == 0)
+	    return 1;
+	cmd->SCp.phase++;
+
+    case 6:			/* Phase 6 - Read status/message */
+	cmd->result = DID_OK << 16;
+	/* Check for data overrun */
+	if (ppa_wait(host_no) != (unsigned char) 0xf0) {
+	    ppa_fail(host_no, DID_ERROR);
+	    return 0;
+	}
+	if (ppa_in(host_no, &l, 1)) {	/* read status byte */
+	    /* Check for optional message byte */
+	    if (ppa_wait(host_no) == (unsigned char) 0xf0)
+		ppa_in(host_no, &h, 1);
+	    cmd->result = (DID_OK << 16) + (h << 8) + (l & STATUS_MASK);
+	}
+	return 0;		/* Finished */
+	break;
+
+    default:
+	printk("ppa: Invalid scsi phase\n");
+    }
+    return 0;
+}
+
+int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+    int host_no = cmd->host->unique_id;
+
+    if (ppa_hosts[host_no].cur_cmd) {
+	printk("PPA: bug in ppa_queuecommand\n");
+	return 0;
+    }
+    ppa_hosts[host_no].failed = 0;
+    ppa_hosts[host_no].jstart = jiffies;
+    ppa_hosts[host_no].cur_cmd = cmd;
+    cmd->scsi_done = done;
+    cmd->result = DID_ERROR << 16;	/* default return code */
+    cmd->SCp.phase = 0;		/* bus free */
+
+    ppa_pb_claim(host_no);
+
+    ppa_hosts[host_no].ppa_tq.data = ppa_hosts + host_no;
+    ppa_hosts[host_no].ppa_tq.sync = 0;
+    queue_task(&ppa_hosts[host_no].ppa_tq, &tq_immediate);
+    mark_bh(IMMEDIATE_BH);
+
+    return 0;
+}
+
+/*
+ * Apparently the disk->capacity attribute is off by 1 sector 
+ * for all disk drives.  We add the one here, but it should really
+ * be done in sd.c.  Even if it gets fixed there, this will still
+ * work.
+ */
+int ppa_biosparam(Disk * disk, kdev_t dev, int ip[])
+{
+    ip[0] = 0x40;
+    ip[1] = 0x20;
+    ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+    if (ip[2] > 1024) {
+	ip[0] = 0xff;
+	ip[1] = 0x3f;
+	ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+	if (ip[2] > 1023)
+	    ip[2] = 1023;
+    }
+    return 0;
+}
+
+int ppa_abort(Scsi_Cmnd * cmd)
+{
+    /*
+     * There is no method for aborting commands since Iomega
+     * have tied the SCSI_MESSAGE line high in the interface
+     */
+
+    switch (cmd->SCp.phase) {
+    case 0:			/* Do not have access to parport */
+    case 1:			/* Have not connected to interface */
+	cmd->result = DID_ABORT;
+	cmd->done(cmd);
+	return SCSI_ABORT_SUCCESS;
+	break;
+    default:			/* SCSI command sent, can not abort */
+	return SCSI_ABORT_BUSY;
+	break;
+    }
+}
+
+int ppa_reset(Scsi_Cmnd * cmd, unsigned int x)
+{
+    int host_no = cmd->host->unique_id;
+    int ppb = PPA_BASE(host_no);
+
+    /*
+     * PHASE1:
+     * Bring the interface crashing down on whatever is running
+     * hopefully this will kill the request.
+     * Bring back up the interface, reset the drive (and anything
+     * attached for that manner)
+     */
+    if (cmd)
+	if (cmd->SCp.phase)
+	    ppa_disconnect(cmd->host->unique_id);
+
+    ppa_connect(host_no, CONNECT_NORMAL);
+    w_dtr(ppb, 0x40);
+    w_ctr(ppb, 0x8);
+    udelay(30);
+    w_ctr(ppb, 0xc);
+    udelay(1000);		/* delay for devices to settle down */
+    ppa_disconnect(host_no);
+    udelay(1000);		/* Additional delay to allow devices to settle down */
+
+    /*
+     * PHASE2:
+     * Sanity check for the sake of mid-level driver
+     */
+    if (!cmd) {
+	printk("ppa bus reset called for invalid command.\n");
+	return SCSI_RESET_NOT_RUNNING;
+    }
+    /*
+     * PHASE3:
+     * Flag the current command as having died due to reset
+     */
+    ppa_connect(host_no, CONNECT_NORMAL);
+    ppa_fail(host_no, DID_RESET);
+
+    /* Since the command was already on the timer queue ppa_interrupt
+     * will be called shortly.
+     */
+    return SCSI_RESET_PENDING;
+}
+
+static int device_check(int host_no)
+{
+    /* This routine looks for a device and then attempts to use EPP
+       to send a command. If all goes as planned then EPP is available. */
+
+    static char cmd[6] =
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    int loop, old_mode, status, k, ppb = PPA_BASE(host_no);
+    unsigned char l;
+
+    old_mode = ppa_hosts[host_no].mode;
+    for (loop = 0; loop < 8; loop++) {
+	/* Attempt to use EPP for Test Unit Ready */
+	if ((ppb & 0x0007) == 0x0000)
+	    ppa_hosts[host_no].mode = PPA_EPP_32;
+
+      second_pass:
+	ppa_connect(host_no, CONNECT_EPP_MAYBE);
+	/* Select SCSI device */
+	if (!ppa_select(host_no, loop)) {
+	    ppa_disconnect(host_no);
+	    continue;
+	}
+	printk("ppa: Found device at ID %i, Attempting to use %s\n", loop,
+	       PPA_MODE_STRING[ppa_hosts[host_no].mode]);
+
+	/* Send SCSI command */
+	status = 1;
+	w_ctr(ppb, 0x0c);
+	for (l = 0; (l < 6) && (status); l++)
+	    status = ppa_out(host_no, cmd, 1);
+
+	if (!status) {
+	    ppa_disconnect(host_no);
+	    ppa_connect(host_no, CONNECT_EPP_MAYBE);
+	    w_dtr(ppb, 0x40);
+	    w_ctr(ppb, 0x08);
+	    udelay(30);
+	    w_ctr(ppb, 0x0c);
+	    udelay(1000);
+	    ppa_disconnect(host_no);
+	    udelay(1000);
+	    if (ppa_hosts[host_no].mode == PPA_EPP_32) {
+		ppa_hosts[host_no].mode = old_mode;
+		goto second_pass;
+	    }
+	    printk("ppa: Unable to establish communication, aborting driver load.\n");
+	    return 1;
+	}
+	w_ctr(ppb, 0x0c);
+	k = 1000000;		/* 1 Second */
+	do {
+	    l = r_str(ppb);
+	    k--;
+	    udelay(1);
+	} while (!(l & 0x80) && (k));
+
+	l &= 0xf0;
+
+	if (l != 0xf0) {
+	    ppa_disconnect(host_no);
+	    ppa_connect(host_no, CONNECT_EPP_MAYBE);
+	    w_dtr(ppb, 0x40);
+	    w_ctr(ppb, 0x08);
+	    udelay(30);
+	    w_ctr(ppb, 0x0c);
+	    udelay(1000);
+	    ppa_disconnect(host_no);
+	    udelay(1000);
+	    if (ppa_hosts[host_no].mode == PPA_EPP_32) {
+		ppa_hosts[host_no].mode = old_mode;
+		goto second_pass;
+	    }
+	    printk("ppa: Unable to establish communication, aborting driver load.\n");
+	    return 1;
+	}
+	ppa_disconnect(host_no);
+	printk("ppa: Communication established with ID %i using %s\n", loop,
+	       PPA_MODE_STRING[ppa_hosts[host_no].mode]);
+	return 0;
+    }
+    printk("ppa: No devices found, aborting driver load.\n");
+    return 1;
+}
+
+#define PPA_ID "ppa: "
+
+int port_probe(unsigned short port)
+{
+    int retv = 0;
+    unsigned char a, b, c;
+    unsigned int i, j;
+
+
+    printk(PPA_ID "Probing port %04x\n", port);
+
+/*                 #####  ######  ######
+ *                #     # #     # #     #
+ *                #       #     # #     #
+ *                 #####  ######  ######
+ *                      # #       #
+ *                #     # #       #
+ *                 #####  #       #
+ */
+
+    outb(0x0c, port + 0x402);
+    outb(0x0c, port + 0x002);
+    outb(0x55, port);
+    a = inb(port);
+    if (a != 0x55)
+	return retv;
+    printk(PPA_ID "    SPP port present\n");
+
+    retv += PPA_PROBE_SPP;
+
+/*                #######  #####  ######
+ *                #       #     # #     #
+ *                #       #       #     #
+ *                #####   #       ######
+ *                #       #       #
+ *                #       #     # #
+ *                #######  #####  #
+ */
+
+    for (i = 1024; i > 0; i--) {	/* clear at most 1k of data from FIFO */
+	a = inb(port + 0x402);
+	if ((a & 0x03) == 0x03)
+	    goto no_ecp;
+	if (a & 0x01)
+	    break;
+	inb(port + 0x400);	/* Remove byte from FIFO */
+    }
+
+    if (i <= 0)
+	goto no_ecp;
+
+    b = a ^ 3;
+    outb(b, port + 0x402);
+    c = inb(port + 0x402);
+
+    if (a == c) {
+	outb(0xc0, port + 0x402);	/* FIFO test */
+	j = 0;
+	while (!(inb(port + 0x402) & 0x01) && (j < 1024)) {
+	    inb(port + 0x400);
+	    j++;
+	}
+	if (j >= 1024)
+	    goto no_ecp;
+	i = 0;
+	j = 0;
+	while (!(inb(port + 0x402) & 0x02) && (j < 1024)) {
+	    outb(0x00, port + 0x400);
+	    i++;
+	    j++;
+	}
+	if (j >= 1024)
+	    goto no_ecp;
+	j = 0;
+	while (!(inb(port + 0x402) & 0x01) && (j < 1024)) {
+	    inb(port + 0x400);
+	    j++;
+	}
+	if (j >= 1024)
+	    goto no_ecp;
+	printk(PPA_ID "    ECP with a %i byte FIFO present\n", i);
+
+	retv += PPA_PROBE_ECR;
+    }
+/*                ######   #####   #####
+ *                #     # #     # #     #
+ *                #     # #             #
+ *                ######   #####   #####
+ *                #             # #
+ *                #       #     # #
+ *                #        #####  #######
+ */
+
+  no_ecp:
+    if (retv & PPA_PROBE_ECR)
+	outb(0x20, port + 0x402);
+
+    outb(0x55, port);
+    outb(0x0c, port + 2);
+    a = inb(port);
+    outb(0x55, port);
+    outb(0x2c, port + 2);
+    b = inb(port);
+    if (a != b) {
+	printk(PPA_ID "    PS/2 bidirectional port present\n");
+	retv += PPA_PROBE_PS2;
+    }
+/*                ####### ######  ######
+ *                #       #     # #     #
+ *                #       #     # #     #
+ *                #####   ######  ######
+ *                #       #       #
+ *                #       #       #
+ *                ####### #       #
+ */
+
+    if (port & 0x007) {
+	printk(PPA_ID "    EPP not supported at this address\n");
+	return retv;
+    }
+    if (retv & PPA_PROBE_ECR) {
+	for (i = 0x00; i < 0x80; i += 0x20) {
+	    outb(i, port + 0x402);
+
+	    a = inb(port + 1);
+	    outb(a, port + 1);
+	    outb(a & 0xfe, port + 1);
+	    a = inb(port + 1);
+	    if (!(a & 0x01)) {
+		printk(PPA_ID "    Failed Intel bug check. (Phony EPP in ECP)\n");
+		return retv;
+	    }
+	}
+	printk(PPA_ID "    Passed Intel bug check.\n");
+	outb(0x80, port + 0x402);
+    }
+    a = inb(port + 1);
+    outb(a, port + 1);
+    outb(a & 0xfe, port + 1);
+    a = inb(port + 1);
+
+    if (a & 0x01) {
+	outb(0x0c, port + 0x402);
+	outb(0x0c, port + 0x002);
+	return retv;
+    }
+
+    outb(0x04, port + 2);
+    inb(port + 4);
+    a = inb(port + 1);
+    outb(a, port + 1);
+    outb(a & 0xfe, port + 1);
+
+    if (a & 0x01) {
+	printk(PPA_ID "    EPP 1.9 with hardware direction protocol\n");
+	retv += PPA_PROBE_EPP19;
+    } else {
+	/* The EPP timeout bit was not set, this could either be:
+	 * EPP 1.7
+	 * EPP 1.9 with software direction
+	 */
+	outb(0x24, port + 2);
+	inb(port + 4);
+	a = inb(port + 1);
+	outb(a, port + 1);
+	outb(a & 0xfe, port + 1);
+	if (a & 0x01) {
+	    printk(PPA_ID "    EPP 1.9 with software direction protocol\n");
+	    retv += PPA_PROBE_EPP19;
+	} else {
+	    printk(PPA_ID "    EPP 1.7\n");
+	    retv += PPA_PROBE_EPP17;
+	}
+    }
+
+    outb(0x0c, port + 0x402);
+    outb(0x0c, port + 0x002);
+    return retv;
+}
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h
--- v2.0.33/linux/drivers/scsi/ppa.h	Thu Mar 14 02:57:46 1996
+++ linux/drivers/scsi/ppa.h	Wed Jun  3 15:17:49 1998
@@ -1,44 +1,173 @@
-#ifndef _PPA_H
-#define _PPA_H
-
 /*  Driver for the PPA3 parallel port SCSI HBA embedded in 
-    the Iomega ZIP drive
+ * the Iomega ZIP drive
+ * 
+ * (c) 1996     Grant R. Guenther  grant@torque.net
+ *		David Campbell	   campbell@torque.net
+ *
+ *	All comments to David.
+ */
 
-	(c) 1996	Grant R. Guenther  grant@torque.net
-*/
+#ifndef _PPA_H
+#define _PPA_H
 
-#define	PPA_INITIATOR	7
+#define   PPA_VERSION   "1.42"
 
-int ppa_detect(Scsi_Host_Template * );
-const char * ppa_info(struct Scsi_Host *);
-int ppa_command(Scsi_Cmnd *);
-int ppa_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+/* Use the following to enable certain chipset support
+ * Default is PEDANTIC = 3
+ */
+#ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+#define CONFIG_SCSI_PPA_HAVE_PEDANTIC	3
+#endif
+
+/* 
+ * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
+ * to support EPP and scatter-gather.                        [0.26-athena]
+ *
+ * additional hacks by David Campbell
+ * in response to this driver "mis-behaving" on his machine.
+ *      Fixed EPP to handle "software" changing of EPP port data direction.
+ *      Chased down EPP timeouts
+ *      Made this driver "kernel version friendly"           [0.28-athena]
+ *
+ * [ Stuff removed ]
+ *
+ * Compiled against 2.1.53.
+ *	Rebuilt ppa_abort() function, should handle unplugged cable.
+ *							[1.35s]
+ *
+ * PPA now auto probes for EPP on base address which are aligned on
+ * 8 byte boundaries (0x278 & 0x378) using the attached devices.
+ * This hopefully avoids the nasty problem of trying to detect EPP.
+ *	Tested on 2.1.53				[1.36]
+ *
+ * The id_probe utility no longer performs read/write tests.
+ * Additional code included for checking the Intel ECP bug
+ * (Bit 0 of STR stuck low which fools the EPP detection routine)
+ *							[1.37]
+ *
+ * Oops! Got the bit sign mixed up for the Intel bug check.
+ * Found that an additional delay is required during SCSI resets
+ * to allow devices to settle down.
+ *							[1.38]
+ *
+ * Fixed all problems in the parport sharing scheme. Now ppa can be safe
+ * used with lp or other parport devices on the same parallel port.
+ *		1997 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *							[1.39]
+ *
+ * Little fix in ppa engine to ensure that ppa don' t release parport
+ * or disconnect in wrong cases.
+ *		1997 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *							[1.40]
+ *
+ * Corrected ppa.h for 2.1.x kernels (>=2.1.85)
+ * Modified "Nat Semi Kludge" for extended chipsets
+ *							[1.41]
+ *
+ * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7)
+ *							[1.42]
+ */
+/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
+
+#ifdef PPA_CODE
+#include  <linux/stddef.h>
+#include  <linux/module.h>
+#include  <linux/kernel.h>
+#include  <linux/tqueue.h>
+#include  <linux/ioport.h>
+#include  <linux/delay.h>
+#include  <linux/proc_fs.h>
+#include  <linux/stat.h>
+#include  <linux/blk.h>
+#include  <linux/sched.h>
+#include  <linux/interrupt.h>
+
+#include  <asm/io.h>
+#include  "sd.h"
+#include  "hosts.h"
+/* batteries not included :-) */
+
+/*
+ * modes in which the driver can operate 
+ */
+#define   PPA_AUTODETECT        0	/* Autodetect mode                */
+#define   PPA_NIBBLE            1	/* work in standard 4 bit mode    */
+#define   PPA_PS2               2	/* PS/2 byte mode         */
+#define   PPA_EPP_8             3	/* EPP mode, 8 bit                */
+#define   PPA_EPP_16            4	/* EPP mode, 16 bit               */
+#define   PPA_EPP_32            5	/* EPP mode, 32 bit               */
+#define   PPA_UNKNOWN           6	/* Just in case...                */
+
+static char *PPA_MODE_STRING[] =
+{
+    "Autodetect",
+    "SPP",
+    "PS/2",
+    "EPP 8 bit",
+    "EPP 16 bit",
+    "EPP 32 bit",
+    "Unknown"};
+
+/* This is a global option */
+int ppa_sg = SG_ALL;		/* enable/disable scatter-gather. */
+
+/* other options */
+#define PPA_CAN_QUEUE   1	/* use "queueing" interface */
+#define PPA_BURST_SIZE	512	/* data burst size */
+#define PPA_SELECT_TMO  5000	/* how long to wait for target ? */
+#define PPA_SPIN_TMO    50000	/* ppa_wait loop limiter */
+#define PPA_DEBUG	0	/* debuging option */
+#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
+
+/* args to ppa_connect */
+#define CONNECT_EPP_MAYBE 1
+#define CONNECT_NORMAL  0
+
+#define r_dtr(x)        (unsigned char)inb((x))
+#define r_str(x)        (unsigned char)inb((x)+1)
+#define r_ctr(x)        (unsigned char)inb((x)+2)
+#define r_epp(x)        (unsigned char)inb((x)+4)
+#define r_fifo(x)       (unsigned char)inb((x)+0x400)
+#define r_ecr(x)        (unsigned char)inb((x)+0x402)
+
+#define w_dtr(x,y)      outb(y, (x))
+#define w_str(x,y)      outb(y, (x)+1)
+#define w_ctr(x,y)      outb(y, (x)+2)
+#define w_epp(x,y)      outb(y, (x)+4)
+#define w_fifo(x,y)     outb(y, (x)+0x400)
+#define w_ecr(x,y)      outb(y, (x)+0x402)
+
+static int ppa_engine(ppa_struct *, Scsi_Cmnd *);
+static int ppa_in(int, char *, int);
+static int ppa_init(int);
+static void ppa_interrupt(void *);
+static int ppa_out(int, char *, int);
+
+struct proc_dir_entry proc_scsi_ppa =
+{PROC_SCSI_PPA, 3, "ppa", S_IFDIR | S_IRUGO | S_IXUGO, 2};
+#else
+extern struct proc_dir_entry proc_scsi_ppa;
+#endif
+
+int ppa_detect(Scsi_Host_Template *);
+const char *ppa_info(struct Scsi_Host *);
+int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int ppa_abort(Scsi_Cmnd *);
-int ppa_reset(Scsi_Cmnd *);
-int ppa_biosparam(Disk *, kdev_t, int[]);
-
-#define PPA {			\
-	0,			\
-	0,			\
-	0,			\
-	0,		        \
-	0,			\
-	ppa_detect,		\
-	0,			\
-	ppa_info,		\
-	ppa_command, 		\
-	ppa_queuecommand,	\
-	ppa_abort,		\
-	ppa_reset,		\
-	0,			\
-	ppa_biosparam,		\
-	0,			\
-	PPA_INITIATOR,		\
-	SG_NONE,		\
-	1,			\
-	0,			\
-	0,			\
-	DISABLE_CLUSTERING	\
+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 {	proc_dir:		&proc_scsi_ppa,			\
+		proc_info:		ppa_proc_info,			\
+		name:			"Iomega parport ZIP drive",	\
+		detect:			ppa_detect,			\
+		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 */
+#endif				/* _PPA_H */
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.0.33/linux/drivers/scsi/qlogicisp.c	Wed Jul 10 03:11:25 1996
+++ linux/drivers/scsi/qlogicisp.c	Wed Jun  3 15:17:49 1998
@@ -296,7 +296,12 @@
 #define CS_DEVICE_RESET_MSG_FAILED	0x0012
 #define CS_ID_MSG_FAILED		0x0013
 #define CS_UNEXP_BUS_FREE		0x0014
+/* as per app note #83120-514-06a: */
 #define CS_DATA_UNDERRUN		0x0015
+#define CS_INVALID_ENTRY_TYPE		0x001b
+#define CS_DEVICE_QUEUE_FULL		0x001c
+#define CS_SCSI_PHASE_SKIPPED		0x001d
+#define CS_ARS_FAILED			0x001e	/* auto Req. Sense failed */
 
 /* status entry state flag definitions */
 #define SF_GOT_BUS			0x0100
@@ -992,6 +997,10 @@
 	      case CS_DEVICE_RESET_MSG_FAILED:
 	      case CS_ID_MSG_FAILED:
 	      case CS_UNEXP_BUS_FREE:
+	      case CS_INVALID_ENTRY_TYPE:
+	      case CS_DEVICE_QUEUE_FULL:
+	      case CS_SCSI_PHASE_SKIPPED:
+	      case CS_ARS_FAILED:
 		host_status = DID_ERROR;
 		break;
 	      case CS_DATA_UNDERRUN:
@@ -1248,7 +1257,8 @@
 	if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
 	    || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
 	{
-		printk("qlogicisp : can't decode i/o address space\n");
+		printk("qlogicisp : can't decode i/o address space at 0x%x\n",
+		       io_base);
 		return 1;
 	}
 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.0.33/linux/drivers/scsi/scsi.c	Mon Aug 11 13:37:24 1997
+++ linux/drivers/scsi/scsi.c	Wed Jun  3 15:17:49 1998
@@ -229,6 +229,7 @@
  */
 static struct dev_info device_list[] =
 {
+{"TEAC","CD-R55S","1.0H", BLIST_NOLUN},         /* Locks up if polled for lun != 0 */
 {"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
 {"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
 {"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.0.33/linux/drivers/scsi/scsi_ioctl.c	Mon Aug 25 12:34:15 1997
+++ linux/drivers/scsi/scsi_ioctl.c	Wed Jun  3 15:17:49 1998
@@ -164,7 +164,7 @@
  * interface instead, as this is a more flexible approach to performing
  * generic SCSI commands on a device.
  */
-static int ioctl_command(Scsi_Device *dev, void *buffer)
+int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer)
 {
     char * buf;
     unsigned char cmd[12]; 
@@ -348,6 +348,11 @@
 		    (unsigned long *) arg);
         put_user( dev->host->unique_id, (unsigned long *) arg+1);
 	return 0;
+    case SCSI_IOCTL_GET_BUS_NUMBER:
+        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+        if (result) return result;
+        put_user( dev->host->host_no, (int *) arg);
+        return 0;
     case SCSI_IOCTL_TAGGED_ENABLE:
 	if(!suser())  return -EACCES;
 	if(!dev->tagged_supported) return -EINVAL;
@@ -363,8 +368,8 @@
     case SCSI_IOCTL_PROBE_HOST:
 	return ioctl_probe(dev->host, arg);
     case SCSI_IOCTL_SEND_COMMAND:
-	if(!suser())  return -EACCES;
-	return ioctl_command((Scsi_Device *) dev, arg);
+	if(!suser() || securelevel > 0)  return -EACCES;
+	return scsi_ioctl_send_command((Scsi_Device *) dev, arg);
     case SCSI_IOCTL_DOORLOCK:
 	if (!dev->removable || !dev->lockable) return 0;
 	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- v2.0.33/linux/drivers/scsi/scsi_syms.c	Sun Aug 17 12:49:03 1997
+++ linux/drivers/scsi/scsi_syms.c	Wed Jun  3 15:17:49 1998
@@ -36,6 +36,7 @@
 
 extern void print_command (unsigned char *command);
 extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
+extern int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer);
 
 struct symbol_table scsi_symbol_table = {
 #include <linux/symtab_begin.h>
@@ -64,6 +65,7 @@
     X(scsi_mark_host_reset),
     X(scsi_mark_bus_reset),
     X(scsi_device_types),
+    X(scsi_ioctl_send_command),
 #if defined(CONFIG_PROC_FS)
     X(proc_print_scsidevice),
 #endif
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.0.33/linux/drivers/scsi/sd.c	Wed Aug 13 18:46:08 1997
+++ linux/drivers/scsi/sd.c	Wed Jun  3 15:17:49 1998
@@ -259,6 +259,21 @@
       }
     
     /*
+     * Handle RECOVERED ERRORs that indicate success after recovery action
+     * by the target device.
+     */
+
+    if (SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
+	SCpnt->sense_buffer[2] == RECOVERED_ERROR)
+      {
+	printk("scsidisk recovered I/O error: dev %s, sector %lu, absolute sector %lu\n",
+	       kdevname(SCpnt->request.rq_dev), SCpnt->request.sector, 
+	       SCpnt->request.sector + sd[MINOR(SCpnt->request.rq_dev)].start_sect);
+	good_sectors = this_count;
+	result = 0;
+      }
+
+    /*
      * First case : we assume that the command succeeded.  One of two things 
      * will happen here.  Either we will be finished, or there will be more
      * sectors that we were unable to read last time.
@@ -1360,14 +1375,21 @@
     return 0;
 }
 
-static void sd_finish()
+static void sd_finish(void)
 {
+    struct gendisk *gendisk;
     int i;
 
     blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
     
-    sd_gendisk.next = gendisk_head;
-    gendisk_head = &sd_gendisk;
+    for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next)
+      if (gendisk == &sd_gendisk)
+	break;
+    if (gendisk == NULL)
+      {
+	sd_gendisk.next = gendisk_head;
+	gendisk_head = &sd_gendisk;
+      }
     
     for (i = 0; i < sd_template.dev_max; ++i)
 	if (!rscsi_disks[i].capacity && 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c
--- v2.0.33/linux/drivers/scsi/sd_ioctl.c	Wed May  1 21:48:54 1996
+++ linux/drivers/scsi/sd_ioctl.c	Wed Jun  3 15:17:49 1998
@@ -91,6 +91,9 @@
 	
     case BLKRRPART: /* Re-read partition tables */
 	return revalidate_scsidisk(dev, 1);
+
+    RO_IOCTLS(dev, arg);
+
     default:
 	return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
     }
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.0.33/linux/drivers/scsi/sg.c	Sat Aug 31 23:15:33 1996
+++ linux/drivers/scsi/sg.c	Wed Jun  3 15:17:49 1998
@@ -73,13 +73,20 @@
     switch(cmd_in)
     {
     case SG_SET_TIMEOUT:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(long));
+        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
         if (result) return result;
 
 	scsi_generics[dev].timeout=get_user((int *) arg);
 	return 0;
     case SG_GET_TIMEOUT:
 	return scsi_generics[dev].timeout;
+    case SCSI_IOCTL_SEND_COMMAND:
+	/*
+	  Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
+	  user already has read/write access to the generic device and so
+	  can execute arbitrary SCSI commands.
+	*/
+	return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg);
     default:
 	return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
     }
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.0.33/linux/drivers/scsi/sr_ioctl.c	Mon Sep  1 11:21:30 1997
+++ linux/drivers/scsi/sr_ioctl.c	Wed Jun  3 15:17:49 1998
@@ -519,9 +519,10 @@
 	return result;
     }
 	
-    case CDROMREADMODE2:
-	return -EINVAL;
+    /* these are compatible with the ide-cd driver */
+    case CDROMREADRAW:
     case CDROMREADMODE1:
+    case CDROMREADMODE2:
 	return -EINVAL;
 	
 	/* block-copy from ../block/sbpcd.c with some adjustments... */
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.0.33/linux/drivers/scsi/tmscsim.c	Thu Aug 14 10:31:20 1997
+++ linux/drivers/scsi/tmscsim.c	Wed Jun  3 15:17:49 1998
@@ -24,6 +24,8 @@
  *	1.09  11/30/96	KG	Added register the allocated IO space	*
  *	1.10  12/05/96	CLH	Modified tmscsim_proc_info(), and reset *
  *				pending interrupt in DC390_detect()	*
+ * 	1.11  02/05/97	KG/CLH	Fixeds problem with partitions greater	*
+ * 				than 1GB				*
  ***********************************************************************/
 
 
@@ -689,11 +691,11 @@
     sectors = 32;
     cylinders = disk->capacity / (heads * sectors);
 
-    if ( cylinders > 1024)
+    if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
     {
       heads = 255;
       sectors = 63;
-      cylinders = disk->capacity / (255 * 63);
+      cylinders = disk->capacity / (heads * sectors);
     }
 
     geom[0] = heads;
@@ -1182,7 +1184,7 @@
 #ifdef	VERSION_ELF_1_2_13
 	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
 #else
-	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
+	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
 #endif
 	{
 	    printk("DC390: register IRQ error!\n");
@@ -1793,7 +1795,7 @@
   if (acbpnt == (PACB)-1) return(-ESRCH);
   if(!shpnt) return(-ESRCH);
 
-  if(inout) // Has data been written to the file ?
+  if(inout) /* Has data been written to the file ? */
     return(tmscsim_set_info(buffer, length, shpnt));
 
   SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.0.33/linux/drivers/scsi/u14-34f.c	Mon Sep 15 09:41:28 1997
+++ linux/drivers/scsi/u14-34f.c	Wed Jun  3 15:17:49 1998
@@ -1,6 +1,40 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
+ *          Improved abort handling during the eh recovery process.
+ *
+ *      13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
+ *          The driver is now fully SMP safe, including the
+ *          abort and reset routines.
+ *          Added command line options (eh:[y|n]) to choose between
+ *          new_eh_code and the old scsi code.
+ *          If linux verion >= 2.1.101 the default is eh:y, while the eh
+ *          option is ignored for previous releases and the old scsi code
+ *          is used.
+ *
+ *      18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
+ *          Reworked interrupt handler.
+ *
+ *      11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
+ *          Major reliability improvement: when a batch with overlapping
+ *          requests is detected, requests are queued one at a time
+ *          eliminating any possible board or drive reordering.
+ *
+ *      10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ *          Improved SMP support (if linux version >= 2.1.95).
+ *
+ *       9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ *          Performance improvement: when sequential i/o is detected,
+ *          always use direct sort instead of reverse sort.
+ *
+ *       4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
+ *          io_port is now unsigned long.
+ *
+ *      17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
+ *          Use new scsi error handling code (if linux version >= 2.1.88).
+ *          Use new interrupt code.
+ *
  *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
  *          Use of udelay inside the wait loops to avoid timeout
  *          problems with fast cpus.
@@ -21,7 +55,7 @@
  *          Fixed data transfer direction for some SCSI opcodes.
  *          Immediate acknowledge to request sense commands.
  *          Linked commands to each disk device are now reordered by elevator
- *          sorting. Rare cases in which reordering of write requests could 
+ *          sorting. Rare cases in which reordering of write requests could
  *          cause wrong results are managed.
  *
  *      18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28
@@ -105,15 +139,15 @@
  *      28 Oct 1994 rev. 1.09 for linux 1.1.58  Final BETA release.
  *      16 Jul 1994 rev. 1.00 for linux 1.1.29  Initial ALPHA release.
  *
- *          This driver is a total replacement of the original UltraStor 
+ *          This driver is a total replacement of the original UltraStor
  *          scsi driver, but it supports ONLY the 14F and 34F boards.
  *          It can be configured in the same kernel in which the original
  *          ultrastor driver is configured to allow the original U24F
  *          support.
- * 
+ *
  *          Multiple U14F and/or U34F host adapters are supported.
  *
- *  Copyright (C) 1994-1997 Dario Ballabio (dario@milano.europe.dg.com)
+ *  Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com)
  *
  *  Redistribution and use in source and binary forms, with or without
  *  modification, are permitted provided that redistributions of source
@@ -134,11 +168,11 @@
  *  24F - EISA Bus Master HA with floppy support and WD1003 emulation.
  *  34F - VESA Local-Bus Bus Master HA (no WD1003 emulation).
  *
- *  This code has been tested with up to two U14F boards, using both 
+ *  This code has been tested with up to two U14F boards, using both
  *  firmware 28004-005/38004-004 (BIOS rev. 2.00) and the latest firmware
- *  28004-006/38004-005 (BIOS rev. 2.01). 
+ *  28004-006/38004-005 (BIOS rev. 2.01).
  *
- *  The latest firmware is required in order to get reliable operations when 
+ *  The latest firmware is required in order to get reliable operations when
  *  clustering is enabled. ENABLE_CLUSTERING provides a performance increase
  *  up to 50% on sequential access.
  *
@@ -154,24 +188,24 @@
  *  have their BIOS disabled, or enabled to an higher address.
  *  Boards are named Ux4F0, Ux4F1..., according to the port address order in
  *  the io_port[] array.
- *  
+ *
  *  The following facts are based on real testing results (not on
  *  documentation) on the above U14F board.
- *  
- *  - The U14F board should be jumpered for bus on time less or equal to 7 
- *    microseconds, while the default is 11 microseconds. This is order to 
- *    get acceptable performance while using floppy drive and hard disk 
- *    together. The jumpering for 7 microseconds is: JP13 pin 15-16, 
+ *
+ *  - The U14F board should be jumpered for bus on time less or equal to 7
+ *    microseconds, while the default is 11 microseconds. This is order to
+ *    get acceptable performance while using floppy drive and hard disk
+ *    together. The jumpering for 7 microseconds is: JP13 pin 15-16,
  *    JP14 pin 7-8 and pin 9-10.
  *    The reduction has a little impact on scsi performance.
- *  
+ *
  *  - If scsi bus length exceeds 3m., the scsi bus speed needs to be reduced
  *    from 10Mhz to 5Mhz (do this by inserting a jumper on JP13 pin 7-8).
  *
  *  - If U14F on board firmware is older than 28004-006/38004-005,
- *    the U14F board is unable to provide reliable operations if the scsi 
+ *    the U14F board is unable to provide reliable operations if the scsi
  *    request length exceeds 16Kbyte. When this length is exceeded the
- *    behavior is: 
+ *    behavior is:
  *    - adapter_status equal 0x96 or 0xa3 or 0x93 or 0x94;
  *    - adapter_status equal 0 and target_status equal 2 on for all targets
  *      in the next operation following the reset.
@@ -185,7 +219,7 @@
  *    Any reset of the scsi bus is going to kill tape operations, since
  *    no retry is allowed for tapes. Bus resets are more likely when the
  *    scsi bus is under heavy load.
- *    Requests using scatter/gather have a maximum length of 16 x 1024 bytes 
+ *    Requests using scatter/gather have a maximum length of 16 x 1024 bytes
  *    when DISABLE_CLUSTERING is in effect, but unscattered requests could be
  *    larger than 16Kbyte.
  *
@@ -205,6 +239,8 @@
  *  After the optional list of detection probes, other possible command line
  *  options are:
  *
+ *  eh:y  use new scsi code (linux 2.2 only);
+ *  eh:n  use old scsi code;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  of:y  enables old firmware support;
@@ -212,13 +248,13 @@
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
  *
  *  The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list
- *  of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4".
+ *  of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- *                max_queue_depth=4
+ *                max_queue_depth=4 use_new_eh_code=0
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -232,15 +268,15 @@
  *  in the elevator sorting queue. When the active command completes, the
  *  commands in this queue are sorted by sector address. The sort is chosen
  *  between increasing or decreasing by minimizing the seek distance between
- *  the sector of the commands just completed and the sector of the first 
- *  command in the list to be sorted. 
+ *  the sector of the commands just completed and the sector of the first
+ *  command in the list to be sorted.
  *  Trivial math assures that the unsorted average seek distance when doing
  *  random seeks over S sectors is S/3.
  *  When (Q-1) requests are uniformly distributed over S sectors, the average
  *  distance between two adjacent requests is S/((Q-1) + 1), so the sorted
  *  average seek distance for (Q-1) random requests over S sectors is S/Q.
  *  The elevator sorting hence divides the seek distance by a factor Q/3.
- *  The above pure geometric remarks are valid in all cases and the 
+ *  The above pure geometric remarks are valid in all cases and the
  *  driver effectively reduces the seek distance by the predicted factor
  *  when there are Q concurrent read i/o operations on the device, but this
  *  does not necessarily results in a noticeable performance improvement:
@@ -248,7 +284,7 @@
  *
  *  Note: command reordering inside a batch of queued commands could cause
  *        wrong results only if there is at least one write request and the
- *        intersection (sector-wise) of all requests is not empty. 
+ *        intersection (sector-wise) of all requests is not empty.
  *        When the driver detects a batch including overlapping requests
  *        (a really rare event) strict serial (pid) order is enforced.
  *  ----------------------------------------------------------------------------
@@ -259,19 +295,24 @@
  *  the driver sets host->wish_block = TRUE for all ISA boards.
  */
 
+#include <linux/version.h>
+
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #define MAX_INT_PARAM 10
+
 #if defined(MODULE)
 #include <linux/module.h>
-#include <linux/version.h>
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
 MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
 MODULE_PARM(linked_comm, "i");
 MODULE_PARM(have_old_firmware, "i");
 MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
+MODULE_PARM(use_new_eh_code, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
+
 #endif
 
 #include <linux/string.h>
@@ -301,6 +342,34 @@
 #define __init
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+#include <asm/spinlock.h>
+#define IRQ_FLAGS
+#define IRQ_LOCK
+#define IRQ_LOCK_SAVE
+#define IRQ_UNLOCK
+#define IRQ_UNLOCK_RESTORE
+#define SPIN_FLAGS unsigned long spin_flags;
+#define SPIN_LOCK spin_lock_irq(&io_request_lock);
+#define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags);
+#define SPIN_UNLOCK spin_unlock_irq(&io_request_lock);
+#define SPIN_UNLOCK_RESTORE \
+                  spin_unlock_irqrestore(&io_request_lock, spin_flags);
+static int use_new_eh_code = TRUE;
+#else
+#define IRQ_FLAGS unsigned long irq_flags;
+#define IRQ_LOCK cli();
+#define IRQ_LOCK_SAVE do {save_flags(irq_flags); cli();} while (0);
+#define IRQ_UNLOCK sti();
+#define IRQ_UNLOCK_RESTORE do {restore_flags(irq_flags);} while (0);
+#define SPIN_FLAGS
+#define SPIN_LOCK
+#define SPIN_LOCK_SAVE
+#define SPIN_UNLOCK
+#define SPIN_UNLOCK_RESTORE
+static int use_new_eh_code = FALSE;
+#endif
+
 struct proc_dir_entry proc_scsi_u14_34f = {
     PROC_SCSI_U14_34F, 6, "u14_34f",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
@@ -329,19 +398,18 @@
 #undef  DEBUG_LINKED_COMMANDS
 #undef  DEBUG_DETECT
 #undef  DEBUG_INTERRUPT
-#undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
-#undef  DEBUG_SMP
+#undef  DEBUG_GENERATE_ERRORS
+#undef  DEBUG_GENERATE_ABORTS
 
 #define MAX_ISA 3
-#define MAX_VESA 1 
+#define MAX_VESA 1
 #define MAX_EISA 0
 #define MAX_PCI 0
 #define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
 #define MAX_CHANNEL 1
 #define MAX_LUN 8
 #define MAX_TARGET 8
-#define MAX_IRQ 16
 #define MAX_MAILBOXES 16
 #define MAX_SGLIST 32
 #define MAX_SAFE_SGLIST 16
@@ -349,7 +417,7 @@
 #define MAX_CMD_PER_LUN 2
 #define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
 
-#define SKIP UINT_MAX
+#define SKIP ULONG_MAX
 #define FALSE 0
 #define TRUE 1
 #define FREE 0
@@ -424,7 +492,6 @@
    unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
    unsigned int last_cp_used;           /* Index of last mailbox used */
    unsigned int iocount;                /* Total i/o done for this board */
-   unsigned int multicount;             /* Total ... in second ihdlr loop */
    int board_number;                    /* Number of this board */
    char board_name[16];                 /* Name of this board */
    char board_id[256];                  /* data from INQUIRY on this board */
@@ -443,9 +510,12 @@
 
 static struct Scsi_Host *sh[MAX_BOARDS + 1];
 static const char *driver_name = "Ux4F";
-static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
+static char sha[MAX_BOARDS];
 
-static unsigned int io_port[] __initdata = { 
+/* Initialize num_boards so that ihdlr can work while detect is in progress */
+static unsigned int num_boards = MAX_BOARDS;
+
+static unsigned long io_port[] __initdata = {
 
    /* Space for MAX_INT_PARAM ports usable while loading as a module */
    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
@@ -462,10 +532,10 @@
 #define BN(board) (HD(board)->board_name)
 
 #define SWAP_BYTE(x) ((unsigned long)( \
-	(((unsigned long)(x) & 0x000000ffU) << 24) | \
-	(((unsigned long)(x) & 0x0000ff00U) <<  8) | \
-	(((unsigned long)(x) & 0x00ff0000U) >>  8) | \
-	(((unsigned long)(x) & 0xff000000U) >> 24)))
+        (((unsigned long)(x) & 0x000000ffU) << 24) | \
+        (((unsigned long)(x) & 0x0000ff00U) <<  8) | \
+        (((unsigned long)(x) & 0x00ff0000U) >>  8) | \
+        (((unsigned long)(x) & 0xff000000U) >> 24)))
 
 #if defined(__BIG_ENDIAN)
 #define H2DEV(x) SWAP_BYTE(x)
@@ -477,25 +547,25 @@
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
 #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
-static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
+static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
 static int link_statistics = 0;
 
-#if defined (HAVE_OLD_UX4F_FIRMWARE)
+#if defined(HAVE_OLD_UX4F_FIRMWARE)
 static int have_old_firmware = TRUE;
 #else
 static int have_old_firmware = FALSE;
 #endif
 
-#if defined (CONFIG_SCSI_U14_34F_LINKED_COMMANDS)
+#if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS)
 static int linked_comm = TRUE;
 #else
 static int linked_comm = FALSE;
 #endif
 
-#if defined CONFIG_SCSI_U14_34F_MAX_TAGS
+#if defined(CONFIG_SCSI_U14_34F_MAX_TAGS)
 static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS;
 #else
 static int max_queue_depth = MAX_CMD_PER_LUN;
@@ -503,12 +573,10 @@
 
 static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
    Scsi_Device *dev;
-   int j, ntag = 0, nuntag = 0, tqd, utqd; 
-   unsigned long flags;
-
-   save_flags(flags);
-   cli();
+   int j, ntag = 0, nuntag = 0, tqd, utqd;
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    j = ((struct hostdata *) host->hostdata)->board_number;
 
    for(dev = devlist; dev; dev = dev->next) {
@@ -556,11 +624,11 @@
              dev->queue_depth, link_suffix, tag_suffix);
       }
 
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return;
 }
 
-static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
+static inline int wait_on_busy(unsigned long iobase, unsigned int loop) {
 
    while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) {
       udelay(1L);
@@ -599,10 +667,12 @@
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
 
-   sti();
+   SPIN_UNLOCK
+   IRQ_UNLOCK
    time = jiffies;
    while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L);
-   cli();
+   IRQ_LOCK
+   SPIN_LOCK
 
    if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
       HD(j)->cp_stat[0] = FREE;
@@ -614,31 +684,31 @@
 }
 
 __initfunc (static inline int port_detect \
-      (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
    unsigned char irq, dma_channel, subversion, i;
    unsigned char in_byte;
    char *bus_type, dma_name[16];
 
    /* Allowed BIOS base addresses (NULL indicates reserved) */
-   void *bios_segment_table[8] = { 
-      NULL, 
+   void *bios_segment_table[8] = {
+      NULL,
       (void *) 0xc4000, (void *) 0xc8000, (void *) 0xcc000, (void *) 0xd0000,
       (void *) 0xd4000, (void *) 0xd8000, (void *) 0xdc000
       };
-   
+
    /* Allowed IRQs */
    unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
-   
+
    /* Allowed DMA channels for ISA (0 indicates reserved) */
    unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
-   
+
    /* Head/sector mappings */
    struct {
       unsigned char heads;
       unsigned char sectors;
-      } mapping_table[4] = { 
-	   { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
-	   };
+      } mapping_table[4] = {
+           { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
+           };
 
    struct config_1 {
       unsigned char bios_segment: 3;
@@ -659,7 +729,7 @@
    sprintf(name, "%s%d", driver_name, j);
 
    if(check_region(port_base, REGION_SIZE)) {
-      printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
+      printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);
       return FALSE;
       }
 
@@ -676,26 +746,35 @@
    dma_channel = dma_channel_table[config_1.dma_channel];
    subversion = (in_byte & 0x0f);
 
-   /* Board detected, allocate its IRQ if not already done */
-   if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
-              u14_34f_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+   /* Board detected, allocate its IRQ */
+   if (request_irq(irq, do_interrupt_handler,
+             SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+             driver_name, (void *) &sha[j])) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
 
    if (subversion == ISA && request_dma(dma_channel, driver_name)) {
       printk("%s: unable to allocate DMA channel %u, detaching.\n",
-	     name, dma_channel);
-      free_irq(irq, NULL);
+             name, dma_channel);
+      free_irq(irq, &sha[j]);
       return FALSE;
       }
 
+   if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+   tpnt->use_new_eh_code = use_new_eh_code;
+#else
+   use_new_eh_code = FALSE;
+#endif
+
    sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
 
    if (sh[j] == NULL) {
       printk("%s: unable to register host, detaching.\n", name);
 
-      if (!irqlist[irq]) free_irq(irq, NULL);
+      free_irq(irq, &sha[j]);
 
       if (subversion == ISA) free_dma(dma_channel);
 
@@ -723,6 +802,9 @@
    }
 #endif
 
+   /* Probably a bogus host scsi id, set it to the dummy value */
+   if (sh[j]->this_id == 0) sh[j]->this_id = -1;
+
    /* If BIOS is disabled, force enable interrupts */
    if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK);
 
@@ -734,7 +816,6 @@
    HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
    HD(j)->subversion = subversion;
    HD(j)->board_number = j;
-   irqlist[irq]++;
 
    if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
 
@@ -751,9 +832,6 @@
       clear_dma_ff(dma_channel);
       set_dma_mode(dma_channel, DMA_MODE_CASCADE);
       enable_dma(dma_channel);
-
-      if (have_old_firmware) sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
-
       sh[j]->dma_channel = dma_channel;
       sprintf(BN(j), "U14F%d", j);
       bus_type = "ISA";
@@ -767,12 +845,12 @@
       HD(j)->board_id[40] = 0;
 
       if (strcmp(&HD(j)->board_id[32], "06000600")) {
-	 printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
-	 printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
-		BN(j), &HD(j)->board_id[32]);
-	 sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
-	 sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
-	 }
+         printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
+         printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
+                BN(j), &HD(j)->board_id[32]);
+         sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
+         sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
+         }
       }
 
    if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
@@ -780,29 +858,35 @@
 
    for (i = 0; i < sh[j]->can_queue; i++)
       if (! ((&HD(j)->cp[i])->sglist = kmalloc(
-            sh[j]->sg_tablesize * sizeof(struct sg_list), 
+            sh[j]->sg_tablesize * sizeof(struct sg_list),
             (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
          printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
          u14_34f_release(sh[j]);
          return FALSE;
          }
-      
-   if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) 
+
+   if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
        max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
 
    if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
 
-   printk("%s: %s 0x%03x, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d, of:%c, "\
-          "lc:%c, mq:%d.\n", BN(j), bus_type, sh[j]->io_port, (int)sh[j]->base,
-          sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue,
-          YESNO(have_old_firmware), YESNO(linked_comm), max_queue_depth);
+   if (j == 0) {
+      printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
+      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c.\n",
+             driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
+             max_queue_depth, YESNO(use_new_eh_code));
+      }
+
+   printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
+          BN(j), bus_type, (unsigned long)sh[j]->io_port, (int)sh[j]->base,
+          sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
 
    if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
       printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
    for (i = 0; i <= sh[j]->max_channel; i++)
-      printk("%s: SCSI channel %u enabled, host target ID %u.\n",
+      printk("%s: SCSI channel %u enabled, host target ID %d.\n",
              BN(j), i, sh[j]->this_id);
 
    return TRUE;
@@ -816,8 +900,8 @@
 
       if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
 
-      for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; 
-   
+      for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
+
       io_port[i] = 0;
       setup_done = TRUE;
       }
@@ -833,6 +917,7 @@
       else if (!strncmp(cur, "of:", 3)) have_old_firmware = val;
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
+      else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -841,14 +926,12 @@
 }
 
 __initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
-   unsigned long flags;
    unsigned int j = 0, k;
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    tpnt->proc_dir = &proc_scsi_u14_34f;
 
-   save_flags(flags);
-   cli();
-
 #if defined(MODULE)
    /* io_port could have been modified when loading as a module */
    if(io_port[0] != SKIP) {
@@ -857,11 +940,6 @@
       }
 #endif
 
-   for (k = 0; k < MAX_IRQ; k++) {
-      irqlist[k] = 0;
-      calls[k] = 0;
-      }
-
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
    for (k = 0; io_port[k]; k++) {
@@ -871,10 +949,8 @@
       if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
       }
 
-   if (j > 0) 
-      printk("UltraStor 14F/34F: Copyright (C) 1994-1997 Dario Ballabio.\n");
-
-   restore_flags(flags);
+   num_boards = j;
+   IRQ_UNLOCK_RESTORE
    return j;
 }
 
@@ -895,14 +971,13 @@
    cpp->data_len = H2DEV(data_len);
 }
 
-int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned long flags;
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    unsigned int i, j, k;
    struct mscp *cpp;
 
    static const unsigned char data_out_cmds[] = {
       0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
-      0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, 
+      0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
       0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
       };
 
@@ -912,24 +987,14 @@
       0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
       };
 
-   save_flags(flags);
-   cli();
    /* j is the board number */
    j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
 
-   if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
+   if (SCpnt->host_scribble)
+      panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
+            BN(j), SCpnt->pid, SCpnt);
 
-   if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
-      SCpnt->result = DID_OK << 16; 
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
-             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);    
-      return 0;
-      }
-
-   /* i is the mailbox number, look for the first free mailbox 
+   /* i is the mailbox number, look for the first free mailbox
       starting from last_cp_used */
    i = HD(j)->last_cp_used + 1;
 
@@ -938,26 +1003,14 @@
       if (i >= sh[j]->can_queue) i = 0;
 
       if (HD(j)->cp_stat[i] == FREE) {
-	 HD(j)->last_cp_used = i;
-	 break;
-	 }
+         HD(j)->last_cp_used = i;
+         break;
+         }
       }
 
    if (k == sh[j]->can_queue) {
-      printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
-
-      if (HD(j)->in_reset) 
-	 printk("%s: qcomm, already in reset.\n", BN(j));
-      else if (u14_34f_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET) 
-               == SCSI_RESET_SUCCESS) 
-	 panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
-
-      SCpnt->result = DID_BUS_BUSY << 16; 
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);    
-      return 0;
+      printk("%s: qcomm, no free mailbox.\n", BN(j));
+      return 1;
       }
 
    /* Set pointer to control packet structure */
@@ -969,16 +1022,16 @@
    SCpnt->host_scribble = (unsigned char *) &cpp->index;
 
    if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
-			BN(j), i, SCpnt->channel, SCpnt->target, 
+                        BN(j), i, SCpnt->channel, SCpnt->target,
                         SCpnt->lun, SCpnt->pid);
 
    cpp->xdir = DTD_IN;
 
    for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
       if (SCpnt->cmnd[0] == data_out_cmds[k]) {
-	 cpp->xdir = DTD_OUT;
-	 break;
-	 }
+         cpp->xdir = DTD_OUT;
+         break;
+         }
 
    if (cpp->xdir == DTD_IN)
       for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
@@ -1011,19 +1064,14 @@
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
       flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
-      restore_flags(flags);
       return 0;
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
-      SCpnt->result = DID_ERROR << 16;
       SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
-             " done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
-             SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);
-      return 0;
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
+             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
+      return 1;
       }
 
    /* Store pointer in OGM address bytes */
@@ -1033,42 +1081,46 @@
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
 
    HD(j)->cp_stat[i] = IN_USE;
-   restore_flags(flags);
    return 0;
 }
 
-int u14_34f_abort(Scsi_Cmnd *SCarg) {
-   unsigned long flags;
+int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_qcomm(SCpnt, done);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+static inline int do_old_abort(Scsi_Cmnd *SCarg) {
    unsigned int i, j;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
-   if (SCarg->host_scribble == NULL
-       || SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->host_scribble == NULL ||
+       (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout))) {
       printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
-	     BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-      restore_flags(flags);
+             BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
    i = *(unsigned int *)SCarg->host_scribble;
    printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
-	  BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+          BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: abort, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == FREE) {
       printk("%s: abort, mbox %d is free.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1076,25 +1128,22 @@
       printk("%s: abort, mbox %d is in use.\n", BN(j), i);
 
       if (SCarg != HD(j)->cp[i].SCpnt)
-	 panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
-	       BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+         panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+               BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
       if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
          printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
 
-      restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
       }
 
    if (HD(j)->cp_stat[i] == IN_RESET) {
       printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == LOCKED) {
       printk("%s: abort, mbox %d is locked.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1103,47 +1152,130 @@
       SCarg->host_scribble = NULL;
       HD(j)->cp_stat[i] = FREE;
       printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
-	     BN(j), i, SCarg->pid);
+             BN(j), i, SCarg->pid);
       SCarg->scsi_done(SCarg);
-      restore_flags(flags);
       return SCSI_ABORT_SUCCESS;
       }
 
-   restore_flags(flags);
    panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned long flags;
+int u14_34f_old_abort(Scsi_Cmnd *SCarg) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_abort(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_abort(Scsi_Cmnd *SCarg) {
+   unsigned int i, j;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+
+   if (SCarg->host_scribble == NULL) {
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+             BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+      return SUCCESS;
+      }
+
+   i = *(unsigned int *)SCarg->host_scribble;
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+          BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (i >= sh[j]->can_queue)
+      panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: abort, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: abort, mbox %d is free.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_USE) {
+      printk("%s: abort, mbox %d is in use.\n", BN(j), i);
+
+      if (SCarg != HD(j)->cp[i].SCpnt)
+         panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+               BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+
+      if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
+         printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
+
+      if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         SCarg->host_scribble = NULL;
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
+                BN(j), i, SCarg->pid);
+         return SUCCESS;
+         }
+
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_RESET) {
+      printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == LOCKED) {
+      printk("%s: abort, mbox %d is locked.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      SCarg->result = DID_ABORT << 16;
+      SCarg->host_scribble = NULL;
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
+             BN(j), i, SCarg->pid);
+      SCarg->scsi_done(SCarg);
+      return SUCCESS;
+      }
+
+   panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
+}
+
+int u14_34f_abort(Scsi_Cmnd *SCarg) {
+
+   return do_abort(SCarg);
+}
+
+#endif /* new_eh_code */
+
+static inline int do_old_reset(Scsi_Cmnd *SCarg) {
    unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-   printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n", 
-	  BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
-          reset_flags);
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
 
-   if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout)) {
       printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
-      restore_flags(flags);
       return SCSI_RESET_NOT_RUNNING;
       }
 
    if (HD(j)->in_reset) {
       printk("%s: reset, exit, already in reset.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: reset, exit, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
@@ -1160,13 +1292,13 @@
       if (HD(j)->cp_stat[i] == FREE) continue;
 
       if (HD(j)->cp_stat[i] == LOCKED) {
-	 HD(j)->cp_stat[i] = FREE;
-	 printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
-	 continue;
-	 }
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+         continue;
+         }
 
       if (!(SCpnt = HD(j)->cp[i].SCpnt))
-	 panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
 
       if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
          HD(j)->cp_stat[i] = ABORTING;
@@ -1181,35 +1313,36 @@
          }
 
       if (SCpnt->host_scribble == NULL)
-	 panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
 
-      if (*(unsigned int *)SCpnt->host_scribble != i) 
-	 panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+      if (*(unsigned int *)SCpnt->host_scribble != i)
+         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
 
-      if (SCpnt->scsi_done == NULL) 
-	 panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+      if (SCpnt->scsi_done == NULL)
+         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
 
       if (SCpnt == SCarg) arg_done = TRUE;
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: reset, cannot reset, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
    printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
 
-#if defined (DEBUG_RESET)
+#if defined(DEBUG_RESET)
    do_trace = TRUE;
 #endif
 
    HD(j)->in_reset = TRUE;
-   sti();
+   SPIN_UNLOCK
+   IRQ_UNLOCK
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
-   cli();
+   IRQ_LOCK
+   SPIN_LOCK
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
    for (i = 0; i < sh[j]->can_queue; i++) {
@@ -1223,7 +1356,7 @@
          HD(j)->cp_stat[i] = LOCKED;
 
          printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
-	        BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->pid);
          }
 
       else if (HD(j)->cp_stat[i] == ABORTING) {
@@ -1235,7 +1368,7 @@
          HD(j)->cp_stat[i] = FREE;
 
          printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
-	        BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->pid);
          }
 
       else
@@ -1243,14 +1376,12 @@
          /* Any other mailbox has already been set free by interrupt */
          continue;
 
-      restore_flags(flags);
       SCpnt->scsi_done(SCpnt);
-      cli();
+      IRQ_LOCK
       }
 
    HD(j)->in_reset = FALSE;
    do_trace = FALSE;
-   restore_flags(flags);
 
    if (arg_done) {
       printk("%s: reset, exit, success.\n", BN(j));
@@ -1262,6 +1393,157 @@
       }
 }
 
+int u14_34f_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_reset(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_reset(Scsi_Cmnd *SCarg) {
+   unsigned int i, j, time, k, c, limit = 0;
+   int arg_done = FALSE;
+   Scsi_Cmnd *SCpnt;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (SCarg->host_scribble == NULL)
+      printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+
+   if (HD(j)->in_reset) {
+      printk("%s: reset, exit, already in reset.\n", BN(j));
+      return FAILED;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, exit, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   HD(j)->retries = 0;
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == FREE) continue;
+
+      if (HD(j)->cp_stat[i] == LOCKED) {
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+         continue;
+         }
+
+      if (!(SCpnt = HD(j)->cp[i].SCpnt))
+         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+      if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+         HD(j)->cp_stat[i] = ABORTING;
+         printk("%s: reset, mbox %d aborting, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else {
+         HD(j)->cp_stat[i] = IN_RESET;
+         printk("%s: reset, mbox %d in reset, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      if (SCpnt->host_scribble == NULL)
+         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+
+      if (*(unsigned int *)SCpnt->host_scribble != i)
+         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+
+      if (SCpnt->scsi_done == NULL)
+         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+
+      if (SCpnt == SCarg) arg_done = TRUE;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, cannot reset, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
+   printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
+
+#if defined(DEBUG_RESET)
+   do_trace = TRUE;
+#endif
+
+   HD(j)->in_reset = TRUE;
+   SPIN_UNLOCK
+   IRQ_UNLOCK
+   time = jiffies;
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
+   IRQ_LOCK
+   SPIN_LOCK
+   printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == IN_RESET) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox is still waiting for its interrupt */
+         HD(j)->cp_stat[i] = LOCKED;
+
+         printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else if (HD(j)->cp_stat[i] == ABORTING) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox was never queued to the adapter */
+         HD(j)->cp_stat[i] = FREE;
+
+         printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else
+
+         /* Any other mailbox has already been set free by interrupt */
+         continue;
+
+      SCpnt->scsi_done(SCpnt);
+      IRQ_LOCK
+      }
+
+   HD(j)->in_reset = FALSE;
+   do_trace = FALSE;
+
+   if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+   else          printk("%s: reset, exit.\n", BN(j));
+
+   return SUCCESS;
+}
+
+int u14_34f_reset(Scsi_Cmnd *SCarg) {
+
+   return do_reset(SCarg);
+}
+
+#endif /* new_eh_code */
+
 int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    unsigned int j = 0;
    int size = disk->capacity;
@@ -1280,7 +1562,7 @@
    for (i = 0; i < n - 1; i++) {
       k = i;
 
-      for (j = k + 1; j < n; j++) 
+      for (j = k + 1; j < n; j++)
          if (rev) {
             if (sk[j] > sk[k]) k = j;
             }
@@ -1297,7 +1579,7 @@
    return;
    }
 
-static inline void reorder(unsigned int j, unsigned long cursec,
+static inline int reorder(unsigned int j, unsigned long cursec,
                  unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
    Scsi_Cmnd *SCpnt;
    struct mscp *cpp;
@@ -1306,6 +1588,7 @@
    unsigned int input_only = TRUE, overlap = FALSE;
    unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
    unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+   unsigned long ioseek = 0;
 
    static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
    static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1316,10 +1599,10 @@
       printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
              " av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
              ovlcount, readycount, readysorted, sortcount, revcount,
-             seeknosort / (readycount + 1), 
+             seeknosort / (readycount + 1),
              seeksorted / (readycount + 1));
 
-   if (n_ready <= 1) return;
+   if (n_ready <= 1) return FALSE;
 
    for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
@@ -1330,12 +1613,13 @@
       if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
 
       sl[n] = SCpnt->request.sector;
+      ioseek += SCpnt->request.nr_sectors;
 
       if (!n) continue;
 
       if (sl[n] < sl[n - 1]) s = FALSE;
       if (sl[n] > sl[n - 1]) r = FALSE;
-   
+
       if (link_statistics) {
          if (sl[n] > sl[n - 1])
             seek += sl[n] - sl[n - 1];
@@ -1351,6 +1635,8 @@
 
    if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
 
+   if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
    if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
@@ -1358,7 +1644,7 @@
       ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
 
       if (!n) continue;
- 
+
       if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
           || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
       }
@@ -1367,15 +1653,15 @@
 
    if (link_statistics) {
       if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
-      batchcount++; readycount += n_ready, seeknosort += seek / 1024; 
+      batchcount++; readycount += n_ready, seeknosort += seek / 1024;
       if (input_only) inputcount++;
-      if (overlap) { ovlcount++; seeksorted += seek / 1024; }
+      if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
       else seeksorted += (iseek + maxsec - minsec) / 1024;
       if (rev && !r)     {  revcount++; readysorted += n_ready; }
       if (!rev && !s)    { sortcount++; readysorted += n_ready; }
       }
 
-#if defined (DEBUG_LINKED_COMMANDS)
+#if defined(DEBUG_LINKED_COMMANDS)
    if (link_statistics && (overlap || !(flushcount % link_statistics)))
       for (n = 0; n < n_ready; n++) {
          k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
@@ -1384,10 +1670,11 @@
                 (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
                 SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
                 SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
-                YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), 
+                YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
                 YESNO(overlap), cpp->xdir);
          }
 #endif
+   return overlap;
 }
 
 static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
@@ -1409,13 +1696,13 @@
       il[n_ready++] = k;
       }
 
-   reorder(j, cursec, ihdlr, il, n_ready);
-  
+   if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
+
    for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
 
       if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
-         printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
+         printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
                 " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
                 SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
          HD(j)->cp_stat[k] = ABORTING;
@@ -1426,251 +1713,247 @@
       outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
       HD(j)->cp_stat[k] = IN_USE;
       }
+
 }
 
-static void u14_34f_interrupt_handler(int irq, void *dev_id,
-                                      struct pt_regs *regs) {
+static inline void ihdlr(int irq, unsigned int j) {
    Scsi_Cmnd *SCpnt;
-   unsigned long flags;
-   unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, reg, ret;
-   struct mscp *spp;
-
-   save_flags(flags);
-   cli();
-
-   if (!irqlist[irq]) {
-      printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
-      restore_flags(flags);
+   unsigned int i, k, c, status, tstatus, reg, ret;
+   struct mscp *spp, *cpp;
+
+   if (sh[j]->irq != irq)
+       panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
+
+   /* Check if this board need to be serviced */
+   if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) return;
+
+   HD(j)->iocount++;
+
+   if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
+                        HD(j)->iocount);
+
+   /* Check if this board is still busy */
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+      printk("%s: ihdlr, busy timeout error,  irq %d, reg 0x%x, count %d.\n",
+             BN(j), irq, reg, HD(j)->iocount);
       return;
       }
 
-   if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n", 
-			driver_name, irq, calls[irq]);
+   spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
+   cpp = spp;
 
-   /* Service all the boards configured on this irq */
-   for (j = 0; sh[j] != NULL; j++) {
+   /* Clear interrupt pending flag */
+   outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
 
-      if (sh[j]->irq != irq) continue;
+#if defined(DEBUG_GENERATE_ABORTS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
+#endif
+
+   /* Find the mailbox to be serviced on this board */
+   i = cpp - HD(j)->cp;
 
-      loops = 0;
-
-      /* Loop until all interrupts for a board are serviced */
-      while ((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED) {
-	 total_loops++;
-	 loops++;
-
-	 if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
-			      BN(j), HD(j)->iocount);
-
-	 spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
-
-	 /* Clear interrupt pending flag */
-	 outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
-
-	 i = spp - HD(j)->cp;
-
-	 if (spp < HD(j)->cp || spp >= HD(j)->cp + sh[j]->can_queue
-                                            || i >= sh[j]->can_queue)
-	    panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n",
-                  BN(j), (void *)ret, HD(j)->cp);
-
-	 if (HD(j)->cp_stat[i] == IGNORE) {
-	    HD(j)->cp_stat[i] = FREE;
-	    continue;
-	    }
-	 else if (HD(j)->cp_stat[i] == LOCKED) {
-	    HD(j)->cp_stat[i] = FREE;
-	    printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
-		   BN(j), i, HD(j)->iocount);
-	    continue;
-	    }
-	 else if (HD(j)->cp_stat[i] == FREE) {
-	    printk("%s: ihdlr, mbox %d is free, count %d.\n", 
-		   BN(j), i, HD(j)->iocount);
-	    continue;
-	    }
-	 else if (HD(j)->cp_stat[i] == IN_RESET)
-	    printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
-	 else if (HD(j)->cp_stat[i] != IN_USE) 
-	    panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
-
-	 HD(j)->cp_stat[i] = FREE;
-	 SCpnt = spp->SCpnt;
-
-	 if (SCpnt == NULL) 
-	    panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
-	 if (SCpnt->host_scribble == NULL) 
-	    panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
-		  BN(j), i, SCpnt->pid, SCpnt);
-
-	 if (*(unsigned int *)SCpnt->host_scribble != i) 
-	    panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
-		  " irq %d.\n", BN(j), i, SCpnt->pid, 
-		  *(unsigned int *)SCpnt->host_scribble, irq);
-
-         if (linked_comm && SCpnt->device->queue_depth > 2
-                                           && TLDEV(SCpnt->device->type))
-            flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
-
-	 tstatus = status_byte(spp->target_status);
-
-	 switch (spp->adapter_status) {
-	    case ASOK:     /* status OK */
-
-	       /* Forces a reset if a disk drive keeps returning BUSY */
-	       if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
-		  status = DID_ERROR << 16;
-
-	       /* If there was a bus reset, redo operation on each target */
-	       else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
-		        && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
-		  status = DID_BUS_BUSY << 16;
-
-	       /* Works around a flaw in scsi.c */
-	       else if (tstatus == CHECK_CONDITION
-			&& SCpnt->device->type == TYPE_DISK
-			&& (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
-		  status = DID_BUS_BUSY << 16;
-
-	       else
-		  status = DID_OK << 16;
-
-	       if (tstatus == GOOD)
-		  HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
-
-	       if (spp->target_status && SCpnt->device->type == TYPE_DISK)
-		  printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
-                         "target_status 0x%x, sense key 0x%x.\n", BN(j), 
-			 SCpnt->channel, SCpnt->target, SCpnt->lun,
-                         SCpnt->pid, spp->target_status,
-                         SCpnt->sense_buffer[2]);
-
-	       HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
-
-               if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
-
-	       break;
-	    case ASST:     /* Selection Time Out */
-
-	       if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
-		  status = DID_ERROR << 16;
-	       else {
-		  status = DID_TIME_OUT << 16;
-		  HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
-		  }
-
-	       break;
-
-            /* Perform a limited number of internal retries */
-	    case 0x93:     /* Unexpected bus free */
-	    case 0x94:     /* Target bus phase sequence failure */
-	    case 0x96:     /* Illegal SCSI command */
-	    case 0xa3:     /* SCSI bus reset error */
-
-	       for (c = 0; c <= sh[j]->max_channel; c++) 
-	          for (k = 0; k < sh[j]->max_id; k++) 
-	             HD(j)->target_redo[k][c] = TRUE;
-   
-
-	    case 0x92:     /* Data over/under-run */
-
-	       if (SCpnt->device->type != TYPE_TAPE
-                   && HD(j)->retries < MAX_INTERNAL_RETRIES) {
-		  status = DID_BUS_BUSY << 16;
-		  HD(j)->retries++;
-                  HD(j)->last_retried_pid = SCpnt->pid;
-                  }
-	       else 
-		  status = DID_ERROR << 16;
-
-	       break;
-	    case 0x01:     /* Invalid command */
-	    case 0x02:     /* Invalid parameters */
-	    case 0x03:     /* Invalid data list */
-	    case 0x84:     /* SCSI bus abort error */
-	    case 0x9b:     /* Auto request sense error */
-	    case 0x9f:     /* Unexpected command complete message error */
-	    case 0xff:     /* Invalid parameter in the S/G list */
-	    default:
-	       status = DID_ERROR << 16;
-	       break;
-	    }
+   if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
+                                     || i >= sh[j]->can_queue)
+      panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
+            (void *)ret, HD(j)->cp);
+
+   if (HD(j)->cp_stat[i] == IGNORE) {
+      HD(j)->cp_stat[i] = FREE;
+      return;
+      }
+   else if (HD(j)->cp_stat[i] == LOCKED) {
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
+             HD(j)->iocount);
+      return;
+      }
+   else if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
+             HD(j)->iocount);
+      return;
+      }
+   else if (HD(j)->cp_stat[i] == IN_RESET)
+      printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+   else if (HD(j)->cp_stat[i] != IN_USE)
+      panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
+            BN(j), i, HD(j)->cp_stat[i]);
+
+   HD(j)->cp_stat[i] = FREE;
+   SCpnt = cpp->SCpnt;
+
+   if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+   if (SCpnt->host_scribble == NULL)
+      panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
+            SCpnt->pid, SCpnt);
+
+   if (*(unsigned int *)SCpnt->host_scribble != i)
+      panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
+            BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
 
-	 SCpnt->result = status | spp->target_status;
-	 HD(j)->iocount++;
+   if (linked_comm && SCpnt->device->queue_depth > 2
+                                     && TLDEV(SCpnt->device->type))
+      flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
 
-	 if (loops > 1) HD(j)->multicount++;
+   tstatus = status_byte(spp->target_status);
 
-#if defined (DEBUG_INTERRUPT)
-	 if (SCpnt->result || do_trace) 
-#else
-	 if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
-	     (spp->adapter_status != ASOK && 
-	      spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
-              do_trace || msg_byte(spp->target_status))
+#if defined(DEBUG_GENERATE_ERRORS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2))
+                                           spp->adapter_status = 0x01;
 #endif
-	    printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
-		   " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
-		   BN(j), i, spp->adapter_status, spp->target_status,
-		   SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
-                   reg, HD(j)->iocount);
 
-	 /* Set the command state to inactive */
-	 SCpnt->host_scribble = NULL;
+   switch (spp->adapter_status) {
+      case ASOK:     /* status OK */
+
+         /* Forces a reset if a disk drive keeps returning BUSY */
+         if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
+            status = DID_ERROR << 16;
+
+         /* If there was a bus reset, redo operation on each target */
+         else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+                  && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
+            status = DID_BUS_BUSY << 16;
+
+         /* Works around a flaw in scsi.c */
+         else if (tstatus == CHECK_CONDITION
+                  && SCpnt->device->type == TYPE_DISK
+                  && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+            status = DID_BUS_BUSY << 16;
+
+         else
+            status = DID_OK << 16;
+
+         if (tstatus == GOOD)
+            HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
+
+         if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+            printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
+                   "target_status 0x%x, sense key 0x%x.\n", BN(j),
+                   SCpnt->channel, SCpnt->target, SCpnt->lun,
+                   SCpnt->pid, spp->target_status,
+                   SCpnt->sense_buffer[2]);
+
+         HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
+
+         if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
+
+         break;
+      case ASST:     /* Selection Time Out */
+
+         if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
+            status = DID_ERROR << 16;
+         else {
+            status = DID_TIME_OUT << 16;
+            HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
+            }
+
+         break;
 
-	 restore_flags(flags);
-	 SCpnt->scsi_done(SCpnt);
-	 cli();
+      /* Perform a limited number of internal retries */
+      case 0x93:     /* Unexpected bus free */
+      case 0x94:     /* Target bus phase sequence failure */
+      case 0x96:     /* Illegal SCSI command */
+      case 0xa3:     /* SCSI bus reset error */
 
-	 }   /* Multiple command loop */
+         for (c = 0; c <= sh[j]->max_channel; c++)
+            for (k = 0; k < sh[j]->max_id; k++)
+               HD(j)->target_redo[k][c] = TRUE;
 
-      }   /* Boards loop */
 
-   calls[irq]++;
+      case 0x92:     /* Data over/under-run */
 
-#if defined (DEBUG_SMP)
-   if (total_loops == 0) 
-     printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
-	    driver_name, irq, calls[irq]);
+         if (SCpnt->device->type != TYPE_TAPE
+             && HD(j)->retries < MAX_INTERNAL_RETRIES) {
+
+#if defined(DID_SOFT_ERROR)
+            status = DID_SOFT_ERROR << 16;
+#else
+            status = DID_BUS_BUSY << 16;
 #endif
 
-   if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
-			driver_name, irq, calls[irq]);
+            HD(j)->retries++;
+            HD(j)->last_retried_pid = SCpnt->pid;
+            }
+         else
+            status = DID_ERROR << 16;
+
+         break;
+      case 0x01:     /* Invalid command */
+      case 0x02:     /* Invalid parameters */
+      case 0x03:     /* Invalid data list */
+      case 0x84:     /* SCSI bus abort error */
+      case 0x9b:     /* Auto request sense error */
+      case 0x9f:     /* Unexpected command complete message error */
+      case 0xff:     /* Invalid parameter in the S/G list */
+      default:
+         status = DID_ERROR << 16;
+         break;
+      }
+
+   SCpnt->result = status | spp->target_status;
 
-#if defined (DEBUG_STATISTICS)
-   if ((calls[irq] % 100000) == 10000)
-      for (j = 0; sh[j] != NULL; j++)
-	 printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
-		calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
+#if defined(DEBUG_INTERRUPT)
+   if (SCpnt->result || do_trace)
+#else
+   if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
+       (spp->adapter_status != ASOK &&
+        spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+        do_trace || msg_byte(spp->target_status))
 #endif
+      printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
+             " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
+             BN(j), i, spp->adapter_status, spp->target_status,
+             SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
+             reg, HD(j)->iocount);
+
+   /* Set the command state to inactive */
+   SCpnt->host_scribble = NULL;
+
+   SCpnt->scsi_done(SCpnt);
+
+   if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
+                        HD(j)->iocount);
 
-   restore_flags(flags);
    return;
 }
 
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+   unsigned int j;
+   IRQ_FLAGS
+   SPIN_FLAGS
+
+   /* Check if the interrupt must be processed by this handler */
+   if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
+
+   SPIN_LOCK_SAVE
+   IRQ_LOCK_SAVE
+   ihdlr(irq, j);
+   IRQ_UNLOCK_RESTORE
+   SPIN_UNLOCK_RESTORE
+}
+
 int u14_34f_release(struct Scsi_Host *shpnt) {
-   unsigned long flags;
    unsigned int i, j;
+   IRQ_FLAGS
 
-   save_flags(flags);
-   cli();
+   IRQ_LOCK_SAVE
 
    for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
-    
+
    if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
                             driver_name);
 
-   for (i = 0; i < sh[j]->can_queue; i++) 
+   for (i = 0; i < sh[j]->can_queue; i++)
       if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
 
-   if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+   free_irq(sh[j]->irq, &sha[j]);
 
    if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
 
    release_region(sh[j]->io_port, sh[j]->n_io_port);
    scsi_unregister(sh[j]);
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return FALSE;
 }
 
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.0.33/linux/drivers/scsi/u14-34f.h	Mon Sep 15 09:41:28 1997
+++ linux/drivers/scsi/u14-34f.h	Wed Jun  3 15:17:49 1998
@@ -4,36 +4,56 @@
 #ifndef _U14_34F_H
 #define _U14_34F_H
 
+#include <linux/version.h>
+
 int u14_34f_detect(Scsi_Host_Template *);
 int u14_34f_release(struct Scsi_Host *);
 int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int u14_34f_abort(Scsi_Cmnd *);
-int u14_34f_reset(Scsi_Cmnd *, unsigned int);
+int u14_34f_old_abort(Scsi_Cmnd *);
+int u14_34f_reset(Scsi_Cmnd *);
+int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "3.11.00"
+#define U14_34F_VERSION "4.31.00"
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+#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_old_abort,                  \
+                reset:                   u14_34f_old_reset,                  \
+                eh_abort_handler:        u14_34f_abort,                      \
+                eh_device_reset_handler: NULL,                               \
+                eh_bus_reset_handler:    NULL,                               \
+                eh_host_reset_handler:   u14_34f_reset,                      \
+                bios_param:              u14_34f_biosparam,                  \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING,                  \
+                use_new_eh_code:         1    /* Enable new error code */    \
+                }
+
+#else /* Use old scsi code */
+
+#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_old_abort,                  \
+                reset:                   u14_34f_old_reset,                  \
+                bios_param:              u14_34f_biosparam,                  \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING                   \
+                }
+
+#endif
 
-#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                                     \
-		}
 #endif
diff -u --recursive --new-file v2.0.33/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.0.33/linux/drivers/scsi/wd7000.c	Mon Aug 11 13:37:24 1997
+++ linux/drivers/scsi/wd7000.c	Wed Jun  3 15:17:49 1998
@@ -131,6 +131,11 @@
  *
  *  Added support for /proc file system (/proc/scsi/wd7000/[0...] files).
  *  Now, driver can handle hard disks with capacity >1GB.
+ *
+ *  01/15/1998
+ *
+ *  Added support for BUS_ON and BUS_OFF parameters in config line.
+ *  Miscellaneous cleanup.
  */
 
 #ifdef MODULE
@@ -156,11 +161,10 @@
 #include <scsi/scsicam.h>
 
 #define ANY2SCSI_INLINE		/* undef this to use old macros */
-#undef BIOSPARAM_DEBUG
-#undef DEBUG                    /* general debug */
+#undef WD7000_DEBUG		/* general debug                */
 
 #include "wd7000.h"
-#include<linux/stat.h>
+#include <linux/stat.h>
 
 
 struct proc_dir_entry proc_scsi_wd7000 =
@@ -195,36 +199,63 @@
  *  WD7000-specific mailbox structure
  *
  */
-typedef volatile struct mailbox{
-  unchar status;
-  unchar scbptr[3];		/* SCSI-style - MSB first (big endian) */
+typedef volatile struct mailbox {
+    unchar status;
+    unchar scbptr[3];		/* SCSI-style - MSB first (big endian) */
 } Mailbox;
 
 /*
  *  This structure should contain all per-adapter global data.  I.e., any
  *  new global per-adapter data should put in here.
- *
  */
 typedef struct adapter {
-  struct Scsi_Host *sh;		/* Pointer to Scsi_Host structure */
-  int iobase;			/* This adapter's I/O base address */
-  int irq;			/* This adapter's IRQ level */
-  int dma;			/* This adapter's DMA channel */
-  struct {			/* This adapter's mailboxes */
-    Mailbox ogmb[OGMB_CNT];	/* Outgoing mailboxes */
-    Mailbox icmb[ICMB_CNT];	/* Incoming mailboxes */
-  } mb;
-  int next_ogmb;		/* to reduce contention at mailboxes */
-  unchar control;		/* shadows CONTROL port value */
-  unchar rev1, rev2;		/* filled in by wd7000_revision */
+    struct Scsi_Host *sh;	/* Pointer to Scsi_Host structure    */
+    int iobase;			/* This adapter's I/O base address   */
+    int irq;			/* This adapter's IRQ level          */
+    int dma;			/* This adapter's DMA channel        */
+    int int_counter;		/* This adapter's interrupt counter  */
+    int bus_on;			/* This adapter's BUS_ON time        */
+    int bus_off;		/* This adapter's BUS_OFF time       */
+    struct {			/* This adapter's mailboxes          */
+	Mailbox ogmb[OGMB_CNT];	/* Outgoing mailboxes                */
+	Mailbox icmb[ICMB_CNT];	/* Incoming mailboxes                */
+    } mb;
+    int next_ogmb;		/* to reduce contention at mailboxes */
+    unchar control;		/* shadows CONTROL port value        */
+    unchar rev1, rev2;		/* filled in by wd7000_revision      */
 } Adapter;
 
 /*
+ * (linear) base address for ROM BIOS
+ */
+static const long wd7000_biosaddr[] =
+{
+    0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
+    0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
+};
+#define NUM_ADDRS (sizeof(wd7000_biosaddr)/sizeof(long))
+
+static const unsigned short wd7000_iobase[] =
+{
+    0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
+    0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
+    0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
+    0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
+};
+#define NUM_IOPORTS (sizeof(wd7000_iobase)/sizeof(unsigned short))
+
+static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
+#define NUM_IRQS (sizeof(wd7000_irq)/sizeof(short))
+
+static const short wd7000_dma[] = { 5, 6, 7 };
+#define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short))
+
+/*
  * possible irq range
  */
 #define IRQ_MIN   3
 #define IRQ_MAX   15
-#define IRQS      (IRQ_MAX-IRQ_MIN + 1)
+#define IRQS      (IRQ_MAX - IRQ_MIN + 1)
 
 /*
  * The following is set up by wd7000_detect, and used thereafter by
@@ -234,46 +265,32 @@
  */
 static struct Scsi_Host *wd7000_host[IRQS];
 
-/*
- * (linear) base address for ROM BIOS
- */
-static const long wd7000_biosaddr[] = {
-  0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
-  0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
-};
-#define NUM_ADDRS (sizeof(wd7000_biosaddr)/sizeof(long))
-
-static const unsigned short wd7000_iobase[] = {
-  0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
-  0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
-  0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
-  0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
-};
-#define NUM_IOPORTS (sizeof(wd7000_iobase)/sizeof(unsigned short))
-
-static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
-#define NUM_IRQS (sizeof(wd7000_irq)/sizeof(short))
+#define BUS_ON    64	/* x 125ns = 8000ns (BIOS default) */
+#define BUS_OFF   15	/* x 125ns = 1875ns (BIOS default) */
 
-static const short wd7000_dma[] = { 5, 6, 7 };
-#define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short))
-  
 /*
  *  Standard Adapter Configurations - used by wd7000_detect
  */
 typedef struct {
-  int      irq;			/* IRQ level        */
-  int      dma;			/* DMA channel      */
-  unsigned iobase;		/* I/O base address */
+    short irq;		/* IRQ level                                  */
+    short dma;		/* DMA channel                                */
+    unsigned iobase;	/* I/O base address                           */
+    short bus_on;	/* Time that WD7000 spends on the AT-bus when */
+			/* transferring data. BIOS default is 8000ns. */
+    short bus_off;	/* Time that WD7000 spends OFF THE BUS after  */
+			/* while it is transferring data.             */
+			/* BIOS default is 1875ns                     */
 } Config;
 
 /*
  * Add here your configuration...
  */
-static const Config configs[] = {
-  { 15,  6, 0x350 },		/* defaults for single adapter */
-  { 11,  5, 0x320 },		/* defaults for second adapter */
-  {  7,  6, 0x350 },		/* My configuration (Zaga)     */
-  { -1, -1, 0x0   }		/* Empty slot                  */
+static Config configs[] =
+{
+    { 15,  6, 0x350, BUS_ON, BUS_OFF },	/* defaults for single adapter */
+    { 11,  5, 0x320, BUS_ON, BUS_OFF },	/* defaults for second adapter */
+    {  7,  6, 0x350, BUS_ON, BUS_OFF },	/* My configuration (Zaga)     */
+    { -1, -1, 0x0,   BUS_ON, BUS_OFF }	/* Empty slot                  */
 };
 #define NUM_CONFIGS (sizeof(configs)/sizeof(Config))
 
@@ -283,13 +300,14 @@
  *  added for the Future Domain version.
  */
 typedef struct signature {
-    const void *sig;		/* String to look for */
-    unsigned    ofs;		/* offset from BIOS base address */
-    unsigned    len;		/* length of string */
+    const void *sig;		/* String to look for            */
+    unsigned ofs;		/* offset from BIOS base address */
+    unsigned len;		/* length of string              */
 } Signature;
 
-static const Signature signatures[] = {
-  { "SSTBIOS", 0x0000d, 7 }	/* "SSTBIOS" @ offset 0x0000d */
+static const Signature signatures[] =
+{
+    {"SSTBIOS", 0x0000d, 7}	/* "SSTBIOS" @ offset 0x0000d */
 };
 #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
 
@@ -298,22 +316,23 @@
  *  I/O Port Offsets and Bit Definitions
  *  4 addresses are used.  Those not defined here are reserved.
  */
-#define ASC_STAT        0	/* Status,  Read */
-#define ASC_COMMAND     0	/* Command, Write */
+#define ASC_STAT        0	/* Status,  Read          */
+#define ASC_COMMAND     0	/* Command, Write         */
 #define ASC_INTR_STAT   1	/* Interrupt Status, Read */
-#define ASC_INTR_ACK    1	/* Acknowledge, Write */
-#define ASC_CONTROL     2	/* Control, Write */
+#define ASC_INTR_ACK    1	/* Acknowledge, Write     */
+#define ASC_CONTROL     2	/* Control, Write         */
 
 /*
  * ASC Status Port
  */
-#define INT_IM		0x80	/* Interrupt Image Flag */
-#define CMD_RDY		0x40	/* Command Port Ready */
-#define CMD_REJ		0x20	/* Command Port Byte Rejected */
-#define ASC_INIT        0x10	/* ASC Initialized Flag */
+#define INT_IM		0x80	/* Interrupt Image Flag           */
+#define CMD_RDY		0x40	/* Command Port Ready             */
+#define CMD_REJ		0x20	/* Command Port Byte Rejected     */
+#define ASC_INIT        0x10	/* ASC Initialized Flag           */
 #define ASC_STATMASK    0xf0	/* The lower 4 Bytes are reserved */
 
-/* COMMAND opcodes
+/*
+ * COMMAND opcodes
  *
  *  Unfortunately, I have no idea how to properly use some of these commands,
  *  as the OEM manual does not make it clear.  I have not been able to use
@@ -321,39 +340,38 @@
  *  discernible effect whatsoever.  I think they may be related to certain
  *  ICB commands, but again, the OEM manual doesn't make that clear.
  */
-#define NO_OP             0	/* NO-OP toggles CMD_RDY bit in ASC_STAT */
-#define INITIALIZATION    1	/* initialization (10 bytes) */
-#define DISABLE_UNS_INTR  2	/* disable unsolicited interrupts */
-#define ENABLE_UNS_INTR   3	/* enable unsolicited interrupts */
-#define INTR_ON_FREE_OGMB 4	/* interrupt on free OGMB */
-#define SOFT_RESET        5	/* SCSI bus soft reset */
-#define HARD_RESET_ACK    6	/* SCSI bus hard reset acknowledge */
-#define START_OGMB        0x80	/* start command in OGMB (n) */
+#define NO_OP             0	/* NO-OP toggles CMD_RDY bit in ASC_STAT  */
+#define INITIALIZATION    1	/* initialization (10 bytes)              */
+#define DISABLE_UNS_INTR  2	/* disable unsolicited interrupts         */
+#define ENABLE_UNS_INTR   3	/* enable unsolicited interrupts          */
+#define INTR_ON_FREE_OGMB 4	/* interrupt on free OGMB                 */
+#define SOFT_RESET        5	/* SCSI bus soft reset                    */
+#define HARD_RESET_ACK    6	/* SCSI bus hard reset acknowledge        */
+#define START_OGMB        0x80	/* start command in OGMB (n)              */
 #define SCAN_OGMBS        0xc0	/* start multiple commands, signature (n) */
-				/*    where (n) = lower 6 bits */
-/* For INITIALIZATION:
+				/*    where (n) = lower 6 bits            */
+/*
+ * For INITIALIZATION:
  */
 typedef struct initCmd {
-  unchar op;			/* command opcode (= 1) */
-  unchar ID;			/* Adapter's SCSI ID */
-  unchar bus_on;		/* Bus on time, x 125ns (see below) */
-  unchar bus_off;		/* Bus off time, ""         ""      */
-  unchar rsvd;			/* Reserved */
-  unchar mailboxes[3];		/* Address of Mailboxes, MSB first  */
-  unchar ogmbs;			/* Number of outgoing MBs, max 64, 0,1 = 1 */
-  unchar icmbs;			/* Number of incoming MBs,   ""       ""   */
+    unchar op;			/* command opcode (= 1)                    */
+    unchar ID;			/* Adapter's SCSI ID                       */
+    unchar bus_on;		/* Bus on time, x 125ns (see below)        */
+    unchar bus_off;		/* Bus off time, ""         ""             */
+    unchar rsvd;		/* Reserved                                */
+    unchar mailboxes[3];	/* Address of Mailboxes, MSB first         */
+    unchar ogmbs;		/* Number of outgoing MBs, max 64, 0,1 = 1 */
+    unchar icmbs;		/* Number of incoming MBs,   ""       ""   */
 } InitCmd;
 
-#define BUS_ON            64	/* x 125ns = 8000ns (BIOS default) */
-#define BUS_OFF           15	/* x 125ns = 1875ns (BIOS default) */
- 
-/* Interrupt Status Port - also returns diagnostic codes at ASC reset
+/*
+ * Interrupt Status Port - also returns diagnostic codes at ASC reset
  *
  * if msb is zero, the lower bits are diagnostic status
  * Diagnostics:
- * 01	No diagnostic error occurred
- * 02	RAM failure
- * 03	FIFO R/W failed
+ * 01   No diagnostic error occurred
+ * 02   RAM failure
+ * 03   FIFO R/W failed
  * 04   SBIC register read/write failed
  * 05   Initialization D-FF failed
  * 06   Host IRQ D-FF failed
@@ -362,19 +380,20 @@
  * 10NNNNNN   outgoing mailbox NNNNNN is free
  * 11NNNNNN   incoming mailbox NNNNNN needs service
  */
-#define MB_INTR	 0xC0		/* Mailbox Service possible/required */
-#define IMB_INTR 0x40		/* 1 Incoming / 0 Outgoing */
-#define MB_MASK  0x3f           /* mask for mailbox number */
+#define MB_INTR    0xC0		/* Mailbox Service possible/required */
+#define IMB_INTR   0x40		/* 1 Incoming / 0 Outgoing           */
+#define MB_MASK    0x3f		/* mask for mailbox number           */
 
-/* CONTROL port bits
+/*
+ * CONTROL port bits
  */
-#define INT_EN		0x08	/* Interrupt Enable	*/
-#define DMA_EN		0x04	/* DMA Enable		*/
-#define SCSI_RES	0x02	/* SCSI Reset		*/
-#define ASC_RES		0x01	/* ASC Reset		*/
+#define INT_EN     0x08		/* Interrupt Enable */
+#define DMA_EN     0x04		/* DMA Enable       */
+#define SCSI_RES   0x02		/* SCSI Reset       */
+#define ASC_RES    0x01		/* ASC Reset        */
 
 /*
- *   Driver data structures:
+ * Driver data structures:
  *   - mb and scbs are required for interfacing with the host adapter.
  *     An SCB has extra fields not visible to the adapter; mb's
  *     _cannot_ do this, since the adapter assumes they are contiguous in
@@ -403,28 +422,28 @@
  */
 typedef struct sgb {
     unchar len[3];
-    unchar ptr[3];              /* Also SCSI-style - MSB first */
+    unchar ptr[3];		/* Also SCSI-style - MSB first */
 } Sgb;
 
-typedef struct scb {		/* Command Control Block 5.4.1 */
-  unchar op;			/* Command Control Block Operation Code */
-  unchar idlun;			/* op=0,2:Target Id, op=1:Initiator Id */
-				/* Outbound data transfer, length is checked*/
-				/* Inbound data transfer, length is checked */
-				/* Logical Unit Number */
-  unchar cdb[12];		/* SCSI Command Block */
-  volatile unchar status;       /* SCSI Return Status */
-  volatile unchar vue;		/* Vendor Unique Error Code */
-  unchar maxlen[3];		/* Maximum Data Transfer Length */
-  unchar dataptr[3];		/* SCSI Data Block Pointer */
-  unchar linkptr[3];		/* Next Command Link Pointer */
-  unchar direc;			/* Transfer Direction */
-  unchar reserved2[6];		/* SCSI Command Descriptor Block */
-				/* end of hardware SCB */
-  Scsi_Cmnd *SCpnt;             /* Scsi_Cmnd using this SCB */
-  Sgb sgb[WD7000_SG];           /* Scatter/gather list for this SCB */
-  Adapter *host;                /* host adapter */
-  struct scb *next;             /* for lists of scbs */
+typedef struct scb {		/* Command Control Block 5.4.1               */
+    unchar op;			/* Command Control Block Operation Code      */
+    unchar idlun;		/* op=0,2:Target Id, op=1:Initiator Id       */
+				/* Outbound data transfer, length is checked */
+				/* Inbound data transfer, length is checked  */
+				/* Logical Unit Number                       */
+    unchar cdb[12];		/* SCSI Command Block                        */
+    volatile unchar status;	/* SCSI Return Status                        */
+    volatile unchar vue;	/* Vendor Unique Error Code                  */
+    unchar maxlen[3];		/* Maximum Data Transfer Length              */
+    unchar dataptr[3];		/* SCSI Data Block Pointer                   */
+    unchar linkptr[3];		/* Next Command Link Pointer                 */
+    unchar direc;		/* Transfer Direction                        */
+    unchar reserved2[6];	/* SCSI Command Descriptor Block             */
+				/* end of hardware SCB                       */
+    Scsi_Cmnd *SCpnt;		/* Scsi_Cmnd using this SCB                  */
+    Sgb sgb[WD7000_SG];		/* Scatter/gather list for this SCB          */
+    Adapter *host;		/* host adapter                              */
+    struct scb *next;		/* for lists of scbs                         */
 } Scb;
 
 /*
@@ -438,110 +457,110 @@
  *  (notably, get/set unsolicited interrupt status) in my copy of the OEM
  *  manual, and others are ambiguous/hard to follow.
  */
-#define ICB_OP_MASK             0x80  /* distinguishes scbs from icbs */
-#define ICB_OP_OPEN_RBUF        0x80  /* open receive buffer */
-#define ICB_OP_RECV_CMD         0x81  /* receive command from initiator */
-#define ICB_OP_RECV_DATA        0x82  /* receive data from initiator */
-#define ICB_OP_RECV_SDATA       0x83  /* receive data with status from init. */
-#define ICB_OP_SEND_DATA        0x84  /* send data with status to initiator */
-#define ICB_OP_SEND_STAT        0x86  /* send command status to initiator */
-			     /* 0x87 is reserved */
-#define ICB_OP_READ_INIT        0x88  /* read initialization bytes */
-#define ICB_OP_READ_ID          0x89  /* read adapter's SCSI ID */
-#define ICB_OP_SET_UMASK        0x8A  /* set unsolicited interrupt mask */
-#define ICB_OP_GET_UMASK        0x8B  /* read unsolicited interrupt mask */
-#define ICB_OP_GET_REVISION     0x8C  /* read firmware revision level */
-#define ICB_OP_DIAGNOSTICS      0x8D  /* execute diagnostics */
-#define ICB_OP_SET_EPARMS       0x8E  /* set execution parameters */
-#define ICB_OP_GET_EPARMS       0x8F  /* read execution parameters */
+#define ICB_OP_MASK           0x80	/* distinguishes scbs from icbs        */
+#define ICB_OP_OPEN_RBUF      0x80	/* open receive buffer                 */
+#define ICB_OP_RECV_CMD       0x81	/* receive command from initiator      */
+#define ICB_OP_RECV_DATA      0x82	/* receive data from initiator         */
+#define ICB_OP_RECV_SDATA     0x83	/* receive data with status from init. */
+#define ICB_OP_SEND_DATA      0x84	/* send data with status to initiator  */
+#define ICB_OP_SEND_STAT      0x86	/* send command status to initiator    */
+					/* 0x87 is reserved                    */
+#define ICB_OP_READ_INIT      0x88	/* read initialization bytes           */
+#define ICB_OP_READ_ID        0x89	/* read adapter's SCSI ID              */
+#define ICB_OP_SET_UMASK      0x8A	/* set unsolicited interrupt mask      */
+#define ICB_OP_GET_UMASK      0x8B	/* read unsolicited interrupt mask     */
+#define ICB_OP_GET_REVISION   0x8C	/* read firmware revision level        */
+#define ICB_OP_DIAGNOSTICS    0x8D	/* execute diagnostics                 */
+#define ICB_OP_SET_EPARMS     0x8E	/* set execution parameters            */
+#define ICB_OP_GET_EPARMS     0x8F	/* read execution parameters           */
 
 typedef struct icbRecvCmd {
-  unchar op;
-  unchar IDlun;                 /* Initiator SCSI ID/lun */
-  unchar len[3];                /* command buffer length */
-  unchar ptr[3];                /* command buffer address */
-  unchar rsvd[7];               /* reserved */
-  volatile unchar vue;          /* vendor-unique error code */
-  volatile unchar status;       /* returned (icmb) status */
-  volatile unchar phase;        /* used by interrupt handler */
+    unchar op;
+    unchar IDlun;		/* Initiator SCSI ID/lun     */
+    unchar len[3];		/* command buffer length     */
+    unchar ptr[3];		/* command buffer address    */
+    unchar rsvd[7];		/* reserved                  */
+    volatile unchar vue;	/* vendor-unique error code  */
+    volatile unchar status;	/* returned (icmb) status    */
+    volatile unchar phase;	/* used by interrupt handler */
 } IcbRecvCmd;
 
 typedef struct icbSendStat {
-  unchar op;
-  unchar IDlun;                 /* Target SCSI ID/lun */
-  unchar stat;                  /* (outgoing) completion status byte 1 */
-  unchar rsvd[12];              /* reserved */
-  volatile unchar vue;          /* vendor-unique error code */
-  volatile unchar status;       /* returned (icmb) status */
-  volatile unchar phase;        /* used by interrupt handler */
+    unchar op;
+    unchar IDlun;		/* Target SCSI ID/lun                  */
+    unchar stat;		/* (outgoing) completion status byte 1 */
+    unchar rsvd[12];		/* reserved                            */
+    volatile unchar vue;	/* vendor-unique error code            */
+    volatile unchar status;	/* returned (icmb) status              */
+    volatile unchar phase;	/* used by interrupt handler           */
 } IcbSendStat;
 
 typedef struct icbRevLvl {
-  unchar op;
-  volatile unchar primary;      /* primary revision level (returned) */
-  volatile unchar secondary;    /* secondary revision level (returned) */
-  unchar rsvd[12];              /* reserved */
-  volatile unchar vue;          /* vendor-unique error code */
-  volatile unchar status;       /* returned (icmb) status */
-  volatile unchar phase;        /* used by interrupt handler */
+    unchar op;
+    volatile unchar primary;	/* primary revision level (returned)   */
+    volatile unchar secondary;	/* secondary revision level (returned) */
+    unchar rsvd[12];		/* reserved                            */
+    volatile unchar vue;	/* vendor-unique error code            */
+    volatile unchar status;	/* returned (icmb) status              */
+    volatile unchar phase;	/* used by interrupt handler           */
 } IcbRevLvl;
 
-typedef struct icbUnsMask {     /* I'm totally guessing here */
-  unchar op;
-  volatile unchar mask[14];     /* mask bits */
+typedef struct icbUnsMask {	/* I'm totally guessing here */
+    unchar op;
+    volatile unchar mask[14];	/* mask bits                 */
 #ifdef 0
-  unchar rsvd[12];              /* reserved */
+    unchar rsvd[12];		/* reserved                  */
 #endif
-  volatile unchar vue;          /* vendor-unique error code */
-  volatile unchar status;       /* returned (icmb) status */
-  volatile unchar phase;        /* used by interrupt handler */
+    volatile unchar vue;	/* vendor-unique error code  */
+    volatile unchar status;	/* returned (icmb) status    */
+    volatile unchar phase;	/* used by interrupt handler */
 } IcbUnsMask;
 
 typedef struct icbDiag {
-  unchar op;
-  unchar type;                  /* diagnostics type code (0-3) */
-  unchar len[3];                /* buffer length */
-  unchar ptr[3];                /* buffer address */
-  unchar rsvd[7];               /* reserved */
-  volatile unchar vue;          /* vendor-unique error code */
-  volatile unchar status;       /* returned (icmb) status */
-  volatile unchar phase;        /* used by interrupt handler */
+    unchar op;
+    unchar type;		/* diagnostics type code (0-3) */
+    unchar len[3];		/* buffer length               */
+    unchar ptr[3];		/* buffer address              */
+    unchar rsvd[7];		/* reserved                    */
+    volatile unchar vue;	/* vendor-unique error code    */
+    volatile unchar status;	/* returned (icmb) status      */
+    volatile unchar phase;	/* used by interrupt handler   */
 } IcbDiag;
 
-#define ICB_DIAG_POWERUP        0     /* Power-up diags only */
-#define ICB_DIAG_WALKING        1     /* walking 1's pattern */
-#define ICB_DIAG_DMA            2     /* DMA - system memory diags */
-#define ICB_DIAG_FULL           3     /* do both 1 & 2 */
+#define ICB_DIAG_POWERUP   0	/* Power-up diags only       */
+#define ICB_DIAG_WALKING   1	/* walking 1's pattern       */
+#define ICB_DIAG_DMA       2	/* DMA - system memory diags */
+#define ICB_DIAG_FULL      3	/* do both 1 & 2             */
 
 typedef struct icbParms {
-  unchar op;
-  unchar rsvd1;                 /* reserved */
-  unchar len[3];                /* parms buffer length */
-  unchar ptr[3];                /* parms buffer address */
-  unchar idx[2];                /* index (MSB-LSB) */
-  unchar rsvd2[5];              /* reserved */
-  volatile unchar vue;          /* vendor-unique error code */
-  volatile unchar status;       /* returned (icmb) status */
-  volatile unchar phase;        /* used by interrupt handler */
+    unchar op;
+    unchar rsvd1;		/* reserved                  */
+    unchar len[3];		/* parms buffer length       */
+    unchar ptr[3];		/* parms buffer address      */
+    unchar idx[2];		/* index (MSB-LSB)           */
+    unchar rsvd2[5];		/* reserved                  */
+    volatile unchar vue;	/* vendor-unique error code  */
+    volatile unchar status;	/* returned (icmb) status    */
+    volatile unchar phase;	/* used by interrupt handler */
 } IcbParms;
 
 typedef struct icbAny {
-  unchar op;
-  unchar data[14];              /* format-specific data */
-  volatile unchar vue;          /* vendor-unique error code */
-  volatile unchar status;       /* returned (icmb) status */
-  volatile unchar phase;        /* used by interrupt handler */
+    unchar op;
+    unchar data[14];		/* format-specific data      */
+    volatile unchar vue;	/* vendor-unique error code  */
+    volatile unchar status;	/* returned (icmb) status    */
+    volatile unchar phase;	/* used by interrupt handler */
 } IcbAny;
 
 typedef union icb {
-  unchar op;                    /* ICB opcode */
-  IcbRecvCmd recv_cmd;          /* format for receive command */
-  IcbSendStat send_stat;        /* format for send status */
-  IcbRevLvl rev_lvl;            /* format for get revision level */
-  IcbDiag diag;                 /* format for execute diagnostics */
-  IcbParms eparms;              /* format for get/set exec parms */
-  IcbAny icb;                   /* generic format */
-  unchar data[18];
+    unchar op;			/* ICB opcode                     */
+    IcbRecvCmd recv_cmd;	/* format for receive command     */
+    IcbSendStat send_stat;	/* format for send status         */
+    IcbRevLvl rev_lvl;		/* format for get revision level  */
+    IcbDiag diag;		/* format for execute diagnostics */
+    IcbParms eparms;		/* format for get/set exec parms  */
+    IcbAny icb;			/* generic format                 */
+    unchar data[18];
 } Icb;
 
 
@@ -552,27 +571,34 @@
  *  structure is not part of the Adapter structure.
  */
 static Scb scbs[MAX_SCBS];
-static Scb *scbfree = NULL;      /* free list */
-static int freescbs = MAX_SCBS;  /* free list counter */
-
-/*
- *
- */
-static short wd7000_setupIRQ[NUM_CONFIGS];
-static short wd7000_setupDMA[NUM_CONFIGS];
-static short wd7000_setupIO[NUM_CONFIGS];
-static short wd7000_card_num = 0;
+static Scb *scbfree = NULL;	/* free list         */
+static int freescbs = MAX_SCBS;	/* free list counter */
 
 /*
  *  END of data/declarations - code follows.
  */
+static void setup_error (char *mesg, int *ints)
+{
+    if (ints[0] == 3)
+        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
+                ints[1], ints[2], ints[3], mesg);
+    else if (ints[0] == 4)
+        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
+                ints[1], ints[2], ints[3], ints[4], mesg);
+    else
+        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
+                ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
+}
 
 
 /*
  * Note: You can now set these options from the kernel's "command line".
  * The syntax is:
  *
- *     wd7000=IRQ,DMA,IO
+ *     wd7000=<IRQ>,<DMA>,<IO>[,<BUS_ON>[,<BUS_OFF>]]
+ *
+ * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values
+ * are 8000ns for BUS_ON and 1875ns for BUS_OFF.
  * eg:
  *     wd7000=7,6,0x350
  *
@@ -581,82 +607,99 @@
  */
 void wd7000_setup (char *str, int *ints)
 {
+    static short wd7000_card_num = 0;
     short i, j;
 
     if (wd7000_card_num >= NUM_CONFIGS) {
-        printk ("wd7000_setup: Too many \"wd7000=\" configurations in "
-	        "command line!\n");
-
-        return;
+	printk ("wd7000_setup: Too many \"wd7000=\" configurations in "
+		"command line!\n");
+	return;
     }
 
-    if (ints[0] != 3)
+    if ((ints[0] < 3) || (ints[0] > 5))
 	printk ("wd7000_setup: Error in command line!  "
-	        "Usage: wd7000=IRQ,DMA,IO\n");
+		"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>[,<BUS_OFF>]]\n");
     else {
 	for (i = 0; i < NUM_IRQS; i++)
 	    if (ints[1] == wd7000_irq[i])
 		break;
 
 	if (i == NUM_IRQS) {
-	    printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
-		    "invalid IRQ.\n", ints[1], ints[2], ints[3]);
+	    setup_error ("invalid IRQ.", ints);
 	    return;
 	}
 	else
- 	    wd7000_setupIRQ[wd7000_card_num] = ints[1];
+	    configs[wd7000_card_num].irq = ints[1];
 
 	for (i = 0; i < NUM_DMAS; i++)
 	    if (ints[2] == wd7000_dma[i])
 		break;
 
 	if (i == NUM_DMAS) {
-	    printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
-		    "invalid DMA channel.\n", ints[1], ints[2], ints[3]);
+	    setup_error ("invalid DMA channel.", ints);
 	    return;
 	}
 	else
-	    wd7000_setupDMA[wd7000_card_num] = ints[2];
+	    configs[wd7000_card_num].dma = ints[2];
 
 	for (i = 0; i < NUM_IOPORTS; i++)
 	    if (ints[3] == wd7000_iobase[i])
 		break;
 
 	if (i == NUM_IOPORTS) {
-	    printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
-		    "invalid I/O base address.\n", ints[1], ints[2], ints[3]);
+	    setup_error ("invalid I/O base address.", ints);
 	    return;
 	}
 	else
-	    wd7000_setupIO[wd7000_card_num] = ints[3];
+	    configs[wd7000_card_num].iobase = ints[3];
+
+	if (ints[0] > 3) {
+	    if ((ints[4] < 500) || (ints[4] > 31875)) {
+	        setup_error ("BUS_ON value is out of range (500 to 31875 nanoseconds)!",
+		             ints);
+	        configs[wd7000_card_num].bus_on = BUS_ON;
+	    }
+	    else
+	        configs[wd7000_card_num].bus_on = ints[4] / 125.0;
+	}
+	else
+	    configs[wd7000_card_num].bus_on = BUS_ON;
+
+	if (ints[0] > 4) {
+	    if ((ints[5] < 500) || (ints[5] > 31875)) {
+	        setup_error ("BUS_OFF value is out of range (500 to 31875 nanoseconds)!",
+		             ints);
+	        configs[wd7000_card_num].bus_off = BUS_OFF;
+	    }
+	    else
+	        configs[wd7000_card_num].bus_off = ints[5] / 125.0;
+	}
+	else
+	    configs[wd7000_card_num].bus_off = BUS_OFF;
 
 	if (wd7000_card_num)
 	    for (i = 0; i < (wd7000_card_num - 1); i++)
-	        for (j = i + 1; j < wd7000_card_num; j++)
-	            if (wd7000_setupIRQ[i] == wd7000_setupIRQ[j]) {
-	                printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
-			        "duplicated IRQ!\n",
-				ints[1], ints[2], ints[3]);
-		        return;
-	            }
-	            else if (wd7000_setupDMA[i] == wd7000_setupDMA[j]) {
-	                printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
-			        "duplicated DMA channel!\n",
-				ints[1], ints[2], ints[3]);
-		        return;
-	            }
-	            else if (wd7000_setupIO[i] == wd7000_setupIO[j]) {
-	                printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
-			        "duplicated I/O base address!\n",
-				ints[1], ints[2], ints[3]);
-		        return;
-	            }
-
-#ifdef DEBUG
-	printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x\n",
-	        wd7000_setupIRQ[wd7000_card_num],
-		wd7000_setupDMA[wd7000_card_num],
-		wd7000_setupIO[wd7000_card_num]);
+		for (j = i + 1; j < wd7000_card_num; j++)
+		    if (configs[i].irq == configs[j].irq) {
+	                setup_error ("duplicated IRQ!", ints);
+			return;
+		    }
+		    else if (configs[i].dma == configs[j].dma) {
+	                setup_error ("duplicated DMA channel!", ints);
+			return;
+		    }
+		    else if (configs[i].iobase == configs[j].iobase) {
+	                setup_error ("duplicated I/O base address!", ints);
+			return;
+		    }
+
+#ifdef WD7000_DEBUG
+	printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",
+		configs[wd7000_card_num].irq,
+		configs[wd7000_card_num].dma,
+		configs[wd7000_card_num].iobase,
+		configs[wd7000_card_num].bus_on * 125,
+		configs[wd7000_card_num].bus_off * 125);
 #endif
 
 	wd7000_card_num++;
@@ -666,21 +709,20 @@
 
 #ifdef ANY2SCSI_INLINE
 /*
-   Since they're used a lot, I've redone the following from the macros
-   formerly in wd7000.h, hopefully to speed them up by getting rid of
-   all the shifting (it may not matter; GCC might have done as well anyway).
-
-   xany2scsi and xscsi2int were not being used, and are no longer defined.
-   (They were simply 4-byte versions of these routines).
-*/
-
-typedef union {  /* let's cheat... */
-  int i;
-  unchar u[sizeof(int)];  /* the sizeof(int) makes it more portable */
+ * Since they're used a lot, I've redone the following from the macros
+ * formerly in wd7000.h, hopefully to speed them up by getting rid of
+ * all the shifting (it may not matter; GCC might have done as well anyway).
+ *
+ * xany2scsi and xscsi2int were not being used, and are no longer defined.
+ * (They were simply 4-byte versions of these routines).
+ */
+typedef union {			/* let's cheat... */
+    int i;
+    unchar u[sizeof (int)];	/* the sizeof(int) makes it more portable */
 } i_u;
 
 
-static inline void any2scsi( unchar *scsi, int any )
+static inline void any2scsi (unchar * scsi, int any)
 {
     *scsi++ = ((i_u) any).u[2];
     *scsi++ = ((i_u) any).u[1];
@@ -688,49 +730,50 @@
 }
 
 
-static inline int scsi2int( unchar *scsi )
+static inline int scsi2int (unchar * scsi)
 {
     i_u result;
 
-    result.i = 0;  /* clears unused bytes */
-    *(result.u+2) = *scsi++;
-    *(result.u+1) = *scsi++;
-      *(result.u) = *scsi++;
-    return result.i;
+    result.i = 0;		/* clears unused bytes */
+    *(result.u + 2) = *scsi++;
+    *(result.u + 1) = *scsi++;
+    *(result.u) = *scsi++;
+
+    return (result.i);
 }
 #else
 /*
-   These are the old ones - I've just moved them here...
-*/
+ * These are the old ones - I've just moved them here...
+ */
 #undef any2scsi
-#define any2scsi(up, p)			\
-(up)[0] = (((unsigned long)(p)) >> 16);		\
-(up)[1] = ((unsigned long)(p)) >> 8;		\
-(up)[2] = ((unsigned long)(p));
+#define any2scsi(up, p)   (up)[0] = (((unsigned long) (p)) >> 16);	\
+			  (up)[1] = ((unsigned long) (p)) >> 8;		\
+			  (up)[2] = ((unsigned long) (p));
 
 #undef scsi2int
-#define scsi2int(up) ( (((unsigned long)*(up)) << 16) + \
- (((unsigned long)(up)[1]) << 8) + ((unsigned long)(up)[2]) )
+#define scsi2int(up)   ( (((unsigned long) *(up)) << 16) +	\
+			 (((unsigned long) (up)[1]) << 8) +	\
+			 ((unsigned long) (up)[2]) )
 #endif
 
-    
-static inline void wd7000_enable_intr(Adapter *host)
+
+static inline void wd7000_enable_intr (Adapter *host)
 {
     host->control |= INT_EN;
-    outb(host->control, host->iobase+ASC_CONTROL);
+    outb (host->control, host->iobase + ASC_CONTROL);
 }
 
 
-static inline void wd7000_enable_dma(Adapter *host)
+static inline void wd7000_enable_dma (Adapter *host)
 {
     host->control |= DMA_EN;
-    outb(host->control,host->iobase+ASC_CONTROL);
-    set_dma_mode(host->dma, DMA_MODE_CASCADE);
-    enable_dma(host->dma);
+    outb (host->control, host->iobase + ASC_CONTROL);
+    set_dma_mode (host->dma, DMA_MODE_CASCADE);
+    enable_dma (host->dma);
 }
 
 
-#define WAITnexttimeout 200  /* 2 seconds */
+#define WAITnexttimeout 200	/* 2 seconds */
 
 static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned noneof)
 {
@@ -738,7 +781,7 @@
     register unsigned long WAITtimeout = jiffies + WAITnexttimeout;
 
     while (jiffies <= WAITtimeout) {
-     	WAITbits = inb (port) & mask;
+	WAITbits = inb (port) & mask;
 
 	if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
 	    return (0);
@@ -748,31 +791,32 @@
 }
 
 
-static inline void delay( unsigned how_long )
+static inline void delay (unsigned how_long)
 {
-     register unsigned long time = jiffies + how_long;
+    register unsigned long time = jiffies + how_long;
 
-     while (jiffies < time);
+    while (jiffies < time);
 }
 
 
-static inline int command_out(Adapter *host, unchar *cmd, int len)
+static inline int command_out (Adapter * host, unchar * cmd, int len)
 {
-    if (! WAIT (host->iobase+ASC_STAT,ASC_STATMASK,CMD_RDY,0)) {
-	while (len--)  {
-	    do  {
-		outb(*cmd, host->iobase+ASC_COMMAND);
-		WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
-	    }  while (inb(host->iobase+ASC_STAT) & CMD_REJ);
+    if (!WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+	while (len--) {
+	    do {
+		outb (*cmd, host->iobase + ASC_COMMAND);
+		WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
+	    } while (inb (host->iobase + ASC_STAT) & CMD_REJ);
 
 	    cmd++;
 	}
 
-	return 1;
+	return (1);
     }
 
-    printk("wd7000 command_out: WAIT failed(%d)\n", len+1);
-    return 0;
+    printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1);
+
+    return (0);
 }
 
 
@@ -786,7 +830,7 @@
  *  the satisfiability of a request is not dependent on the size of the
  *  request.
  */
-static inline Scb *alloc_scbs(int needed)
+static inline Scb *alloc_scbs (int needed)
 {
     register Scb *scb, *p;
     register unsigned long flags;
@@ -795,85 +839,89 @@
     static int busy = 0;
     int i;
 
-    if (needed <= 0)  return NULL;  /* sanity check */
+    if (needed <= 0)
+	return (NULL);		/* sanity check */
 
-    save_flags(flags);
-    cli();
-    while (busy)  { /* someone else is allocating */
-	sti();	/* Yes this is really needed here */
-	now = jiffies;  while (jiffies == now)  /* wait a jiffy */;
-	cli();
+    save_flags (flags);
+    cli ();
+    while (busy) {		/* someone else is allocating */
+	sti ();			/* Yes this is really needed here */
+	for (now = jiffies; now == jiffies; );	/* wait a jiffy */
+	cli ();
     }
-    busy = 1;          /* not busy now; it's our turn */
+    busy = 1;			/* not busy now; it's our turn */
 
-    while (freescbs < needed)  {
+    while (freescbs < needed) {
 	timeout = jiffies + WAITnexttimeout;
 	do {
-	    sti();	/* Yes this is really needed here */
-	    now = jiffies;
-	    while (jiffies == now); /* wait a jiffy */
-	    cli();
-	}  while (freescbs < needed && jiffies <= timeout);
+	    sti ();		/* Yes this is really needed here */
+	    for (now = jiffies; now == jiffies; );	/* wait a jiffy */
+	    cli ();
+	} while (freescbs < needed && jiffies <= timeout);
 	/*
 	 *  If we get here with enough free Scbs, we can take them.
 	 *  Otherwise, we timed out and didn't get enough.
 	 */
-	if (freescbs < needed)  {
+	if (freescbs < needed) {
 	    busy = 0;
-	    panic("wd7000: can't get enough free SCBs.\n");
-	    restore_flags(flags);
-	    return NULL;
+	    panic ("wd7000: can't get enough free SCBs.\n");
+	    restore_flags (flags);
+	    return (NULL);
 	}
     }
-    scb = scbfree;  freescbs -= needed;
-    for (i = 0; i < needed; i++)  { p = scbfree;  scbfree = p->next; }
+    scb = scbfree;
+    freescbs -= needed;
+    for (i = 0; i < needed; i++) {
+	p = scbfree;
+	scbfree = p->next;
+    }
     p->next = NULL;
-    
-    busy = 0;   /* we're done */
+    busy = 0;			/* we're done */
 
-    restore_flags(flags);
+    restore_flags (flags);
 
-    return scb;
+    return (scb);
 }
 
 
-static inline void free_scb( Scb *scb )
+static inline void free_scb (Scb *scb)
 {
     register unsigned long flags;
 
-    save_flags(flags);
-    cli();
+    save_flags (flags);
+    cli ();
 
-    memset(scb, 0, sizeof(Scb));
+    memset (scb, 0, sizeof (Scb));
     scb->next = scbfree;
     scbfree = scb;
     freescbs++;
 
-    restore_flags(flags);
+    restore_flags (flags);
 }
 
 
-static inline void init_scbs(void)
+static inline void init_scbs (void)
 {
     int i;
     unsigned long flags;
 
-    save_flags(flags);
-    cli();
+    save_flags (flags);
+    cli ();
 
     scbfree = &(scbs[0]);
-    memset(scbs, 0, sizeof(scbs));
-    for (i = 0;  i < MAX_SCBS-1;  i++)  {
-      scbs[i].next = &(scbs[i+1]);  scbs[i].SCpnt = NULL;
-    }
-    scbs[MAX_SCBS-1].next = NULL;
-    scbs[MAX_SCBS-1].SCpnt = NULL;
-
-    restore_flags(flags);
-}    
-    
+    memset (scbs, 0, sizeof (scbs));
+    for (i = 0; i < MAX_SCBS - 1; i++) {
+	scbs[i].next = &(scbs[i + 1]);
+	scbs[i].SCpnt = NULL;
+    }
+    scbs[MAX_SCBS - 1].next = NULL;
+    scbs[MAX_SCBS - 1].SCpnt = NULL;
+
+    restore_flags (flags);
+}
 
-static int mail_out( Adapter *host, Scb *scbptr )
+
+static int mail_out (Adapter *host, Scb *scbptr)
 /*
  *  Note: this can also be used for ICBs; just cast to the parm type.
  */
@@ -883,30 +931,35 @@
     unchar start_ogmb;
     Mailbox *ogmbs = host->mb.ogmb;
     int *next_ogmb = &(host->next_ogmb);
-#ifdef DEBUG
-    printk("wd7000 mail_out: 0x%06lx",(long) scbptr);
+
+#ifdef WD7000_DEBUG
+    printk ("wd7000 mail_out: 0x%06lx", (long) scbptr);
 #endif
+
     /* We first look for a free outgoing mailbox */
-    save_flags(flags);
-    cli();
+    save_flags (flags);
+    cli ();
     ogmb = *next_ogmb;
     for (i = 0; i < OGMB_CNT; i++) {
-	if (ogmbs[ogmb].status == 0)  {
-#ifdef DEBUG
-	    printk(" using OGMB 0x%x",ogmb);
+	if (ogmbs[ogmb].status == 0) {
+#ifdef WD7000_DEBUG
+	    printk (" using OGMB 0x%x", ogmb);
 #endif
 	    ogmbs[ogmb].status = 1;
-	    any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
+	    any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
 
-	    *next_ogmb = (ogmb+1) % OGMB_CNT;
+	    *next_ogmb = (ogmb + 1) % OGMB_CNT;
 	    break;
-	}  else
+	}
+	else
 	    ogmb = (++ogmb) % OGMB_CNT;
     }
-    restore_flags(flags);
-#ifdef DEBUG
-    printk(", scb is 0x%06lx",(long) scbptr);
+    restore_flags (flags);
+
+#ifdef WD7000_DEBUG
+    printk (", scb is 0x%06lx", (long) scbptr);
 #endif
+
     if (i >= OGMB_CNT) {
 	/*
 	 *  Alternatively, we might issue the "interrupt on free OGMB",
@@ -916,75 +969,76 @@
 	 *  that marks OGMB's free, waiting even with interrupts off
 	 *  should work, since they are freed very quickly in most cases.
 	 */
-	#ifdef DEBUG
-	printk(", no free OGMBs.\n");
+#ifdef WD7000_DEBUG
+	printk (", no free OGMBs.\n");
 #endif
-	return 0;
+	return (0);
     }
 
-    wd7000_enable_intr(host); 
+    wd7000_enable_intr (host);
 
     start_ogmb = START_OGMB | ogmb;
-    command_out( host, &start_ogmb, 1 );
-#ifdef DEBUG
-    printk(", awaiting interrupt.\n");
+    command_out (host, &start_ogmb, 1);
+
+#ifdef WD7000_DEBUG
+    printk (", awaiting interrupt.\n");
 #endif
-    return 1;
+
+    return (1);
 }
 
 
-int make_code(unsigned hosterr, unsigned scsierr)
-{   
-#ifdef DEBUG
+int make_code (unsigned hosterr, unsigned scsierr)
+{
+#ifdef WD7000_DEBUG
     int in_error = hosterr;
 #endif
 
-    switch ((hosterr>>8)&0xff){
-	case 0:	/* Reserved */
-		hosterr = DID_ERROR;
-		break;
-	case 1:	/* Command Complete, no errors */
-		hosterr = DID_OK;
-		break;
-	case 2: /* Command complete, error logged in scb status (scsierr) */ 
-		hosterr = DID_OK;
-		break;
-	case 4:	/* Command failed to complete - timeout */
-		hosterr = DID_TIME_OUT;
-		break;
-	case 5:	/* Command terminated; Bus reset by external device */
-		hosterr = DID_RESET;
-		break;
-	case 6:	/* Unexpected Command Received w/ host as target */
-		hosterr = DID_BAD_TARGET;
-		break;
+    switch ((hosterr >> 8) & 0xff) {
+	case 0:  /* Reserved */
+                 hosterr = DID_ERROR;
+                 break;
+	case 1:  /* Command Complete, no errors */
+                 hosterr = DID_OK;
+                 break;
+	case 2:  /* Command complete, error logged in scb status (scsierr) */
+                 hosterr = DID_OK;
+                 break;
+	case 4:  /* Command failed to complete - timeout */
+                 hosterr = DID_TIME_OUT;
+                 break;
+	case 5:  /* Command terminated; Bus reset by external device */
+                 hosterr = DID_RESET;
+                 break;
+	case 6:  /* Unexpected Command Received w/ host as target */
+                 hosterr = DID_BAD_TARGET;
+                 break;
 	case 80: /* Unexpected Reselection */
 	case 81: /* Unexpected Selection */
-		hosterr = DID_BAD_INTR;
-		break;
+                 hosterr = DID_BAD_INTR;
+                 break;
 	case 82: /* Abort Command Message  */
-		hosterr = DID_ABORT;
-		break;
+                 hosterr = DID_ABORT;
+                 break;
 	case 83: /* SCSI Bus Software Reset */
 	case 84: /* SCSI Bus Hardware Reset */
-		hosterr = DID_RESET;
-		break;
+                 hosterr = DID_RESET;
+                 break;
 	default: /* Reserved */
-		hosterr = DID_ERROR;
-		break;
-	}
-#ifdef DEBUG
-    if (scsierr||hosterr)
-	printk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
-	       scsierr,in_error,hosterr);
+                 hosterr = DID_ERROR;
+    }
+#ifdef WD7000_DEBUG
+    if (scsierr || hosterr)
+	printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
+		scsierr, in_error, hosterr);
 #endif
-    return scsierr | (hosterr << 16);
+    return (scsierr | (hosterr << 16));
 }
 
 
-static void wd7000_scsi_done(Scsi_Cmnd * SCpnt)
+static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
 {
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
     printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);
 #endif
 
@@ -992,97 +1046,100 @@
 }
 
 
-#define wd7000_intr_ack(host)  outb(0,host->iobase+ASC_INTR_ACK)
+#define wd7000_intr_ack(host)   outb (0, host->iobase + ASC_INTR_ACK)
 
-void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
+void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
 {
     register int flag, icmb, errstatus, icmb_status;
     register int host_error, scsi_error;
-    register Scb *scb;             /* for SCSI commands */
-    register IcbAny *icb;          /* for host commands */
+    register Scb *scb;		/* for SCSI commands */
+    register IcbAny *icb;	/* for host commands */
     register Scsi_Cmnd *SCpnt;
-    Adapter *host = (Adapter *) wd7000_host[irq - IRQ_MIN]->hostdata; /* This MUST be set!!! */
+    Adapter *host = (Adapter *) wd7000_host[irq - IRQ_MIN]->hostdata;	/* This MUST be set!!! */
     Mailbox *icmbs = host->mb.icmb;
 
-#ifdef DEBUG
-    printk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
+    host->int_counter++;
+
+#ifdef WD7000_DEBUG
+    printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
 #endif
 
-    flag = inb(host->iobase+ASC_INTR_STAT);
+    flag = inb (host->iobase + ASC_INTR_STAT);
 
-#ifdef DEBUG
-    printk("wd7000_intr_handle: intr stat = 0x%02x\n",flag);
+#ifdef WD7000_DEBUG
+    printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
 #endif
 
-    if (!(inb(host->iobase+ASC_STAT) & INT_IM))  {
+    if (!(inb (host->iobase + ASC_STAT) & INT_IM)) {
 	/* NB: these are _very_ possible if IRQ 15 is being used, since
-	   it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,
-	   any interrupt signal into the 8259 which can't be identified
-	   comes out as 7 from the 8259, which is 15 to the host.  Thus, it
-	   is a good thing the WD7000 has an interrupt status port, so we
-	   can sort these out.  Otherwise, electrical noise and other such
-	   problems would be indistinguishable from valid interrupts...
-	*/
-#ifdef DEBUG 
-	printk("wd7000_intr_handle: phantom interrupt...\n");
+	 * it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,
+	 * any interrupt signal into the 8259 which can't be identified
+	 * comes out as 7 from the 8259, which is 15 to the host.  Thus, it
+	 * is a good thing the WD7000 has an interrupt status port, so we
+	 * can sort these out.  Otherwise, electrical noise and other such
+	 * problems would be indistinguishable from valid interrupts...
+	 */
+#ifdef WD7000_DEBUG
+	printk ("wd7000_intr_handle: phantom interrupt...\n");
 #endif
-	wd7000_intr_ack(host);
-	return; 
+	wd7000_intr_ack (host);
+	return;
     }
 
-    if (flag & MB_INTR)  {
+    if (flag & MB_INTR) {
 	/* The interrupt is for a mailbox */
 	if (!(flag & IMB_INTR)) {
-#ifdef DEBUG
-	    printk("wd7000_intr_handle: free outgoing mailbox\n");
+#ifdef WD7000_DEBUG
+	    printk ("wd7000_intr_handle: free outgoing mailbox\n");
 #endif
 	    /*
 	     * If sleep_on() and the "interrupt on free OGMB" command are
 	     * used in mail_out(), wake_up() should correspondingly be called
 	     * here.  For now, we don't need to do anything special.
 	     */
-	    wd7000_intr_ack(host);
+	    wd7000_intr_ack (host);
 	    return;
-	}  else  {
+	}
+	else {
 	    /* The interrupt is for an incoming mailbox */
 	    icmb = flag & MB_MASK;
 	    icmb_status = icmbs[icmb].status;
-	    if (icmb_status & 0x80)  {  /* unsolicited - result in ICMB */
-#ifdef DEBUG
- 		printk("wd7000_intr_handle: unsolicited interrupt 0x%02xh\n",
-		       icmb_status);
+	    if (icmb_status & 0x80) {	/* unsolicited - result in ICMB */
+#ifdef WD7000_DEBUG
+		printk ("wd7000_intr_handle: unsolicited interrupt 0x%02xh\n",
+			icmb_status);
 #endif
-		wd7000_intr_ack(host);
+		wd7000_intr_ack (host);
 		return;
 	    }
-	    scb = (struct scb *) scsi2int((unchar *)icmbs[icmb].scbptr);
+	    scb = (struct scb *) scsi2int ((unchar *) icmbs[icmb].scbptr);
 	    icmbs[icmb].status = 0;
-	    if (!(scb->op & ICB_OP_MASK))  {   /* an SCB is done */
+	    if (!(scb->op & ICB_OP_MASK)) {	/* an SCB is done */
 		SCpnt = scb->SCpnt;
-		if (--(SCpnt->SCp.phase) <= 0)  {  /* all scbs are done */
+		if (--(SCpnt->SCp.phase) <= 0) {	/* all scbs are done */
 		    host_error = scb->vue | (icmb_status << 8);
 		    scsi_error = scb->status;
-		    errstatus = make_code(host_error,scsi_error);    
+		    errstatus = make_code (host_error, scsi_error);
 		    SCpnt->result = errstatus;
 
-		    free_scb(scb);
+		    free_scb (scb);
 
-		    SCpnt->scsi_done(SCpnt);
+		    SCpnt->scsi_done (SCpnt);
 		}
-	    }  else  {    /* an ICB is done */
+	    }
+	    else {		/* an ICB is done */
 		icb = (IcbAny *) scb;
 		icb->status = icmb_status;
-		icb->phase  = 0;
+		icb->phase = 0;
 	    }
-	}  /* incoming mailbox */
+	}			/* incoming mailbox */
     }
 
-    wd7000_intr_ack(host);
-    return;
+    wd7000_intr_ack (host);
 }
 
 
-int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
 {
     register Scb *scb;
     register Sgb *sgb;
@@ -1095,94 +1152,106 @@
     idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
     SCpnt->scsi_done = done;
     SCpnt->SCp.phase = 1;
-    scb = alloc_scbs(1);
+    scb = alloc_scbs (1);
     scb->idlun = idlun;
-    memcpy(scb->cdb, cdb, cdblen);
+    memcpy (scb->cdb, cdb, cdblen);
     scb->direc = 0x40;		/* Disable direction check */
 
-    scb->SCpnt = SCpnt;         /* so we can find stuff later */
+    scb->SCpnt = SCpnt;		/* so we can find stuff later */
     SCpnt->host_scribble = (unchar *) scb;
     scb->host = host;
 
-    if (SCpnt->use_sg)  {
+    if (SCpnt->use_sg) {
 	struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
 	unsigned i;
 
-	if (SCpnt->host->sg_tablesize == SG_NONE)  {
-	    panic("wd7000_queuecommand: scatter/gather not supported.\n");
+	if (SCpnt->host->sg_tablesize == SG_NONE) {
+	    panic ("wd7000_queuecommand: scatter/gather not supported.\n");
 	}
-#ifdef DEBUG
- 	printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg);
+#ifdef WD7000_DEBUG
+	printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
 #endif
 
 	sgb = scb->sgb;
- 	scb->op = 1;
- 	any2scsi(scb->dataptr, (int) sgb);
- 	any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) );
-
-	for (i = 0;  i < SCpnt->use_sg;  i++)  {
- 	    any2scsi(sgb[i].ptr, (int) sg[i].address);
- 	    any2scsi(sgb[i].len, sg[i].length);
+	scb->op = 1;
+	any2scsi (scb->dataptr, (int) sgb);
+	any2scsi (scb->maxlen, SCpnt->use_sg * sizeof (Sgb));
+
+	for (i = 0; i < SCpnt->use_sg; i++) {
+	    any2scsi (sgb[i].ptr, (int) sg[i].address);
+	    any2scsi (sgb[i].len, sg[i].length);
 	}
-    }  else  {
+    }
+    else {
 	scb->op = 0;
-	any2scsi(scb->dataptr, (int) SCpnt->request_buffer);
-	any2scsi(scb->maxlen, SCpnt->request_bufflen);
+	any2scsi (scb->dataptr, (int) SCpnt->request_buffer);
+	any2scsi (scb->maxlen, SCpnt->request_bufflen);
     }
-    while (!mail_out(host, scb)) /* keep trying */;
 
-    return 1;
+    while (!mail_out (host, scb));	/* keep trying */
+
+    return (1);
 }
 
 
-int wd7000_command(Scsi_Cmnd *SCpnt)
+int wd7000_command (Scsi_Cmnd *SCpnt)
 {
-    wd7000_queuecommand(SCpnt, wd7000_scsi_done);
+    wd7000_queuecommand (SCpnt, wd7000_scsi_done);
 
-    while (SCpnt->SCp.phase > 0) barrier();  /* phase counts scbs down to 0 */
+    while (SCpnt->SCp.phase > 0)
+	barrier ();		/* phase counts scbs down to 0 */
 
-    return SCpnt->result;
+    return (SCpnt->result);
 }
 
 
-int wd7000_diagnostics( Adapter *host, int code )
+int wd7000_diagnostics (Adapter *host, int code)
 {
-    static IcbDiag icb = {ICB_OP_DIAGNOSTICS};
+    static IcbDiag icb =
+    {ICB_OP_DIAGNOSTICS};
     static unchar buf[256];
     unsigned long timeout;
 
     icb.type = code;
-    any2scsi(icb.len, sizeof(buf));
-    any2scsi(icb.ptr, (int) &buf);
+    any2scsi (icb.len, sizeof (buf));
+    any2scsi (icb.ptr, (int) &buf);
     icb.phase = 1;
     /*
      * This routine is only called at init, so there should be OGMBs
      * available.  I'm assuming so here.  If this is going to
      * fail, I can just let the timeout catch the failure.
      */
-    mail_out(host, (struct scb *) &icb);
-    timeout = jiffies + WAITnexttimeout;  /* wait up to 2 seconds */
+    mail_out (host, (struct scb *) &icb);
+    timeout = jiffies + WAITnexttimeout;	/* wait up to 2 seconds */
     while (icb.phase && jiffies < timeout)
-    	barrier(); /* wait for completion */
+	barrier ();		/* wait for completion */
 
-    if (icb.phase)  {
-	printk("wd7000_diagnostics: timed out.\n");
-	return 0;
-    }
-    if (make_code(icb.vue|(icb.status << 8),0))  {
-	printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n",
-	       icb.vue, icb.status);
-	return 0;
+    if (icb.phase) {
+	printk ("wd7000_diagnostics: timed out.\n");
+	return (0);
+    }
+    if (make_code (icb.vue | (icb.status << 8), 0)) {
+	printk ("wd7000_diagnostics: failed (0x%02x,0x%02x)\n",
+		icb.vue, icb.status);
+	return (0);
     }
 
-    return 1;
+    return (1);
 }
 
 
-int wd7000_init( Adapter *host )
+int wd7000_init (Adapter *host)
 {
-    InitCmd init_cmd = {
-	INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, {0,0,0}, OGMB_CNT, ICMB_CNT
+    InitCmd init_cmd =
+    {
+	INITIALIZATION,
+ 	7,
+	host->bus_on,
+	host->bus_off,
+	0,
+	{ 0, 0, 0 },
+	OGMB_CNT,
+	ICMB_CNT
     };
     int diag;
 
@@ -1190,84 +1259,78 @@
      *  Reset the adapter - only.  The SCSI bus was initialized at power-up,
      *  and we need to do this just so we control the mailboxes, etc.
      */
-    outb(ASC_RES, host->iobase+ASC_CONTROL);
-    delay(1);  /* reset pulse: this is 10ms, only need 25us */
-    outb(0,host->iobase+ASC_CONTROL);
-    host->control = 0;   /* this must always shadow ASC_CONTROL */
-
-    if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
-        printk ("wd7000_init: WAIT timed out.\n"); 
-        return 0;					/* 0 = not ok */
-    }
-
-    if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1) {
-	printk("wd7000_init: ");
-
-	switch (diag)  {
-	case 2:
-	  printk("RAM failure.\n");
-	  break;
-	case 3:
-	  printk("FIFO R/W failed\n");
-	  break;
-	case 4:
-	  printk("SBIC register R/W failed\n");
-	  break;
-	case 5:
-	  printk("Initialization D-FF failed.\n");
-	  break;
-	case 6:
-	  printk("Host IRQ D-FF failed.\n");
-	  break;
-	case 7:
-	  printk("ROM checksum error.\n");
-	  break;
-	default:
-	  printk("diagnostic code 0x%02Xh received.\n", diag);
+    outb (ASC_RES, host->iobase + ASC_CONTROL);
+    delay (1);			/* reset pulse: this is 10ms, only need 25us */
+    outb (0, host->iobase + ASC_CONTROL);
+    host->control = 0;		/* this must always shadow ASC_CONTROL */
+
+    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+	printk ("wd7000_init: WAIT timed out.\n");
+	return (0);		/* 0 = not ok */
+    }
+
+    if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) {
+	printk ("wd7000_init: ");
+
+	switch (diag) {
+	    case 2:  printk ("RAM failure.\n");
+		     break;
+	    case 3:  printk ("FIFO R/W failed\n");
+		     break;
+	    case 4:  printk ("SBIC register R/W failed\n");
+		     break;
+	    case 5:  printk ("Initialization D-FF failed.\n");
+		     break;
+	    case 6:  printk ("Host IRQ D-FF failed.\n");
+		     break;
+	    case 7:  printk ("ROM checksum error.\n");
+		     break;
+	    default: printk ("diagnostic code 0x%02Xh received.\n", diag);
 	}
-	return 0;
+	return (0);
     }
-    
+
     /* Clear mailboxes */
-    memset(&(host->mb), 0, sizeof(host->mb));
+    memset (&(host->mb), 0, sizeof (host->mb));
 
     /* Execute init command */
-    any2scsi((unchar *) &(init_cmd.mailboxes), (int) &(host->mb));
-    if (!command_out(host, (unchar *) &init_cmd, sizeof(init_cmd)))  {
-	printk("wd7000_init: adapter initialization failed.\n"); 
-	return 0;
+    any2scsi ((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
+    if (!command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) {
+	printk ("wd7000_init: adapter initialization failed.\n");
+	return (0);
     }
 
-    if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
-        printk ("wd7000_init: WAIT timed out.\n"); 
-        return 0;
+    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
+	printk ("wd7000_init: WAIT timed out.\n");
+	return (0);
     }
 
-    if (request_irq(host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
-	printk("wd7000_init: can't get IRQ %d.\n", host->irq);
-	return 0;
+    if (request_irq (host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
+	printk ("wd7000_init: can't get IRQ %d.\n", host->irq);
+	return (0);
     }
-    if (request_dma(host->dma,"wd7000"))  {
-	printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
-	free_irq(host->irq, NULL);
-	return 0;
+    if (request_dma (host->dma, "wd7000")) {
+	printk ("wd7000_init: can't get DMA channel %d.\n", host->dma);
+	free_irq (host->irq, NULL);
+	return (0);
     }
-    wd7000_enable_dma(host);
-    wd7000_enable_intr(host);
+    wd7000_enable_dma (host);
+    wd7000_enable_intr (host);
 
-    if (!wd7000_diagnostics(host,ICB_DIAG_FULL))  {
-	free_dma(host->dma);
-	free_irq(host->irq, NULL);
-	return 0;
+    if (!wd7000_diagnostics (host, ICB_DIAG_FULL)) {
+	free_dma (host->dma);
+	free_irq (host->irq, NULL);
+	return (0);
     }
 
-    return 1;
+    return (1);
 }
 
 
-void wd7000_revision(Adapter *host)
+void wd7000_revision (Adapter *host)
 {
-    static IcbRevLvl icb = {ICB_OP_GET_REVISION};
+    static IcbRevLvl icb =
+    {ICB_OP_GET_REVISION};
 
     icb.phase = 1;
     /*
@@ -1276,9 +1339,9 @@
      * the only damage will be that the revision will show up as 0.0,
      * which in turn means that scatter/gather will be disabled.
      */
-    mail_out(host, (struct scb *) &icb);
+    mail_out (host, (struct scb *) &icb);
     while (icb.phase)
-    	barrier(); /* wait for completion */
+	barrier ();		/* wait for completion */
     host->rev1 = icb.primary;
     host->rev2 = icb.secondary;
 }
@@ -1294,7 +1357,7 @@
     save_flags (flags);
     cli ();
 
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
     printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length);
 #endif
 
@@ -1314,12 +1377,12 @@
     struct Scsi_Host *host = NULL;
     Scsi_Device *scd = scsi_devices;
     Adapter *adapter;
-    Mailbox *ogmbs, *icmbs;
     unsigned long flags;
     char *pos = buffer;
     short i;
 
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
+    Mailbox *ogmbs, *icmbs;
     short count;
 #endif
 
@@ -1327,8 +1390,8 @@
      * Find the specified host board.
      */
     for (i = 0; i < IRQS; i++)
-        if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
-            host = wd7000_host[i];
+	if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
+	    host = wd7000_host[i];
 
 	    break;
 	}
@@ -1336,35 +1399,39 @@
     /*
      * Host not found!
      */
-    if (! host)
-        return (-ESRCH);
+    if (!host)
+	return (-ESRCH);
 
     /*
      * Has data been written to the file ?
-     */ 
+     */
     if (inout)
-        return (wd7000_set_info (buffer, length, host));
+	return (wd7000_set_info (buffer, length, host));
 
     adapter = (Adapter *) host->hostdata;
-    ogmbs = adapter->mb.ogmb;
-    icmbs = adapter->mb.icmb;
 
     save_flags (flags);
     cli ();
 
     SPRINTF ("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2);
-    SPRINTF ("  IO base:     0x%x\n", adapter->iobase);
-    SPRINTF ("  IRQ:         %d\n", adapter->irq);
-    SPRINTF ("  DMA channel: %d\n", adapter->dma);
+    SPRINTF ("  IO base:      0x%x\n", adapter->iobase);
+    SPRINTF ("  IRQ:          %d\n", adapter->irq);
+    SPRINTF ("  DMA channel:  %d\n", adapter->dma);
+    SPRINTF ("  Interrupts:   %d\n", adapter->int_counter);
+    SPRINTF ("  BUS_ON time:  %d nanoseconds\n", adapter->bus_on * 125);
+    SPRINTF ("  BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
 
-#ifdef DEBUG
-    SPRINTF ("Control port value: 0x%x\n", adapter->control);
+#ifdef WD7000_DEBUG
+    ogmbs = adapter->mb.ogmb;
+    icmbs = adapter->mb.icmb;
+
+    SPRINTF ("\nControl port value: 0x%x\n", adapter->control);
     SPRINTF ("Incoming mailbox:\n");
     SPRINTF ("  size: %d\n", ICMB_CNT);
     SPRINTF ("  queued messages: ");
 
     for (i = count = 0; i < ICMB_CNT; i++)
-        if (icmbs[i].status) {
+	if (icmbs[i].status) {
 	    count++;
 	    SPRINTF ("0x%x ", i);
 	}
@@ -1377,7 +1444,7 @@
     SPRINTF ("  queued messages: ");
 
     for (i = count = 0; i < OGMB_CNT; i++)
-        if (ogmbs[i].status) {
+	if (ogmbs[i].status) {
 	    count++;
 	    SPRINTF ("0x%x ", i);
 	}
@@ -1388,23 +1455,25 @@
     /*
      * Display driver information for each device attached to the board.
      */
-    SPRINTF ("Attached devices: %s\n", scd ? "" : "none");
+    SPRINTF ("\nAttached devices: %s\n", scd ? "" : "none");
 
-    for ( ; scd; scd = scd->next)
-        if (scd->host->host_no == hostno) {
+    for (; scd; scd = scd->next)
+	if (scd->host->host_no == hostno) {
 	    SPRINTF ("  [Channel: %02d, Id: %02d, Lun: %02d]  ",
 		     scd->channel, scd->id, scd->lun);
 	    SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
 		     scsi_device_types[(short) scd->type] : "Unknown device");
 
 	    for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
-	        SPRINTF ("%c", scd->vendor[i]);
+		SPRINTF ("%c", scd->vendor[i]);
 	    SPRINTF (" ");
 
 	    for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
-	        SPRINTF ("%c", scd->model[i]);
+		SPRINTF ("%c", scd->model[i]);
 	    SPRINTF ("\n");
-        }
+	}
+
+    SPRINTF ("\n");
 
     restore_flags (flags);
 
@@ -1414,11 +1483,11 @@
     *start = buffer + offset;
 
     if ((pos - buffer) < offset)
-        return (0);
+	return (0);
     else if ((pos - buffer - offset) < length)
-        return (pos - buffer - offset);
+	return (pos - buffer - offset);
     else
-        return (length);
+	return (length);
 }
 
 
@@ -1434,14 +1503,14 @@
  */
 int wd7000_detect (Scsi_Host_Template *tpnt)
 {
-    short present = 0, biosaddr_ptr, cfg_ptr, sig_ptr, i, pass;
+    short present = 0, biosaddr_ptr, sig_ptr, i, pass;
     short biosptr[NUM_CONFIGS];
     unsigned iobase;
     Adapter *host = NULL;
     struct Scsi_Host *sh;
 
-    for (i = 0; i < IRQS; wd7000_host[i++] = NULL);
-    for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
+    for (i = 0; i < IRQS; wd7000_host[i++] = NULL) ;
+    for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1) ;
 
     tpnt->proc_dir = &proc_scsi_wd7000;
     tpnt->proc_info = &wd7000_proc_info;
@@ -1451,72 +1520,68 @@
      */
     init_scbs ();
 
-    for (pass = 0, cfg_ptr = 0; pass < NUM_CONFIGS; pass++) {
-        /*
+    for (pass = 0; pass < NUM_CONFIGS; pass++) {
+	/*
 	 * First, search for BIOS SIGNATURE...
 	 */
-        for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
+	for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
 	    for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
-	        for (i = 0; i < pass; i++)
-	            if (biosptr[i] == biosaddr_ptr)
-		        break;
+		for (i = 0; i < pass; i++)
+		    if (biosptr[i] == biosaddr_ptr)
+			break;
 
 		if ((i == pass) &&
 		    !memcmp ((void *) (wd7000_biosaddr[biosaddr_ptr] +
-		             signatures[sig_ptr].ofs), signatures[sig_ptr].sig,
-		             signatures[sig_ptr].len))
+				       signatures[sig_ptr].ofs), signatures[sig_ptr].sig,
+			     signatures[sig_ptr].len))
 		    goto bios_matched;
 	    }
 
-bios_matched:
+      bios_matched:
 	/*
 	 * BIOS SIGNATURE has been found.
 	 */
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
 	printk ("wd7000_detect: pass %d\n", pass + 1);
 
-        if (biosaddr_ptr == NUM_ADDRS)
+	if (biosaddr_ptr == NUM_ADDRS)
 	    printk ("WD-7000 SST BIOS not detected...\n");
 	else
 	    printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
-	            wd7000_biosaddr[biosaddr_ptr]);
+		    wd7000_biosaddr[biosaddr_ptr]);
 #endif
 
-	if (wd7000_card_num) 
-	    iobase = wd7000_setupIO[wd7000_card_num - 1];
-	else {
-	    if (configs[cfg_ptr++].irq < 0)
-		continue;
+	if (configs[pass].irq < 0)
+	    continue;
 
-	    iobase = configs[cfg_ptr - 1].iobase;
-	}
+	iobase = configs[pass].iobase;
 
-#ifdef DEBUG
- 	printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
+#ifdef WD7000_DEBUG
+	printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
 #endif
 
-	if (! check_region (iobase, 4)) {
+	if (!check_region (iobase, 4)) {
 
-#ifdef DEBUG
- 	    printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
+#ifdef WD7000_DEBUG
+	    printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
 #endif
- 	    /*
-  	     * ASC reset...
- 	     */
- 	    outb (ASC_RES, iobase + ASC_CONTROL);
- 	    delay (1);
- 	    outb (0, iobase + ASC_CONTROL);
-
- 	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
-#ifdef DEBUG
- 	    {
-  		printk ("failed!\n");
-  		continue;
- 	    }
- 	    else
-  		printk ("ok!\n");
+	    /*
+	     * ASC reset...
+	     */
+	    outb (ASC_RES, iobase + ASC_CONTROL);
+	    delay (1);
+	    outb (0, iobase + ASC_CONTROL);
+
+	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
+#ifdef WD7000_DEBUG
+	    {
+		printk ("failed!\n");
+		continue;
+	    }
+	    else
+		printk ("ok!\n");
 #else
-	    continue;
+		continue;
 #endif
 
 	    if (inb (iobase + ASC_INTR_STAT) == 1) {
@@ -1530,31 +1595,27 @@
 		sh = scsi_register (tpnt, sizeof (Adapter));
 		host = (Adapter *) sh->hostdata;
 
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
 		printk ("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
 #endif
 
 		memset (host, 0, sizeof (Adapter));
 
-		if (wd7000_card_num) {
-		    host->irq = wd7000_setupIRQ[--wd7000_card_num];
-		    host->dma = wd7000_setupDMA[wd7000_card_num];
-		}
-		else {
-		    host->irq = configs[cfg_ptr - 1].irq;
-		    host->dma = configs[cfg_ptr - 1].dma;
-		}
-
-	    	host->sh = wd7000_host[host->irq - IRQ_MIN] = sh;
-    		host->iobase = iobase;
+		host->irq = configs[pass].irq;
+		host->dma = configs[pass].dma;
+		host->iobase = iobase;
+		host->int_counter = 0;
+		host->bus_on = configs[pass].bus_on;
+		host->bus_off = configs[pass].bus_off;
+		host->sh = wd7000_host[host->irq - IRQ_MIN] = sh;
 
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
 		printk ("wd7000_detect: Trying init WD-7000 card at IO "
 			"0x%x, IRQ %d, DMA %d...\n",
 			host->iobase, host->irq, host->dma);
 #endif
 
-		if (! wd7000_init (host)) {  /* Initialization failed */
+		if (!wd7000_init (host)) {	/* Initialization failed */
 		    scsi_unregister (sh);
 
 		    continue;
@@ -1563,7 +1624,7 @@
 		/*
 		 *  OK from here - we'll use this adapter/configuration.
 		 */
-		wd7000_revision (host);   /* important for scatter/gather */
+		wd7000_revision (host);		/* important for scatter/gather */
 
 		/*
 		 * Register our ports.
@@ -1576,27 +1637,29 @@
 		if (host->rev1 < 6)
 		    sh->sg_tablesize = SG_NONE;
 
-		present++;		/* count it */
+		present++;	/* count it */
 
 		if (biosaddr_ptr != NUM_ADDRS)
 		    biosptr[pass] = biosaddr_ptr;
 
 		printk ("Western Digital WD-7000 (rev %d.%d) ",
 			host->rev1, host->rev2);
-		printk ("using IO 0x%x, IRQ %d, DMA %d.\n", 
+		printk ("using IO 0x%x, IRQ %d, DMA %d.\n",
 			host->iobase, host->irq, host->dma);
+                printk ("  BUS_ON time: %dns, BUS_OFF time: %dns\n",
+                        host->bus_on * 125, host->bus_off * 125);
 	    }
 	}
 
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
 	else
- 	    printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
+	    printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
 #endif
 
     }
 
-    if (! present)
-       printk ("Failed initialization of WD-7000 SCSI card!\n");
+    if (!present)
+	printk ("Failed initialization of WD-7000 SCSI card!\n");
 
     return (present);
 }
@@ -1605,26 +1668,27 @@
 /*
  *  I have absolutely NO idea how to do an abort with the WD7000...
  */
-int wd7000_abort(Scsi_Cmnd * SCpnt)
+int wd7000_abort (Scsi_Cmnd *SCpnt)
 {
     Adapter *host = (Adapter *) SCpnt->host->hostdata;
 
-    if (inb(host->iobase+ASC_STAT) & INT_IM)  {
-	printk("wd7000_abort: lost interrupt\n");
-	wd7000_intr_handle(host->irq, NULL, NULL);
-	return SCSI_ABORT_SUCCESS;
+    if (inb (host->iobase + ASC_STAT) & INT_IM) {
+	printk ("wd7000_abort: lost interrupt\n");
+	wd7000_intr_handle (host->irq, NULL, NULL);
+
+	return (SCSI_ABORT_SUCCESS);
     }
 
-    return SCSI_ABORT_SNOOZE;
+    return (SCSI_ABORT_SNOOZE);
 }
 
 
 /*
  *  I also have no idea how to do a reset...
  */
-int wd7000_reset(Scsi_Cmnd * SCpnt)
+int wd7000_reset (Scsi_Cmnd *SCpnt)
 {
-    return SCSI_RESET_PUNT;
+    return (SCSI_RESET_PUNT);
 }
 
 
@@ -1633,8 +1697,8 @@
  */
 int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
 {
-#ifdef BIOSPARAM_DEBUG
-    printk("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity);
+#ifdef WD7000_DEBUG
+    printk ("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity);
 #endif
 
     /*
@@ -1655,14 +1719,15 @@
 	 */
 	if ((scsicam_bios_param (disk, dev, info) < 0) ||
 	    !(((info[0] == 64) && (info[1] == 32)) ||
-	    ((info[0] == 255) && (info[1] == 63)))) {
+	      ((info[0] == 255) && (info[1] == 63)))) {
 	    printk ("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n"
 		    "                  using extended translation.\n");
 
 	    ip[0] = 255;
 	    ip[1] = 63;
 	    ip[2] = disk->capacity / (255 * 63);
-	} else {
+	}
+	else {
 	    ip[0] = info[0];
 	    ip[1] = info[1];
 	    ip[2] = info[2];
@@ -1672,7 +1737,7 @@
 	}
     }
 
-#ifdef BIOSPARAM_DEBUG
+#ifdef WD7000_DEBUG
     printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
     printk ("WARNING: check, if the bios geometry is correct.\n");
 #endif
diff -u --recursive --new-file v2.0.33/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c
--- v2.0.33/linux/drivers/sound/lowlevel/aci.c	Sat Jul  6 01:31:42 1996
+++ linux/drivers/sound/lowlevel/aci.c	Wed Jun  3 15:17:49 1998
@@ -58,6 +58,7 @@
  *
  */
 
+#include <linux/config.h> /* CONFIG_ACI_MIXER */
 #include "../sound_config.h"
 #ifdef CONFIG_ACI_MIXER
 
diff -u --recursive --new-file v2.0.33/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.0.33/linux/drivers/sound/sb_common.c	Sun Aug  3 15:25:08 1997
+++ linux/drivers/sound/sb_common.c	Wed Jun  3 15:17:49 1998
@@ -261,6 +261,7 @@
   return 1;
 }
 
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
 static void
 sb16_set_mpu_port(sb_devc *devc, struct address_info *hw_config)
 {
@@ -283,6 +284,7 @@
 		printk("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base);
 	}
 }
+#endif
 
 static int
 sb16_set_irq_hw (sb_devc * devc, int level)
diff -u --recursive --new-file v2.0.33/linux/fs/Config.in linux/fs/Config.in
--- v2.0.33/linux/fs/Config.in	Fri Sep  5 20:43:59 1997
+++ linux/fs/Config.in	Wed Jun  3 15:17:49 1998
@@ -10,11 +10,42 @@
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 tristate 'xiafs filesystem support' CONFIG_XIA_FS
 
-# msdos filesystems
-tristate 'DOS FAT fs support' CONFIG_FAT_FS
-dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
-dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+tristate 'Native language support (Unicode, codepages)' CONFIG_NLS
+if [ "$CONFIG_NLS" = "y" -o "$CONFIG_NLS" = "m" ]; then
+  dep_tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS $CONFIG_NLS
+
+  # msdos filesystems
+  dep_tristate 'DOS FAT fs support' CONFIG_FAT_FS $CONFIG_NLS
+  dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
+  dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+  dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
+  dep_tristate 'Codepage 437'      CONFIG_NLS_CODEPAGE_437 $CONFIG_NLS
+  dep_tristate 'Codepage 737'      CONFIG_NLS_CODEPAGE_737 $CONFIG_NLS
+  dep_tristate 'Codepage 775'      CONFIG_NLS_CODEPAGE_775 $CONFIG_NLS
+  dep_tristate 'Codepage 850'      CONFIG_NLS_CODEPAGE_850 $CONFIG_NLS
+  dep_tristate 'Codepage 852'      CONFIG_NLS_CODEPAGE_852 $CONFIG_NLS
+  dep_tristate 'Codepage 855'      CONFIG_NLS_CODEPAGE_855 $CONFIG_NLS
+  dep_tristate 'Codepage 857'      CONFIG_NLS_CODEPAGE_857 $CONFIG_NLS
+  dep_tristate 'Codepage 860'      CONFIG_NLS_CODEPAGE_860 $CONFIG_NLS
+  dep_tristate 'Codepage 861'      CONFIG_NLS_CODEPAGE_861 $CONFIG_NLS
+  dep_tristate 'Codepage 862'      CONFIG_NLS_CODEPAGE_862 $CONFIG_NLS
+  dep_tristate 'Codepage 863'      CONFIG_NLS_CODEPAGE_863 $CONFIG_NLS
+  dep_tristate 'Codepage 864'      CONFIG_NLS_CODEPAGE_864 $CONFIG_NLS
+  dep_tristate 'Codepage 865'      CONFIG_NLS_CODEPAGE_865 $CONFIG_NLS
+  dep_tristate 'Codepage 866'      CONFIG_NLS_CODEPAGE_866 $CONFIG_NLS
+  dep_tristate 'Codepage 869'      CONFIG_NLS_CODEPAGE_869 $CONFIG_NLS
+  dep_tristate 'Codepage 874'      CONFIG_NLS_CODEPAGE_874 $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-1'    CONFIG_NLS_ISO8859_1    $CONFIG_NLS 
+  dep_tristate 'NLS ISO 8859-2'    CONFIG_NLS_ISO8859_2    $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-3'    CONFIG_NLS_ISO8859_3    $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-4'    CONFIG_NLS_ISO8859_4    $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-5'    CONFIG_NLS_ISO8859_5    $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-6'    CONFIG_NLS_ISO8859_6    $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-7'    CONFIG_NLS_ISO8859_7    $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-8'    CONFIG_NLS_ISO8859_8    $CONFIG_NLS
+  dep_tristate 'NLS ISO 8859-9'    CONFIG_NLS_ISO8859_9    $CONFIG_NLS
+  dep_tristate 'NLS KOI8-R'        CONFIG_NLS_KOI8_R       $CONFIG_NLS
+fi
 
 bool '/proc filesystem support' CONFIG_PROC_FS
 if [ "$CONFIG_INET" = "y" ]; then
@@ -34,7 +65,6 @@
 if [ "$CONFIG_IPX" != "n" ]; then
   tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
 fi
-tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --recursive --new-file v2.0.33/linux/fs/Makefile linux/fs/Makefile
--- v2.0.33/linux/fs/Makefile	Fri Sep  5 20:43:59 1997
+++ linux/fs/Makefile	Wed Jun  3 15:17:49 1998
@@ -13,7 +13,8 @@
 O_OBJS    = open.o read_write.o inode.o devices.o file_table.o buffer.o \
 		super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
 		ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-		dcache.o bad_inode.o $(BINFMTS) 
+		dcache.o bad_inode.o $(BINFMTS)
+OX_OBJS   = $(NLS)
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \
@@ -189,7 +190,303 @@
   endif
 endif
 
+ifeq ($(CONFIG_BINFMT_EM86),y)
+BINFMTS += binfmt_em86.o
+else
+  ifeq ($(CONFIG_BINFMT_EM86),m)
+  M_OBJS += binfmt_em86.o
+  endif
+endif
+
 # binfmt_script is always there
 BINFMTS += binfmt_script.o
+
+ifeq ($(CONFIG_NLS),y)
+NLS += nls.o
+else
+  ifeq ($(CONFIG_NLS),m)
+  MX_OBJS += nls.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_437),y)
+NLS += nls_cp437.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_437),m)
+  M_OBJS += nls_cp437.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_737),y)
+NLS += nls_cp737.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_737),m)
+  M_OBJS += nls_cp737.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_775),y)
+NLS += nls_cp775.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_775),m)
+  M_OBJS += nls_cp775.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_850),y)
+NLS += nls_cp850.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_850),m)
+  M_OBJS += nls_cp850.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_852),y)
+NLS += nls_cp852.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_852),m)
+  M_OBJS += nls_cp852.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_855),y)
+NLS += nls_cp855.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_855),m)
+  M_OBJS += nls_cp855.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_857),y)
+NLS += nls_cp857.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_857),m)
+  M_OBJS += nls_cp857.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_860),y)
+NLS += nls_cp860.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_860),m)
+  M_OBJS += nls_cp860.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_861),y)
+NLS += nls_cp861.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_861),m)
+  M_OBJS += nls_cp861.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_862),y)
+NLS += nls_cp862.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_862),m)
+  M_OBJS += nls_cp862.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_863),y)
+NLS += nls_cp863.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_863),m)
+  M_OBJS += nls_cp863.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_864),y)
+NLS += nls_cp864.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_864),m)
+  M_OBJS += nls_cp864.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_865),y)
+NLS += nls_cp865.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_865),m)
+  M_OBJS += nls_cp865.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_866),y)
+NLS += nls_cp866.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_866),m)
+  M_OBJS += nls_cp866.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_869),y)
+NLS += nls_cp869.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_869),m)
+  M_OBJS += nls_cp869.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_874),y)
+NLS += nls_cp874.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_874),m)
+  M_OBJS += nls_cp874.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1250),y)
+NLS += nls_cp1250.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1250),m)
+  M_OBJS += nls_cp1250.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1251),y)
+NLS += nls_cp1251.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1251),m)
+  M_OBJS += nls_cp1251.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1252),y)
+NLS += nls_cp1252.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1252),m)
+  M_OBJS += nls_cp1252.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1253),y)
+NLS += nls_cp1253.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1253),m)
+  M_OBJS += nls_cp1253.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1254),y)
+NLS += nls_cp1254.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1254),m)
+  M_OBJS += nls_cp1254.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1255),y)
+NLS += nls_cp1255.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1255),m)
+  M_OBJS += nls_cp1255.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1256),y)
+NLS += nls_cp1256.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1256),m)
+  M_OBJS += nls_cp1256.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1257),y)
+NLS += nls_cp1257.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1257),m)
+  M_OBJS += nls_cp1257.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1258),y)
+NLS += nls_cp1258.o
+else
+  ifeq ($(CONFIG_NLS_CODEPAGE_1258),m)
+  M_OBJS += nls_cp1258.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_1),y)
+NLS += nls_iso8859_1.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_1),m)
+  M_OBJS += nls_iso8859_1.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_2),y)
+NLS += nls_iso8859_2.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_2),m)
+  M_OBJS += nls_iso8859_2.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_3),y)
+NLS += nls_iso8859_3.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_3),m)
+  M_OBJS += nls_iso8859_3.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_4),y)
+NLS += nls_iso8859_4.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_4),m)
+  M_OBJS += nls_iso8859_4.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_5),y)
+NLS += nls_iso8859_5.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_5),m)
+  M_OBJS += nls_iso8859_5.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_6),y)
+NLS += nls_iso8859_6.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_6),m)
+  M_OBJS += nls_iso8859_6.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_7),y)
+NLS += nls_iso8859_7.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_7),m)
+  M_OBJS += nls_iso8859_7.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_8),y)
+NLS += nls_iso8859_8.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_8),m)
+  M_OBJS += nls_iso8859_8.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_9),y)
+NLS += nls_iso8859_9.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_9),m)
+  M_OBJS += nls_iso8859_9.o
+  endif
+endif
+
+ifeq ($(CONFIG_NLS_KOI8_R),y)
+NLS += nls_koi8_r.o
+else
+  ifeq ($(CONFIG_NLS_KOI8_R),m)
+  M_OBJS += nls_koi8_r.o
+  endif
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.0.33/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.0.33/linux/fs/binfmt_elf.c	Wed Oct 15 14:56:43 1997
+++ linux/fs/binfmt_elf.c	Wed Jun  3 15:17:49 1998
@@ -37,9 +37,9 @@
 
 #include <linux/elf.h>
 
-static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
+static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static int load_elf_library(int fd);
-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
 extern void dump_thread(struct pt_regs *, struct user *);
 
 /*
@@ -47,7 +47,7 @@
  * don't even try.
  */
 #ifdef USE_ELF_CORE_DUMP
-static int elf_core_dump(long signr, struct pt_regs * regs);
+static int elf_core_dump(long signr, struct pt_regs *regs);
 #else
 #define elf_core_dump	NULL
 #endif
@@ -55,11 +55,12 @@
 #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
 #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
 
-static struct linux_binfmt elf_format = {
+static struct linux_binfmt elf_format =
+{
 #ifndef MODULE
 	NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
 #else
-	NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump
+  NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump
 #endif
 };
 
@@ -67,7 +68,7 @@
 {
 	start = PAGE_ALIGN(start);
 	end = PAGE_ALIGN(end);
-	if (end <= start) 
+	if (end <= start)
 		return;
 	do_mmap(NULL, start, end - start,
 		PROT_READ | PROT_WRITE | PROT_EXEC,
@@ -84,9 +85,9 @@
 static void padzero(unsigned long elf_bss)
 {
 	unsigned long nbyte;
-	char * fpnt;
-  
-	nbyte = elf_bss & (PAGE_SIZE-1);
+	char *fpnt;
+
+	nbyte = elf_bss & (PAGE_SIZE - 1);
 	if (nbyte) {
 		nbyte = PAGE_SIZE - nbyte;
 		/* FIXME: someone should investigate, why a bad binary
@@ -103,10 +104,10 @@
 	}
 }
 
-unsigned long * create_elf_tables(char *p, int argc, int envc, 
-				  struct elfhdr * exec,
-				  unsigned long load_addr,
-				  unsigned long interp_load_addr, int ibcs)
+unsigned long *create_elf_tables(char *p, int argc, int envc,
+				 struct elfhdr *exec,
+				 unsigned long load_addr,
+				 unsigned long interp_load_addr, int ibcs)
 {
 	unsigned long *argv, *envp, *dlinfo;
 	unsigned long *sp;
@@ -115,52 +116,53 @@
 	 * Force 16 byte alignment here for generality.
 	 */
 	sp = (unsigned long *) (~15UL & (unsigned long) p);
-	sp -= exec ? DLINFO_ITEMS*2 : 2;
+	sp -= exec ? DLINFO_ITEMS * 2 : 2;
 	dlinfo = sp;
-	sp -= envc+1;
+	sp -= envc + 1;
 	envp = sp;
-	sp -= argc+1;
+	sp -= argc + 1;
 	argv = sp;
 	if (!ibcs) {
-		put_user(envp,--sp);
-		put_user(argv,--sp);
+		put_user(envp, --sp);
+		put_user(argv, --sp);
 	}
-
 #define NEW_AUX_ENT(id, val) \
 	  put_user ((id), dlinfo++); \
 	  put_user ((val), dlinfo++)
 
-	if (exec) { /* Put this here for an ELF program interpreter */
-	  struct elf_phdr * eppnt;
-	  eppnt = (struct elf_phdr *) exec->e_phoff;
-
-	  NEW_AUX_ENT (AT_PHDR, load_addr + exec->e_phoff);
-	  NEW_AUX_ENT (AT_PHENT, sizeof (struct elf_phdr));
-	  NEW_AUX_ENT (AT_PHNUM, exec->e_phnum);
-	  NEW_AUX_ENT (AT_PAGESZ, PAGE_SIZE);
-	  NEW_AUX_ENT (AT_BASE, interp_load_addr);
-	  NEW_AUX_ENT (AT_FLAGS, 0);
-	  NEW_AUX_ENT (AT_ENTRY, (unsigned long) exec->e_entry);
-	  NEW_AUX_ENT (AT_UID, (unsigned long) current->uid);
-	  NEW_AUX_ENT (AT_EUID, (unsigned long) current->euid);
-	  NEW_AUX_ENT (AT_GID, (unsigned long) current->gid);
-	  NEW_AUX_ENT (AT_EGID, (unsigned long) current->egid);
+	if (exec) {		/* Put this here for an ELF program interpreter */
+		struct elf_phdr *eppnt;
+		eppnt = (struct elf_phdr *) exec->e_phoff;
+
+		NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff);
+		NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr));
+		NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
+		NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE);
+		NEW_AUX_ENT(AT_BASE, interp_load_addr);
+		NEW_AUX_ENT(AT_FLAGS, 0);
+		NEW_AUX_ENT(AT_ENTRY, (unsigned long) exec->e_entry);
+		NEW_AUX_ENT(AT_UID, (unsigned long) current->uid);
+		NEW_AUX_ENT(AT_EUID, (unsigned long) current->euid);
+		NEW_AUX_ENT(AT_GID, (unsigned long) current->gid);
+		NEW_AUX_ENT(AT_EGID, (unsigned long) current->egid);
 	}
-	NEW_AUX_ENT (AT_NULL, 0);
+	NEW_AUX_ENT(AT_NULL, 0);
 #undef NEW_AUX_ENT
-	put_user((unsigned long)argc,--sp);
+	put_user((unsigned long) argc, --sp);
 	current->mm->arg_start = (unsigned long) p;
-	while (argc-->0) {
-		put_user(p,argv++);
-		while (get_user(p++)) /* nothing */ ;
+	while (argc-- > 0) {
+		put_user(p, argv++);
+		while (get_user(p++))	/* nothing */
+			;
 	}
-	put_user(0,argv);
+	put_user(0, argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-	while (envc-->0) {
-		put_user(p,envp++);
-		while (get_user(p++)) /* nothing */ ;
+	while (envc-- > 0) {
+		put_user(p, envp++);
+		while (get_user(p++))	/* nothing */
+			;
 	}
-	put_user(0,envp);
+	put_user(0, envp);
 	current->mm->env_end = (unsigned long) p;
 	return sp;
 }
@@ -171,12 +173,12 @@
    is only provided so that we can read a.out libraries that have
    an ELF header */
 
-static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
-				     struct inode * interpreter_inode, 
+static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
+				     struct inode *interpreter_inode,
 				     unsigned long *interp_load_addr)
 {
-	struct file * file;
-	struct elf_phdr *elf_phdata  =  NULL;
+	struct file *file;
+	struct elf_phdr *elf_phdata = NULL;
 	struct elf_phdr *eppnt;
 	unsigned long load_addr;
 	int load_addr_set = 0;
@@ -185,108 +187,104 @@
 	unsigned long last_bss, elf_bss;
 	unsigned long error;
 	int i;
-	
+
 	elf_bss = 0;
 	last_bss = 0;
 	error = load_addr = 0;
-	
+
 	/* First of all, some simple consistency checks */
-	if ((interp_elf_ex->e_type != ET_EXEC && 
-	    interp_elf_ex->e_type != ET_DYN) || 
-	   !elf_check_arch(interp_elf_ex->e_machine) ||
-	   (!interpreter_inode->i_op ||
-	    !interpreter_inode->i_op->default_file_ops->mmap)){
+	if ((interp_elf_ex->e_type != ET_EXEC &&
+	     interp_elf_ex->e_type != ET_DYN) ||
+	    !elf_check_arch(interp_elf_ex->e_machine) ||
+	    (!interpreter_inode->i_op ||
+	     !interpreter_inode->i_op->default_file_ops->mmap)) {
 		return ~0UL;
 	}
-	
 	/* Now read in all of the header information */
-	
+
 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
-	    return ~0UL;
-	
-	elf_phdata =  (struct elf_phdr *) 
-		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 
-			GFP_KERNEL);
+		 return ~0UL;
+
+	elf_phdata = (struct elf_phdr *)
+	    kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
+		    GFP_KERNEL);
 	if (!elf_phdata)
-	  return ~0UL;
-	
+		return ~0UL;
+
 	/*
 	 * If the size of this structure has changed, then punt, since
 	 * we will be doing the wrong thing.
 	 */
-	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
-	  {
-	    kfree(elf_phdata);
-	    return ~0UL;
-	  }
-
-	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, 
+	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
+		kfree(elf_phdata);
+		return ~0UL;
+	}
+	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
 			   (char *) elf_phdata,
-			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
-	
+		    sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
+
 	if (retval < 0) {
-		kfree (elf_phdata);
+		kfree(elf_phdata);
 		return retval;
- 	}
-
+	}
 	elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
 	if (elf_exec_fileno < 0) {
-	  kfree(elf_phdata);
-	  return ~0UL;
+		kfree(elf_phdata);
+		return ~0UL;
 	}
-
 	file = current->files->fd[elf_exec_fileno];
 
 	eppnt = elf_phdata;
-	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-	  if (eppnt->p_type == PT_LOAD) {
-	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-	    int elf_prot = 0;
-	    unsigned long vaddr = 0;
-	    unsigned long k;
-
-	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
-	    	elf_type |= MAP_FIXED;
-	    	vaddr = eppnt->p_vaddr;
-	    }
-	    
-	    error = do_mmap(file, 
-			    load_addr + ELF_PAGESTART(vaddr),
-			    eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
-			    elf_prot,
-			    elf_type,
-			    eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-	    
-	    if (error > -1024UL) {
-	      /* Real error */
-	      sys_close(elf_exec_fileno);
-	      kfree(elf_phdata);
-	      return ~0UL;
-	    }
-
-	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-	      load_addr = error;
-	      load_addr_set = 1;
-	    }
-
-	    /*
-	     * Find the end of the file  mapping for this phdr, and keep
-	     * track of the largest address we see for this.
-	     */
-	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-	    if (k > elf_bss) elf_bss = k;
-
-	    /*
-	     * Do the same thing for the memory mapping - between
-	     * elf_bss and last_bss is the bss section.
-	     */
-	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-	    if (k > last_bss) last_bss = k;
-	  }
-	
+	for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++)
+		if (eppnt->p_type == PT_LOAD) {
+			int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+			int elf_prot = 0;
+			unsigned long vaddr = 0;
+			unsigned long k;
+
+			if (eppnt->p_flags & PF_R)
+				elf_prot = PROT_READ;
+			if (eppnt->p_flags & PF_W)
+				elf_prot |= PROT_WRITE;
+			if (eppnt->p_flags & PF_X)
+				elf_prot |= PROT_EXEC;
+			if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+				elf_type |= MAP_FIXED;
+				vaddr = eppnt->p_vaddr;
+			}
+			error = do_mmap(file,
+					load_addr + ELF_PAGESTART(vaddr),
+			eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
+					elf_prot,
+					elf_type,
+			eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+
+			if (error > -1024UL) {
+				/* Real error */
+				sys_close(elf_exec_fileno);
+				kfree(elf_phdata);
+				return ~0UL;
+			}
+			if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+				load_addr = error;
+				load_addr_set = 1;
+			}
+			/*
+			 * Find the end of the file  mapping for this phdr, and keep
+			 * track of the largest address we see for this.
+			 */
+			k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+			if (k > elf_bss)
+				elf_bss = k;
+
+			/*
+			 * Do the same thing for the memory mapping - between
+			 * elf_bss and last_bss is the bss section.
+			 */
+			k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+			if (k > last_bss)
+				last_bss = k;
+		}
 	/* Now use mmap to map the library into memory. */
 
 	sys_close(elf_exec_fileno);
@@ -298,55 +296,56 @@
 	 * bss page.
 	 */
 	padzero(elf_bss);
-	elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
+	elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1);	/* What we have mapped so far */
 
 	/* Map the last of the bss segment */
 	if (last_bss > elf_bss)
-	  do_mmap(NULL, elf_bss, last_bss-elf_bss,
-		  PROT_READ|PROT_WRITE|PROT_EXEC,
-		  MAP_FIXED|MAP_PRIVATE, 0);
+		do_mmap(NULL, elf_bss, last_bss - elf_bss,
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE, 0);
 	kfree(elf_phdata);
 
 	*interp_load_addr = load_addr;
 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
 }
 
-static unsigned long load_aout_interp(struct exec * interp_ex,
-			     struct inode * interpreter_inode)
+static unsigned long load_aout_interp(struct exec *interp_ex,
+				      struct inode *interpreter_inode)
 {
-  int retval;
-  unsigned long elf_entry;
-  
-  current->mm->brk = interp_ex->a_bss +
-    (current->mm->end_data = interp_ex->a_data +
-     (current->mm->end_code = interp_ex->a_text));
-  elf_entry = interp_ex->a_entry;
-  
-  
-  if (N_MAGIC(*interp_ex) == OMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-	    PROT_READ|PROT_WRITE|PROT_EXEC,
-	    MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode, 32, (char *) 0, 
-		       interp_ex->a_text+interp_ex->a_data, 0);
-  } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-	    PROT_READ|PROT_WRITE|PROT_EXEC,
-	    MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode,
-		       N_TXTOFF(*interp_ex) ,
-		       (char *) N_TXTADDR(*interp_ex),
-		       interp_ex->a_text+interp_ex->a_data, 0);
-  } else
-    retval = -1;
-  
-  if (retval >= 0)
-    do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
-	    interp_ex->a_bss,
-	    PROT_READ|PROT_WRITE|PROT_EXEC,
-	    MAP_FIXED|MAP_PRIVATE, 0);
-  if (retval < 0) return ~0UL;
-  return elf_entry;
+	int retval;
+	unsigned long elf_entry;
+
+	current->mm->brk = interp_ex->a_bss +
+	    (current->mm->end_data = interp_ex->a_data +
+	     (current->mm->end_code = interp_ex->a_text));
+	elf_entry = interp_ex->a_entry;
+
+
+	if (N_MAGIC(*interp_ex) == OMAGIC) {
+		do_mmap(NULL, 0, interp_ex->a_text + interp_ex->a_data,
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE, 0);
+		retval = read_exec(interpreter_inode, 32, (char *) 0,
+			       interp_ex->a_text + interp_ex->a_data, 0);
+	} else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
+		do_mmap(NULL, 0, interp_ex->a_text + interp_ex->a_data,
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE, 0);
+		retval = read_exec(interpreter_inode,
+				   N_TXTOFF(*interp_ex),
+				   (char *) N_TXTADDR(*interp_ex),
+			       interp_ex->a_text + interp_ex->a_data, 0);
+	} else
+		retval = -1;
+
+	if (retval >= 0)
+		do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
+			interp_ex->a_bss,
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE, 0);
+	if (retval < 0)
+		return ~0UL;
+	return elf_entry;
 }
 
 /*
@@ -359,13 +358,12 @@
 #define INTERPRETER_ELF 2
 
 
-static inline int
-do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+static inline int do_load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
 	struct elfhdr elf_ex;
 	struct elfhdr interp_elf_ex;
-	struct file * file;
-  	struct exec interp_ex;
+	struct file *file;
+	struct exec interp_ex;
 	struct inode *interpreter_inode;
 	unsigned long load_addr;
 	int load_addr_set = 0;
@@ -374,125 +372,123 @@
 	int i;
 	int old_fs;
 	int error;
-	struct elf_phdr * elf_ppnt, *elf_phdata;
+	struct elf_phdr *elf_ppnt, *elf_phdata;
 	int elf_exec_fileno;
 	unsigned long elf_bss, k, elf_brk;
-	int retval;
-	char * elf_interpreter;
+	int retval, ret_namei = -1;
+	char *elf_interpreter;
 	unsigned long elf_entry, interp_load_addr = 0;
 	int status;
 	unsigned long start_code, end_code, end_data;
 	unsigned long elf_stack;
 	char passed_fileno[6];
-	
+
 	ibcs2_interpreter = 0;
 	status = 0;
 	load_addr = 0;
-	elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
-	
+	elf_ex = *((struct elfhdr *) bprm->buf);	/* exec-header */
+
 	if (elf_ex.e_ident[0] != 0x7f ||
-	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
-		return  -ENOEXEC;
+	    strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) {
+		return -ENOEXEC;
 	}
-	
-	
 	/* First of all, some simple consistency checks */
 	if ((elf_ex.e_type != ET_EXEC &&
-	    elf_ex.e_type != ET_DYN) || 
-	   (! elf_check_arch(elf_ex.e_machine)) ||
-	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-	    !bprm->inode->i_op->default_file_ops->mmap)){
+	     elf_ex.e_type != ET_DYN) ||
+	    (!elf_check_arch(elf_ex.e_machine)) ||
+	    (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+	     !bprm->inode->i_op->default_file_ops->mmap)) {
 		return -ENOEXEC;
 	}
-	
 	/* Now read in all of the header information */
-	
-	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * 
-						 elf_ex.e_phnum, GFP_KERNEL);
+
+	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
+					     elf_ex.e_phnum, GFP_KERNEL);
 	if (elf_phdata == NULL) {
 		return -ENOMEM;
 	}
-	
 	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
 			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
 	if (retval < 0) {
-		kfree (elf_phdata);
+		kfree(elf_phdata);
 		return retval;
 	}
-	
 	elf_ppnt = elf_phdata;
-	
+
 	elf_bss = 0;
 	elf_brk = 0;
-	
+
 	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
 
 	if (elf_exec_fileno < 0) {
-		kfree (elf_phdata);
+		kfree(elf_phdata);
 		return elf_exec_fileno;
 	}
-	
 	file = current->files->fd[elf_exec_fileno];
-	
+
 	elf_stack = ~0UL;
 	elf_interpreter = NULL;
 	start_code = ~0UL;
 	end_code = 0;
 	end_data = 0;
-	
-	for(i=0;i < elf_ex.e_phnum; i++){
+
+	for (i = 0; i < elf_ex.e_phnum; i++) {
 		if (elf_ppnt->p_type == PT_INTERP) {
-		  	if ( elf_interpreter != NULL )
-			{
-				kfree (elf_phdata);
+			if (elf_interpreter != NULL) {
+				iput(interpreter_inode);
+				kfree(elf_phdata);
 				kfree(elf_interpreter);
 				sys_close(elf_exec_fileno);
 				return -EINVAL;
 			}
-
 			/* This is the program interpreter used for
 			 * shared libraries - for now assume that this
 			 * is an a.out format binary 
 			 */
-			
-			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, 
+
+			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
 							   GFP_KERNEL);
 			if (elf_interpreter == NULL) {
-				kfree (elf_phdata);
+				kfree(elf_phdata);
 				sys_close(elf_exec_fileno);
 				return -ENOMEM;
 			}
-			
-			retval = read_exec(bprm->inode,elf_ppnt->p_offset,
+			retval = read_exec(bprm->inode, elf_ppnt->p_offset,
 					   elf_interpreter,
 					   elf_ppnt->p_filesz, 1);
 			/* If the program interpreter is one of these two,
 			   then assume an iBCS2 image. Otherwise assume
 			   a native linux image. */
-			if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
-			    strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
-			  ibcs2_interpreter = 1;
+			if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 ||
+			strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0)
+				ibcs2_interpreter = 1;
 #if 0
 			printk("Using ELF interpreter %s\n", elf_interpreter);
 #endif
 			if (retval >= 0) {
-				old_fs = get_fs(); /* This could probably be optimized */
+				old_fs = get_fs();	/* This could probably be optimized */
 				set_fs(get_ds());
-				retval = open_namei(elf_interpreter, 0, 0,
-						    &interpreter_inode, NULL);
+				retval = ret_namei = open_namei(elf_interpreter, 0, 0,
+					       &interpreter_inode, NULL);
 				set_fs(old_fs);
 			}
+			if (retval >= 0)
+				retval = permission(interpreter_inode, MAY_EXEC);
+			if (retval >= 0)
+				retval = S_ISREG(interpreter_inode->i_mode) ? 0 : -EACCES;
 
 			if (retval >= 0)
-				retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
-			
+				retval = read_exec(interpreter_inode, 0, bprm->buf, 128, 1);
+
 			if (retval >= 0) {
-				interp_ex = *((struct exec *) bprm->buf);		/* exec-header */
-				interp_elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
-				
+				interp_ex = *((struct exec *) bprm->buf);	/* exec-header */
+				interp_elf_ex = *((struct elfhdr *) bprm->buf);		/* exec-header */
+
 			}
 			if (retval < 0) {
-				kfree (elf_phdata);
+				if (ret_namei >= 0)
+					iput(interpreter_inode);
+				kfree(elf_phdata);
 				kfree(elf_interpreter);
 				sys_close(elf_exec_fileno);
 				return retval;
@@ -502,56 +498,56 @@
 	}
 
 	/* Some simple consistency checks for the interpreter */
-	if (elf_interpreter){
+	if (elf_interpreter) {
 		interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
 
 		/* Now figure out which format our binary is */
-		if ((N_MAGIC(interp_ex) != OMAGIC) && 
+		if ((N_MAGIC(interp_ex) != OMAGIC) &&
 		    (N_MAGIC(interp_ex) != ZMAGIC) &&
-		    (N_MAGIC(interp_ex) != QMAGIC)) 
-		  interpreter_type = INTERPRETER_ELF;
+		    (N_MAGIC(interp_ex) != QMAGIC))
+			interpreter_type = INTERPRETER_ELF;
 
 		if (interp_elf_ex.e_ident[0] != 0x7f ||
-		    strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
-		  interpreter_type &= ~INTERPRETER_ELF;
+		    strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0)
+			interpreter_type &= ~INTERPRETER_ELF;
 
-		if (!interpreter_type)
-		  {
-		    kfree(elf_interpreter);
-		    kfree(elf_phdata);
-		    sys_close(elf_exec_fileno);
-		    return -ELIBBAD;
-		  }
+		if (!interpreter_type) {
+			iput(interpreter_inode);
+			kfree(elf_interpreter);
+			kfree(elf_phdata);
+			sys_close(elf_exec_fileno);
+			return -ELIBBAD;
+		}
 	}
-	
 	/* OK, we are done with that, now set up the arg stuff,
 	   and then start this sucker up */
-	
+
 	if (!bprm->sh_bang) {
-		char * passed_p;
-		
+		char *passed_p;
+
 		if (interpreter_type == INTERPRETER_AOUT) {
-		  sprintf(passed_fileno, "%d", elf_exec_fileno);
-		  passed_p = passed_fileno;
-		
-		  if (elf_interpreter) {
-		    bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
-		    bprm->argc++;
-		  }
+			sprintf(passed_fileno, "%d", elf_exec_fileno);
+			passed_p = passed_fileno;
+
+			if (elf_interpreter) {
+				bprm->p = copy_strings(1, &passed_p, bprm->page, bprm->p, 2);
+				bprm->argc++;
+			}
 		}
 		if (!bprm->p) {
 			if (elf_interpreter) {
-			      kfree(elf_interpreter);
+				kfree(elf_interpreter);
 			}
-			kfree (elf_phdata);
+			iput(interpreter_inode);
+			kfree(elf_phdata);
 			sys_close(elf_exec_fileno);
 			return -E2BIG;
 		}
 	}
-	
-	if (flush_old_exec(bprm))
+	if (flush_old_exec(bprm)) {
+		iput(interpreter_inode);
 		return -ENOMEM;
-
+	}
 	/* OK, This is the point of no return */
 
 	current->mm->end_data = 0;
@@ -559,86 +555,93 @@
 	current->mm->start_mmap = ELF_START_MMAP;
 	current->mm->mmap = NULL;
 	elf_entry = (unsigned long) elf_ex.e_entry;
-	
+
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
 	current->mm->rss = 0;
 	bprm->p = setup_arg_pages(bprm->p, bprm);
 	current->mm->start_stack = bprm->p;
-	
+
 	/* Now we do a little grungy work by mmaping the ELF image into
 	   the correct location in memory.  At this point, we assume that
 	   the image should be loaded at fixed address, not at a variable
 	   address. */
-	
+
 	old_fs = get_fs();
 	set_fs(get_ds());
-	for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+	for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
 		if (elf_ppnt->p_type == PT_LOAD) {
 			int elf_prot = 0;
-			if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
-			if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-			if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+			if (elf_ppnt->p_flags & PF_R)
+				elf_prot |= PROT_READ;
+			if (elf_ppnt->p_flags & PF_W)
+				elf_prot |= PROT_WRITE;
+			if (elf_ppnt->p_flags & PF_X)
+				elf_prot |= PROT_EXEC;
 
 			error = do_mmap(file,
 					ELF_PAGESTART(elf_ppnt->p_vaddr),
 					(elf_ppnt->p_filesz +
-					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+				      ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
 					elf_prot,
 					(MAP_FIXED | MAP_PRIVATE |
 					 MAP_DENYWRITE | MAP_EXECUTABLE),
 					(elf_ppnt->p_offset -
-					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-			
+				     ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+
 #ifdef LOW_ELF_STACK
-			if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 
+			if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
 				elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
 #endif
-			
-			if (!load_addr_set) { 
-			  load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
-			  load_addr_set = 1;
+
+			if (!load_addr_set) {
+				load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
+				load_addr_set = 1;
 			}
 			k = elf_ppnt->p_vaddr;
-			if (k < start_code) start_code = k;
+			if (k < start_code)
+				start_code = k;
 			k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-			if (k > elf_bss) elf_bss = k;
+			if (k > elf_bss)
+				elf_bss = k;
 #if 1
-			if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
+			if ((elf_ppnt->p_flags & PF_X) && end_code < k)
 #else
-			if ( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
+			if (!(elf_ppnt->p_flags & PF_W) && end_code < k)
 #endif
-				end_code = k; 
-			if (end_data < k) end_data = k; 
+				end_code = k;
+			if (end_data < k)
+				end_data = k;
 			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-			if (k > elf_brk) elf_brk = k;		     
+			if (k > elf_brk)
+				elf_brk = k;
 		}
 	}
 	set_fs(old_fs);
 
 	if (elf_interpreter) {
-		if (interpreter_type & 1) 
+		if (interpreter_type & 1)
 			elf_entry = load_aout_interp(&interp_ex,
 						     interpreter_inode);
-		else if (interpreter_type & 2) 
-			elf_entry = load_elf_interp(&interp_elf_ex, 
-						    interpreter_inode, 
+		else if (interpreter_type & 2)
+			elf_entry = load_elf_interp(&interp_elf_ex,
+						    interpreter_inode,
 						    &interp_load_addr);
 
 		iput(interpreter_inode);
 		kfree(elf_interpreter);
-			
-		if (elf_entry == ~0UL) { 
+
+		if (elf_entry == ~0UL) {
 			printk("Unable to load interpreter\n");
 			kfree(elf_phdata);
 			send_sig(SIGSEGV, current, 0);
 			return 0;
 		}
 	}
-
 	kfree(elf_phdata);
-	
-	if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
+
+	if (interpreter_type != INTERPRETER_AOUT)
+		sys_close(elf_exec_fileno);
 	current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
 
 	if (current->exec_domain && current->exec_domain->use_count)
@@ -662,16 +665,16 @@
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
 	current->flags &= ~PF_FORKNOEXEC;
-	bprm->p = (unsigned long) 
-	  create_elf_tables((char *)bprm->p,
-			bprm->argc,
-			bprm->envc,
-			(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
-			load_addr,
-			interp_load_addr,
-			(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+	bprm->p = (unsigned long)
+	    create_elf_tables((char *) bprm->p,
+			      bprm->argc,
+			      bprm->envc,
+		  (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
+			      load_addr,
+			      interp_load_addr,
+			 (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
 	if (interpreter_type == INTERPRETER_AOUT)
-	  current->mm->arg_start += strlen(passed_fileno) + 1;
+		current->mm->arg_start += strlen(passed_fileno) + 1;
 	current->mm->start_brk = current->mm->brk = elf_brk;
 	current->mm->end_code = end_code;
 	current->mm->start_code = start_code;
@@ -685,16 +688,15 @@
 	padzero(elf_bss);
 
 #if 0
-	printk("(start_brk) %x\n" , current->mm->start_brk);
-	printk("(end_code) %x\n" , current->mm->end_code);
-	printk("(start_code) %x\n" , current->mm->start_code);
-	printk("(end_data) %x\n" , current->mm->end_data);
-	printk("(start_stack) %x\n" , current->mm->start_stack);
-	printk("(brk) %x\n" , current->mm->brk);
+	printk("(start_brk) %x\n", current->mm->start_brk);
+	printk("(end_code) %x\n", current->mm->end_code);
+	printk("(start_code) %x\n", current->mm->start_code);
+	printk("(end_data) %x\n", current->mm->end_data);
+	printk("(start_stack) %x\n", current->mm->start_stack);
+	printk("(brk) %x\n", current->mm->brk);
 #endif
 
-	if ( current->personality == PER_SVR4 )
-	{
+	if (current->personality == PER_SVR4) {
 		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
 		   and some applications "depend" upon this behavior.
 		   Since we do not have the power to recompile these, we
@@ -702,7 +704,6 @@
 		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE, 0);
 	}
-
 #ifdef ELF_PLAT_INIT
 	/*
 	 * The ABI may specify that certain registers be set up in special
@@ -720,8 +721,7 @@
 	return 0;
 }
 
-static int
-load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
 	int retval;
 
@@ -734,24 +734,24 @@
 /* This is really simpleminded and specialized - we are loading an
    a.out library that is given an ELF header. */
 
-static inline int
-do_load_elf_library(int fd){
-	struct file * file;
+static inline int do_load_elf_library(int fd)
+{
+	struct file *file;
 	struct elfhdr elf_ex;
-	struct elf_phdr *elf_phdata  =  NULL;
-	struct  inode * inode;
+	struct elf_phdr *elf_phdata = NULL;
+	struct inode *inode;
 	unsigned long len;
 	int elf_bss;
 	int retval;
 	unsigned long bss;
 	int error;
-	int i,j, k;
+	int i, j, k;
 
 	len = 0;
 	file = current->files->fd[fd];
 	inode = file->f_inode;
 	elf_bss = 0;
-	
+
 	if (!file || !file->f_op)
 		return -EACCES;
 
@@ -769,39 +769,40 @@
 		return -ENOEXEC;
 
 	if (elf_ex.e_ident[0] != 0x7f ||
-	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+	    strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
 		return -ENOEXEC;
 
 	/* First of all, some simple consistency checks */
 	if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
-	   !elf_check_arch(elf_ex.e_machine) ||
-	   (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+	    !elf_check_arch(elf_ex.e_machine) ||
+	    (!inode->i_op || !inode->i_op->default_file_ops->mmap))
 		return -ENOEXEC;
-	
+
 	/* Now read in all of the header information */
-	
+
 	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
-		return -ENOEXEC;
-	
-	elf_phdata =  (struct elf_phdr *) 
-		kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+		 return -ENOEXEC;
+
+	elf_phdata = (struct elf_phdr *)
+	    kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
 	if (elf_phdata == NULL)
 		return -ENOMEM;
-	
+
 	retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
-	
+
 	j = 0;
-	for(i=0; i<elf_ex.e_phnum; i++)
-		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
-	
-	if (j != 1)  {
+	for (i = 0; i < elf_ex.e_phnum; i++)
+		if ((elf_phdata + i)->p_type == PT_LOAD)
+			j++;
+
+	if (j != 1) {
 		kfree(elf_phdata);
 		return -ENOEXEC;
 	}
-	
-	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-	
+	while (elf_phdata->p_type != PT_LOAD)
+		elf_phdata++;
+
 	/* Now use mmap to map the library into memory. */
 	error = do_mmap(file,
 			ELF_PAGESTART(elf_phdata->p_vaddr),
@@ -813,21 +814,21 @@
 			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
 
 	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
-	if (k > elf_bss) elf_bss = k;
-	
+	if (k > elf_bss)
+		elf_bss = k;
+
 	if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
 		kfree(elf_phdata);
 		return error;
 	}
-
 	padzero(elf_bss);
 
-	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
+	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_EXEC_PAGESIZE - 1);
 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
 	if (bss > len)
-	  do_mmap(NULL, len, bss-len,
-		  PROT_READ|PROT_WRITE|PROT_EXEC,
-		  MAP_FIXED|MAP_PRIVATE, 0);
+		do_mmap(NULL, len, bss - len,
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE, 0);
 	kfree(elf_phdata);
 	return 0;
 }
@@ -882,12 +883,12 @@
  */
 static inline int maydump(struct vm_area_struct *vma)
 {
-	if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
+	if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 		return 0;
 #if 1
-	if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
+	if (vma->vm_flags & (VM_WRITE | VM_GROWSUP | VM_GROWSDOWN))
 		return 1;
-	if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
+	if (vma->vm_flags & (VM_READ | VM_EXEC | VM_EXECUTABLE | VM_SHARED))
 		return 0;
 #endif
 	return 1;
@@ -896,8 +897,7 @@
 #define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
 
 /* An ELF note in memory */
-struct memelfnote
-{
+struct memelfnote {
 	const char *name;
 	int type;
 	unsigned int datasz;
@@ -907,32 +907,33 @@
 static int notesize(struct memelfnote *en)
 {
 	int sz;
-	
+
 	sz = sizeof(struct elf_note);
 	sz += roundup(strlen(en->name), 4);
 	sz += roundup(en->datasz, 4);
-	
+
 	return sz;
 }
 
 /* #define DEBUG */
 
 #ifdef DEBUG
-static void dump_regs(const char *str, elf_greg_t *r)
+static void dump_regs(const char *str, elf_greg_t * r)
 {
 	int i;
-	static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp",
-					      "eax", "ds", "es", "fs", "gs",
-					      "orig_eax", "eip", "cs",
-					      "efl", "uesp", "ss"};
+	static const char *regs[] =
+	{"ebx", "ecx", "edx", "esi", "edi", "ebp",
+	 "eax", "ds", "es", "fs", "gs",
+	 "orig_eax", "eip", "cs",
+	 "efl", "uesp", "ss"};
 	printk("Registers: %s\n", str);
 
-	for(i = 0; i < ELF_NGREG; i++)
-	{
+	for (i = 0; i < ELF_NGREG; i++) {
 		unsigned long val = r[i];
 		printk("   %-2d %-5s=%08lx %lu\n", i, regs[i], val, val);
 	}
 }
+
 #endif
 
 #define DUMP_WRITE(addr, nr)	\
@@ -951,10 +952,10 @@
 	DUMP_WRITE(&en, sizeof(en));
 	DUMP_WRITE(men->name, en.n_namesz);
 	/* XXX - cast from long long to long to avoid need for libgcc.a */
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+	DUMP_SEEK(roundup((unsigned long) file->f_pos, 4));	/* XXX */
 	DUMP_WRITE(men->data, men->datasz);
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
-	
+	DUMP_SEEK(roundup((unsigned long) file->f_pos, 4));	/* XXX */
+
 	return 1;
 }
 #undef DUMP_WRITE
@@ -973,13 +974,13 @@
  * and then they are actually written out.  If we run out of core limit
  * we just truncate.
  */
-static int elf_core_dump(long signr, struct pt_regs * regs)
+static int elf_core_dump(long signr, struct pt_regs *regs)
 {
 	int has_dumped = 0;
 	struct file file;
 	struct inode *inode;
 	unsigned short fs;
-	char corefile[6+sizeof(current->comm)];
+	char corefile[6 + sizeof(current->comm)];
 	int segs;
 	int i;
 	size_t size;
@@ -990,9 +991,9 @@
 	int numnote = 4;
 	struct memelfnote notes[4];
 	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
-	elf_fpregset_t fpu;		/* NT_PRFPREG */
+	elf_fpregset_t fpu;	/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
-	
+
 	if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
 		return 0;
 	current->dumpable = 0;
@@ -1004,17 +1005,15 @@
 	/* Count what's needed to dump, up to the limit of coredump size */
 	segs = 0;
 	size = 0;
-	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
-		if (maydump(vma))
-		{
-			int sz = vma->vm_end-vma->vm_start;
-		
-			if (size+sz >= limit)
+	for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+		if (maydump(vma)) {
+			int sz = vma->vm_end - vma->vm_start;
+
+			if (size + sz >= limit)
 				break;
 			else
 				size += sz;
 		}
-		
 		segs++;
 	}
 #ifdef DEBUG
@@ -1026,8 +1025,8 @@
 	elf.e_ident[EI_CLASS] = ELF_CLASS;
 	elf.e_ident[EI_DATA] = ELF_DATA;
 	elf.e_ident[EI_VERSION] = EV_CURRENT;
-	memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-	
+	memset(elf.e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD);
+
 	elf.e_type = ET_CORE;
 	elf.e_machine = ELF_ARCH;
 	elf.e_version = EV_CURRENT;
@@ -1037,20 +1036,20 @@
 	elf.e_flags = 0;
 	elf.e_ehsize = sizeof(elf);
 	elf.e_phentsize = sizeof(struct elf_phdr);
-	elf.e_phnum = segs+1;		/* Include notes */
+	elf.e_phnum = segs + 1;	/* Include notes */
 	elf.e_shentsize = 0;
 	elf.e_shnum = 0;
 	elf.e_shstrndx = 0;
-	
+
 	fs = get_fs();
 	set_fs(KERNEL_DS);
-	memcpy(corefile,"core.",5);
+	memcpy(corefile, "core.", 5);
 #if 0
-	memcpy(corefile+5,current->comm,sizeof(current->comm));
+	memcpy(corefile + 5, current->comm, sizeof(current->comm));
 #else
 	corefile[4] = '\0';
 #endif
-	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+	if (open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600, &inode, NULL)) {
 		inode = NULL;
 		goto end_coredump;
 	}
@@ -1066,7 +1065,7 @@
 	file.f_reada = 0;
 	file.f_op = inode->i_op->default_file_ops;
 	if (file.f_op->open)
-		if (file.f_op->open(inode,&file))
+		if (file.f_op->open(inode, &file))
 			goto end_coredump;
 	if (!file.f_op->write)
 		goto close_coredump;
@@ -1074,8 +1073,8 @@
 	current->flags |= PF_DUMPCORE;
 
 	DUMP_WRITE(&elf, sizeof(elf));
-	offset += sizeof(elf);				/* Elf header */
-	offset += (segs+1) * sizeof(struct elf_phdr);	/* Program headers */
+	offset += sizeof(elf);	/* Elf header */
+	offset += (segs + 1) * sizeof(struct elf_phdr);		/* Program headers */
 
 	/*
 	 * Set up the notes in similar form to SVR4 core dumps made
@@ -1111,18 +1110,16 @@
 #ifdef ELF_CORE_COPY_REGS
 	ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
 #else
-	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
-	{
+	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) {
 		printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n",
-			sizeof(elf_gregset_t), sizeof(struct pt_regs));
-	}
-	else
-		*(struct pt_regs *)&prstatus.pr_reg = *regs;
+		       sizeof(elf_gregset_t), sizeof(struct pt_regs));
+	} else
+		*(struct pt_regs *) &prstatus.pr_reg = *regs;
 #endif
-	
+
 #ifdef DEBUG
-	dump_regs("Passed in regs", (elf_greg_t *)regs);
-	dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg);
+	dump_regs("Passed in regs", (elf_greg_t *) regs);
+	dump_regs("prstatus regs", (elf_greg_t *) & prstatus.pr_reg);
 #endif
 
 	notes[1].name = "CORE";
@@ -1132,7 +1129,7 @@
 	psinfo.pr_state = current->state;
 	psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
 	psinfo.pr_zomb = psinfo.pr_sname == 'Z';
-	psinfo.pr_nice = current->priority-15;
+	psinfo.pr_nice = current->priority - 15;
 	psinfo.pr_flag = current->flags;
 	psinfo.pr_uid = current->uid;
 	psinfo.pr_gid = current->gid;
@@ -1140,12 +1137,12 @@
 		int i, len;
 
 		set_fs(fs);
-		
+
 		len = current->mm->arg_end - current->mm->arg_start;
-		len = (len >= ELF_PRARGSZ-1) ? ELF_PRARGSZ-1 : len;
+		len = (len >= ELF_PRARGSZ - 1) ? ELF_PRARGSZ - 1 : len;
 		memcpy_fromfs(&psinfo.pr_psargs,
-			      (const char *)current->mm->arg_start, len);
-		for(i = 0; i < len; i++)
+			      (const char *) current->mm->arg_start, len);
+		for (i = 0; i < len; i++)
 			if (psinfo.pr_psargs[i] == 0)
 				psinfo.pr_psargs[i] = ' ';
 		psinfo.pr_psargs[len] = 0;
@@ -1158,29 +1155,26 @@
 	notes[2].type = NT_TASKSTRUCT;
 	notes[2].datasz = sizeof(*current);
 	notes[2].data = current;
-	
+
 	/* Try to dump the fpu. */
-	prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
-	if (!prstatus.pr_fpvalid)
-	{
+	prstatus.pr_fpvalid = dump_fpu(regs, &fpu);
+	if (!prstatus.pr_fpvalid) {
 		numnote--;
-	}
-	else
-	{
+	} else {
 		notes[3].name = "CORE";
 		notes[3].type = NT_PRFPREG;
 		notes[3].datasz = sizeof(fpu);
 		notes[3].data = &fpu;
 	}
-	
+
 	/* Write notes phdr entry */
 	{
 		struct elf_phdr phdr;
 		int sz = 0;
 
-		for(i = 0; i < numnote; i++)
+		for (i = 0; i < numnote; i++)
 			sz += notesize(&notes[i]);
-		
+
 		phdr.p_type = PT_NOTE;
 		phdr.p_offset = offset;
 		phdr.p_vaddr = 0;
@@ -1196,17 +1190,17 @@
 
 	/* Page-align dumped data */
 	dataoff = offset = roundup(offset, PAGE_SIZE);
-	
+
 	/* Write program headers for segments dump */
-	for(vma = current->mm->mmap, i = 0;
-		i < segs && vma != NULL; vma = vma->vm_next) {
+	for (vma = current->mm->mmap, i = 0;
+	     i < segs && vma != NULL; vma = vma->vm_next) {
 		struct elf_phdr phdr;
 		size_t sz;
 
 		i++;
 
 		sz = vma->vm_end - vma->vm_start;
-		
+
 		phdr.p_type = PT_LOAD;
 		phdr.p_offset = offset;
 		phdr.p_vaddr = vma->vm_start;
@@ -1215,34 +1209,36 @@
 		phdr.p_memsz = sz;
 		offset += phdr.p_filesz;
 		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
-		if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
-		if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+		if (vma->vm_flags & VM_WRITE)
+			phdr.p_flags |= PF_W;
+		if (vma->vm_flags & VM_EXEC)
+			phdr.p_flags |= PF_X;
 		phdr.p_align = PAGE_SIZE;
 
 		DUMP_WRITE(&phdr, sizeof(phdr));
 	}
 
-	for(i = 0; i < numnote; i++)
+	for (i = 0; i < numnote; i++)
 		if (!writenote(&notes[i], &file))
 			goto close_coredump;
-	
+
 	set_fs(fs);
 
 	DUMP_SEEK(dataoff);
-	
-	for(i = 0, vma = current->mm->mmap;
-	    i < segs && vma != NULL;
-	    vma = vma->vm_next) {
+
+	for (i = 0, vma = current->mm->mmap;
+	     i < segs && vma != NULL;
+	     vma = vma->vm_next) {
 		unsigned long addr = vma->vm_start;
 		unsigned long len = vma->vm_end - vma->vm_start;
-		
+
 		i++;
 		if (!maydump(vma))
 			continue;
 #ifdef DEBUG
 		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
 #endif
-		DUMP_WRITE((void *)addr, len);
+		DUMP_WRITE((void *) addr, len);
 	}
 
 	if ((off_t) file.f_pos != offset) {
@@ -1250,12 +1246,11 @@
 		printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
 		       (off_t) file.f_pos, offset);
 	}
-
- close_coredump:
+      close_coredump:
 	if (file.f_op->release)
-		file.f_op->release(inode,&file);
+		file.f_op->release(inode, &file);
 
- end_coredump:
+      end_coredump:
 	set_fs(fs);
 	iput(inode);
 #ifndef CONFIG_BINFMT_ELF
@@ -1263,16 +1258,16 @@
 #endif
 	return has_dumped;
 }
-#endif		/* USE_ELF_CORE_DUMP */
+#endif				/* USE_ELF_CORE_DUMP */
 
-int init_elf_binfmt(void) 
+int init_elf_binfmt(void)
 {
 	return register_binfmt(&elf_format);
 }
 
 #ifdef MODULE
 
-int init_module(void) 
+int init_module(void)
 {
 	/* Install the COFF, ELF and XOUT loaders.
 	 * N.B. We *rely* on the table being the right size with the
@@ -1282,9 +1277,10 @@
 }
 
 
-void cleanup_module( void) 
+void cleanup_module(void)
 {
 	/* Remove the COFF and ELF loaders. */
 	unregister_binfmt(&elf_format);
 }
+
 #endif
diff -u --recursive --new-file v2.0.33/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c
--- v2.0.33/linux/fs/binfmt_em86.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/binfmt_em86.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,131 @@
+/*
+ *  linux/fs/binfmt_em86.c
+ *
+ *  Based on linux/fs/binfmt_script.c
+ *  Copyright (C) 1996  Martin von Löwis
+ *  original #!-checking implemented by tytso.
+ *
+ *  em86 changes Copyright (C) 1997  Jim Paradis
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+#include <linux/elf.h>
+
+#define EM86_INTERP	"/usr/bin/em86"
+#define EM86_I_NAME	"em86"
+
+static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+	char *cp, *interp, *i_name, *i_arg;
+	int retval;
+	struct elfhdr	elf_ex;
+	uid_t		x86_uid;
+	gid_t		x86_gid;
+
+	/* Make sure this is a Linux/Intel ELF executable... */
+	elf_ex = *((struct elfhdr *)bprm->buf);
+	
+        if (elf_ex.e_ident[0] != 0x7f ||
+            strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
+                return  -ENOEXEC;
+        }
+
+
+        /* First of all, some simple consistency checks */
+        if ((elf_ex.e_type != ET_EXEC &&
+            elf_ex.e_type != ET_DYN) ||
+           (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
+           (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+            !bprm->inode->i_op->default_file_ops->mmap)){
+                return -ENOEXEC;
+        }
+
+	bprm->sh_bang++;	/* Well, the bang-shell is implicit... */
+	iput(bprm->inode);
+	bprm->dont_iput = 1;
+
+	/* Unlike in the script case, we don't have to do any hairy
+	 * parsing to find our interpreter... it's hardcoded!
+	 */
+	interp = EM86_INTERP;
+	i_name = EM86_I_NAME;
+	i_arg = NULL;		/* We reserve the right to add an arg later */
+
+	/*
+	 * Splice in (1) the interpreter's name for argv[0]
+	 *           (2) (optional) argument to interpreter
+	 *           (3) filename of emulated file (replace argv[0])
+	 *
+	 * This is done in reverse order, because of how the
+	 * user environment and arguments are stored.
+	 */
+	remove_arg_zero(bprm);
+	bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+	bprm->argc++;
+	if (i_arg) {
+		bprm->p = copy_strings(1, &i_arg, bprm->page, bprm->p, 2);
+		bprm->argc++;
+	}
+	bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
+	bprm->argc++;
+	if (!bprm->p) 
+		return -E2BIG;
+	/*
+	 * OK, now restart the process with the interpreter's inode.
+	 * Note that we use open_namei() as the name is now in kernel
+	 * space, and we don't need to copy it.
+	 */
+	retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
+	if (retval)
+		return retval;
+	bprm->dont_iput=0;
+
+	/* Remember the uid/gid that was set by this executable */
+	x86_uid = bprm->e_uid;
+	x86_gid = bprm->e_gid;
+	retval=prepare_binprm(bprm);
+	if(retval<0)
+		return retval;
+
+	/* ...so that we may propagate them to em86 */
+	bprm->e_uid = x86_uid;
+	bprm->e_gid = x86_gid;
+	current->personality = PER_LINUX_EM86;
+	return search_binary_handler(bprm,regs);
+}
+
+static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+	int retval;
+	MOD_INC_USE_COUNT;
+	retval = do_load_em86(bprm,regs);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+struct linux_binfmt em86_format = {
+#ifndef MODULE
+	NULL, 0, load_em86, NULL, NULL
+#else
+	NULL, &mod_use_count_, load_em86, NULL, NULL
+#endif
+};
+
+int init_em86_binfmt(void) {
+	return register_binfmt(&em86_format);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_em86_binfmt();
+}
+
+void cleanup_module( void) {
+	unregister_binfmt(&em86_format);
+}
+#endif
diff -u --recursive --new-file v2.0.33/linux/fs/buffer.c linux/fs/buffer.c
--- v2.0.33/linux/fs/buffer.c	Tue Mar 10 13:19:09 1998
+++ linux/fs/buffer.c	Wed Jun  3 15:17:49 1998
@@ -1249,6 +1249,8 @@
 
 	clear_bit(BH_Lock, &bh->b_state);
 	wake_up(&bh->b_wait);
+	if (waitqueue_active(&buffer_wait))
+		wake_up(&buffer_wait);
 
 	if (!test_bit(BH_FreeOnIO, &bh->b_state))
 		return;
diff -u --recursive --new-file v2.0.33/linux/fs/devices.c linux/fs/devices.c
--- v2.0.33/linux/fs/devices.c	Sun May 12 21:36:19 1996
+++ linux/fs/devices.c	Wed Jun  3 15:17:49 1998
@@ -227,6 +227,10 @@
 int blkdev_open(struct inode * inode, struct file * filp)
 {
 	int ret = -ENODEV;
+
+	if (securelevel > 0 && (filp->f_mode & FMODE_WRITE))
+		return -EACCES; /* cevans */
+
 	filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
 	if (filp->f_op != NULL){
 		ret = 0;
diff -u --recursive --new-file v2.0.33/linux/fs/dquot.c linux/fs/dquot.c
--- v2.0.33/linux/fs/dquot.c	Sun Aug  3 15:31:34 1997
+++ linux/fs/dquot.c	Wed Jun  3 15:17:49 1998
@@ -17,7 +17,7 @@
  * 
  * Author:  Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net>
  * 
- * Fixes:   Dmitry Gorodchanin <begemot@bgm.rosprint.net>, 11 Feb 96
+ * Fixes:   Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96
  *	    removed race conditions in dqput(), dqget() and iput(). 
  *          Nick Kralevich <nickkral@cal.alumni.berkeley.edu>, 21 Jul 97
  *          Fixed a condition where user and group quotas could get mixed up.
@@ -231,8 +231,13 @@
 			unlock_dquot(dquot);
 			return;
 		}
-	} else
-		filp->f_pos = dqoff(dquot->dq_id);
+	}
+	else
+	{
+		int p = dqoff(dquot->dq_id);
+		if(p>=0)
+			filp->f_pos = p;
+	}
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	if (filp->f_op->write(filp->f_inode, filp,
@@ -1074,6 +1079,9 @@
 		default:
 			return(-EINVAL);
 	}
+
+	if (id & ~0xFFFF)
+		return(-EINVAL);
 
 	flags |= QUOTA_SYSCALL;
 	if (has_quota_enabled(dev, type))
diff -u --recursive --new-file v2.0.33/linux/fs/ext/freelists.c linux/fs/ext/freelists.c
--- v2.0.33/linux/fs/ext/freelists.c	Sat Nov 30 02:21:19 1996
+++ linux/fs/ext/freelists.c	Wed Jun  3 15:17:49 1998
@@ -188,7 +188,7 @@
 		return;
 	}
 	if (inode->i_count != 1) {
-		printk("free_inode: inode has count=%d\n",inode->i_count);
+		printk("free_inode: inode has count=%ld\n",inode->i_count);
 		return;
 	}
 	if (inode->i_nlink) {
diff -u --recursive --new-file v2.0.33/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.0.33/linux/fs/ext2/file.c	Tue Feb 20 00:28:13 1996
+++ linux/fs/ext2/file.c	Wed Jun  3 15:17:49 1998
@@ -33,9 +33,6 @@
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-
 static int ext2_file_write (struct inode *, struct file *, const char *, int);
 static void ext2_release_file (struct inode *, struct file *);
 
diff -u --recursive --new-file v2.0.33/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.0.33/linux/fs/ext2/ialloc.c	Sat Aug 16 16:23:19 1997
+++ linux/fs/ext2/ialloc.c	Wed Jun  3 15:17:49 1998
@@ -196,7 +196,7 @@
 		return;
 	}
 	if (inode->i_count > 1) {
-		printk ("ext2_free_inode: inode has count=%d\n",
+		printk ("ext2_free_inode: inode has count=%ld\n",
 			inode->i_count);
 		return;
 	}
diff -u --recursive --new-file v2.0.33/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.0.33/linux/fs/ext2/namei.c	Mon Aug  4 12:30:53 1997
+++ linux/fs/ext2/namei.c	Wed Jun  3 15:17:49 1998
@@ -573,12 +573,13 @@
 	    	ext2_warning (inode->i_sb, "empty_dir",
 			      "bad directory (dir #%lu) - no `.' or `..'",
 			      inode->i_ino);
+		brelse (bh);
 		return 1;
 	}
 	offset = de->rec_len + de1->rec_len;
 	de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len);
 	while (offset < inode->i_size ) {
-		if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
+		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
 			brelse (bh);
 			bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
 			if (!bh) {
diff -u --recursive --new-file v2.0.33/linux/fs/fat/buffer.c linux/fs/fat/buffer.c
--- v2.0.33/linux/fs/fat/buffer.c	Thu May  9 21:54:52 1996
+++ linux/fs/fat/buffer.c	Wed Jun  3 15:17:49 1998
@@ -10,12 +10,19 @@
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
 
+#if 0
+#  define PRINTK(x) printk x
+#else
+#  define PRINTK(x)
+#endif
+
 struct buffer_head *fat_bread (
 	struct super_block *sb,
 	int block)
 {
 	struct buffer_head *ret = NULL;
 
+	PRINTK(("fat_bread: block=0x%x\n", block));
 	/* Note that the blocksize is 512 or 1024, but the first read
 	   is always of size 1024. Doing readahead may be counterproductive
 	   or just plain wrong. */
@@ -73,6 +80,7 @@
 	int block)
 {
 	struct buffer_head *ret = NULL;
+	PRINTK(("fat_getblk: block=0x%x\n", block));
 	if (sb->s_blocksize == 512){
 		ret = getblk (sb->s_dev,block,512);
 	}else{
diff -u --recursive --new-file v2.0.33/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.0.33/linux/fs/fat/cache.c	Thu May  9 21:54:52 1996
+++ linux/fs/fat/cache.c	Wed Jun  3 15:17:49 1998
@@ -12,6 +12,11 @@
 
 #include "msbuffer.h"
 
+#if 0
+#  define PRINTK(x) printk x
+#else
+#  define PRINTK(x)
+#endif
 
 static struct fat_cache *fat_cache,cache[FAT_CACHE];
 
@@ -22,11 +27,13 @@
 {
 	struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
 	unsigned char *p_first,*p_last;
-	int first,last,next,copy,b;
+	int copy,first,last,next,b;
 
 	if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
 		return 0;
-	if (MSDOS_SB(sb)->fat_bits == 16) {
+	if (MSDOS_SB(sb)->fat_bits == 32) {
+		first = last = nr*4;
+	} else if (MSDOS_SB(sb)->fat_bits == 16) {
 		first = last = nr*2;
 	} else {
 		first = nr*3/2;
@@ -46,13 +53,19 @@
 			return 0;
 		}
 	}
-	if (MSDOS_SB(sb)->fat_bits == 16) {
+	if (MSDOS_SB(sb)->fat_bits == 32) {
+		p_first = p_last = NULL; /* GCC needs that stuff */
+		next = CF_LE_L(((unsigned long *) bh->b_data)[(first &
+		    (SECTOR_SIZE-1)) >> 2]);
+		if (next >= 0xffffff7) next = -1;
+		PRINTK(("fat_bread: 0x%x, nr=0x%x, first=0x%x, next=0x%d\n", b, nr, first, next));
+
+	} else if (MSDOS_SB(sb)->fat_bits == 16) {
 		p_first = p_last = NULL; /* GCC needs that stuff */
 		next = CF_LE_W(((unsigned short *) bh->b_data)[(first &
 		    (SECTOR_SIZE-1)) >> 1]);
 		if (next >= 0xfff7) next = -1;
-	}
-	else {
+	} else {
 		p_first = &((unsigned char *) bh->b_data)[first & (SECTOR_SIZE-1)];
 		p_last = &((unsigned char *) bh2->b_data)[(first+1) &
 		    (SECTOR_SIZE-1)];
@@ -61,10 +74,13 @@
 		if (next >= 0xff7) next = -1;
 	}
 	if (new_value != -1) {
-		if (MSDOS_SB(sb)->fat_bits == 16)
+		if (MSDOS_SB(sb)->fat_bits == 32) {
+			((unsigned long *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
+			    2] = CT_LE_L(new_value);
+		} else if (MSDOS_SB(sb)->fat_bits == 16) {
 			((unsigned short *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
 			    1] = CT_LE_W(new_value);
-		else {
+		} else {
 			if (nr & 1) {
 				*p_first = (*p_first & 0xf) | (new_value << 4);
 				*p_last = new_value >> 4;
@@ -239,16 +255,17 @@
 	return nr;
 }
 
-
 int fat_smap(struct inode *inode,int sector)
 {
 	struct msdos_sb_info *sb;
 	int cluster,offset;
 
 	sb = MSDOS_SB(inode->i_sb);
-	if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
-	    !MSDOS_I(inode)->i_start)) {
-		if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0;
+	if ((sb->fat_bits != 32) &&
+	    (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
+	     !MSDOS_I(inode)->i_start))) {
+		if (sector >= sb->dir_entries >> MSDOS_DPS_BITS)
+			return 0;
 		return sector+sb->dir_start;
 	}
 	cluster = sector/sb->cluster_size;
@@ -264,6 +281,7 @@
 int fat_free(struct inode *inode,int skip)
 {
 	int nr,last;
+	int fat_bits;
 
 	if (!(nr = MSDOS_I(inode)->i_start)) return 0;
 	last = 0;
@@ -275,11 +293,13 @@
 			return -EIO;
 		}
 	}
-	if (last)
-		fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
-		    12 ? 0xff8 : 0xfff8);
-	else {
+	if (last) {
+		fat_bits = MSDOS_SB(inode->i_sb)->fat_bits;
+		fat_access(inode->i_sb,last,fat_bits == 12 ? EOF_FAT12 :
+			   fat_bits == 16 ? EOF_FAT16 : EOF_FAT32);
+	} else {
 		MSDOS_I(inode)->i_start = 0;
+		MSDOS_I(inode)->i_logstart = 0;
 		inode->i_dirt = 1;
 	}
 	lock_fat(inode->i_sb);
@@ -288,8 +308,12 @@
 			fat_fs_panic(inode->i_sb,"fat_free: deleting beyond EOF");
 			break;
 		}
-		if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
+		if (MSDOS_SB(inode->i_sb)->free_clusters != -1) {
 			MSDOS_SB(inode->i_sb)->free_clusters++;
+			if (MSDOS_SB(inode->i_sb)->fat_bits == 32) {
+				fat_clusters_flush(inode->i_sb);
+			}
+		}
 		inode->i_blocks -= MSDOS_SB(inode->i_sb)->cluster_size;
 	}
 	unlock_fat(inode->i_sb);
diff -u --recursive --new-file v2.0.33/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.0.33/linux/fs/fat/dir.c	Thu May  9 21:54:52 1996
+++ linux/fs/fat/dir.c	Wed Jun  3 15:17:49 1998
@@ -11,8 +11,12 @@
  *  Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
  */
 
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+
+#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
+#include <linux/nls.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
@@ -21,15 +25,28 @@
 #include <linux/dirent.h>
 #include <linux/mm.h>
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+#include <asm/uaccess.h>
+#define FAT_GET_USER(len, addr) get_user(len, addr)
+#define FAT_COPY_TO_USER(uaddr, kaddr, len) copy_to_user(uaddr, kaddr, len)
+#else
 #include <asm/segment.h>
+#define FAT_GET_USER(len, addr) (len) = get_user(addr)
+#define FAT_COPY_TO_USER(uaddr, kaddr, len) memcpy_tofs(uaddr, kaddr, len)
+#endif
 
 #include "msbuffer.h"
-#include "tables.h"
 
 
 #define PRINTK(X)
 
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+static long fat_dir_read(struct inode * inode,struct file * filp,
+			 char * buf,unsigned long count)
+#else
 static int fat_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
+#endif
 {
 	return -EISDIR;
 }
@@ -39,7 +56,7 @@
 	fat_dir_read,		/* read */
 	NULL,			/* write - bad */
 	fat_readdir,		/* readdir */
-	NULL,			/* select - default */
+	NULL,			/* select v2.0.x/poll v2.1.x - default */
 	fat_dir_ioctl,		/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
@@ -47,7 +64,9 @@
 	file_fsync		/* fsync */
 };
 
-/* Convert Unicode string to ASCII.  If uni_xlate is enabled and we
+/*
+ * Convert Unicode 16 to UTF8, translated unicode, or ascii.
+ * If uni_xlate is enabled and we
  * can't get a 1:1 conversion, use a colon as an escape character since
  * it is normally invalid on the vfat filesystem.  The following three
  * characters are a sort of uuencoded 16 bit Unicode value.  This lets
@@ -55,10 +74,11 @@
  * into some trouble with long Unicode names, but ignore that right now.
  */
 static int
-uni2ascii(unsigned char *uni, unsigned char *ascii, int uni_xlate)
+uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
+	    struct nls_table *nls)
 {
 	unsigned char *ip, *op;
-	unsigned char page, pg_off;
+	unsigned char ch, cl;
 	unsigned char *uni_page;
 	unsigned short val;
 
@@ -66,21 +86,21 @@
 	op = ascii;
 
 	while (*ip || ip[1]) {
-		pg_off = *ip++;
-		page = *ip++;
-		
-		uni_page = fat_uni2asc_pg[page];
-		if (uni_page && uni_page[pg_off]) {
-			*op++ = uni_page[pg_off];
+		cl = *ip++;
+		ch = *ip++;
+
+		uni_page = nls->page_uni2charset[ch];
+		if (uni_page && uni_page[cl]) {
+			*op++ = uni_page[cl];
 		} else {
 			if (uni_xlate == 1) {
 				*op++ = ':';
-				val = (pg_off << 8) + page;
-				op[2] = fat_uni2code[val & 0x3f];
+				val = (cl << 8) + ch;
+				op[2] = fat_uni2esc[val & 0x3f];
 				val >>= 6;
-				op[1] = fat_uni2code[val & 0x3f];
+				op[1] = fat_uni2esc[val & 0x3f];
 				val >>= 6;
-				*op = fat_uni2code[val & 0x3f];
+				*op = fat_uni2esc[val & 0x3f];
 				op += 3;
 			} else {
 				*op++ = '?';
@@ -91,6 +111,7 @@
 	return (op - ascii);
 }
 
+
 int fat_readdirx(
 	struct inode *inode,
 	struct file *filp,
@@ -114,7 +135,9 @@
 	unsigned char alias_checksum = 0; /* Make compiler warning go away */
 	unsigned char long_slots = 0;
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
+	int utf8 = MSDOS_SB(sb)->options.utf8;
 	unsigned char *unicode = NULL;
+	struct nls_table *nls = MSDOS_SB(sb)->nls_io;
 
 	if (!inode || !S_ISDIR(inode->i_mode))
 		return -EBADF;
@@ -213,10 +236,10 @@
 			char bufname[14];
 			char *ptname = bufname;
 			int dotoffset = 0;
+			int was_long = is_long;
 
 			if (is_long) {
 				unsigned char sum;
-				long_len = uni2ascii(unicode, longname, uni_xlate);
 				for (sum = 0, i = 0; i < 11; i++) {
 					sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
 				}
@@ -225,6 +248,11 @@
 					PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
 					is_long = 0;
 				}
+				if (utf8) {
+					long_len = utf8_wcstombs(longname, (__u16 *) unicode, sizeof(longname));
+				} else {
+					long_len = uni16_to_x8(longname, unicode, uni_xlate, nls);
+				}
 			}
 
 			if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
@@ -264,7 +292,7 @@
 						bufname[i+dotoffset] = '\0';
 					}
 					spos = oldpos;
-					if (is_long) {
+					if (was_long) {
 						spos = filp->f_pos - sizeof(struct msdos_dir_entry);
 					} else {
 						long_slots = 0;
@@ -343,7 +371,8 @@
 	int len, slen;
 	int dotdir;
 
-	if (get_user(&d1->d_reclen) != 0) {
+	FAT_GET_USER(len, &d1->d_reclen);
+	if (len != 0) {
 		return -1;
 	}
 
@@ -356,19 +385,19 @@
 		len = strlen(name);
 	}
 	if (len != name_len) {
-		memcpy_tofs(d2->d_name, name, len);
+		FAT_COPY_TO_USER(d2->d_name, name, len);
 		put_user(0, d2->d_name + len);
 		put_user(len, &d2->d_reclen);
 		put_user(ino, &d2->d_ino);
 		put_user(offset, &d2->d_off);
 		slen = name_len - len;
-		memcpy_tofs(d1->d_name, name+len+1, slen);
+		FAT_COPY_TO_USER(d1->d_name, name+len+1, slen);
 		put_user(0, d1->d_name+slen);
 		put_user(slen, &d1->d_reclen);
 	} else {
 		put_user(0, d2->d_name);
 		put_user(0, &d2->d_reclen);
-		memcpy_tofs(d1->d_name, name, len);
+		FAT_COPY_TO_USER(d1->d_name, name, len);
 		put_user(0, d1->d_name+len);
 		put_user(len, &d1->d_reclen);
 	}
@@ -391,7 +420,7 @@
 	switch (cmd) {
 	case VFAT_IOCTL_READDIR_BOTH: {
 		struct dirent *d1 = (struct dirent *)arg;
-		err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+		err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
 		if (err)
 			return err;
 		put_user(0, &d1->d_reclen);
@@ -401,7 +430,7 @@
 	case VFAT_IOCTL_READDIR_SHORT: {
 		struct dirent *d1 = (struct dirent *)arg;
 		put_user(0, &d1->d_reclen);
-		err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+		err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
 		if (err)
 			return err;
 		return fat_readdirx(inode,filp,(void *)arg,
diff -u --recursive --new-file v2.0.33/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.0.33/linux/fs/fat/fatfs_syms.c	Tue Mar  5 03:03:26 1996
+++ linux/fs/fat/fatfs_syms.c	Wed Jun  3 15:17:49 1998
@@ -4,55 +4,65 @@
  * Exported kernel symbols for the low-level FAT-based fs support.
  *
  */
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/mm.h>
 #include <linux/msdos_fs.h>
 
 #include "msbuffer.h"
-#include "tables.h"
 
 extern struct file_operations fat_dir_operations;
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+#define X(sym) EXPORT_SYMBOL(sym);
+#define X_PUNCT ;
+#else
+#define X_PUNCT ,
 static struct symbol_table fat_syms = {
 #include <linux/symtab_begin.h>
-	X(fat_a2alias),
-	X(fat_a2uni),
-	X(fat_add_cluster),
-	X(fat_bmap),
-	X(fat_brelse),
-	X(fat_cache_inval_inode),
-	X(fat_code2uni),
-	X(fat_date_unix2dos),
-	X(fat_dir_operations),
-	X(fat_file_read),
-	X(fat_file_write),
-	X(fat_fs_panic),
-	X(fat_get_entry),
-	X(fat_lock_creation),
-	X(fat_mark_buffer_dirty),
-	X(fat_mmap),
-	X(fat_notify_change),
-	X(fat_parent_ino),
-	X(fat_put_inode),
-	X(fat_put_super),
-	X(fat_read_inode),
-	X(fat_read_super),
-	X(fat_readdirx),
-	X(fat_readdir),
-	X(fat_scan),
-	X(fat_smap),
-	X(fat_statfs),
-	X(fat_truncate),
-	X(fat_uni2asc_pg),
-	X(fat_uni2code),
-	X(fat_unlock_creation),
-	X(fat_write_inode),
+#endif
+X(fat_add_cluster) X_PUNCT
+X(fat_bmap) X_PUNCT
+X(fat_brelse) X_PUNCT
+X(fat_cache_inval_inode) X_PUNCT
+X(fat_esc2uni) X_PUNCT
+X(fat_date_unix2dos) X_PUNCT
+X(fat_dir_operations) X_PUNCT
+X(fat_file_read) X_PUNCT
+X(fat_file_write) X_PUNCT
+X(fat_fs_panic) X_PUNCT
+X(fat_get_entry) X_PUNCT
+X(fat_lock_creation) X_PUNCT
+X(fat_mark_buffer_dirty) X_PUNCT
+X(fat_mmap) X_PUNCT
+X(fat_notify_change) X_PUNCT
+X(fat_parent_ino) X_PUNCT
+X(fat_put_inode) X_PUNCT
+X(fat_put_super) X_PUNCT
+X(fat_read_inode) X_PUNCT
+X(fat_read_super) X_PUNCT
+X(fat_readdirx) X_PUNCT
+X(fat_readdir) X_PUNCT
+X(fat_scan) X_PUNCT
+X(fat_smap) X_PUNCT
+X(fat_statfs) X_PUNCT
+X(fat_truncate) X_PUNCT
+X(fat_uni2esc) X_PUNCT
+X(fat_unlock_creation) X_PUNCT
+X(fat_write_inode) X_PUNCT
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
 #include <linux/symtab_end.h>
 };                                           
+#endif
 
 int init_fat_fs(void)
 {
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+	return 0;
+#else
 	return register_symtab(&fat_syms);
+#endif
 }
-
diff -u --recursive --new-file v2.0.33/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.0.33/linux/fs/fat/file.c	Thu May  9 21:54:52 1996
+++ linux/fs/fat/file.c	Wed Jun  3 15:17:49 1998
@@ -6,6 +6,8 @@
  *  regular file handling primitives for fat-based filesystems
  */
 
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/locks.h>
 #include <linux/fs.h>
@@ -16,7 +18,17 @@
 #include <linux/string.h>
 #include <linux/pagemap.h>
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+#include <asm/uaccess.h>
+#define FAT_COPY_TO_USER(uaddr, kaddr, len) copy_to_user(uaddr, kaddr, len)
+#define FAT_COPY_FROM_USER(uaddr, kaddr, len) copy_from_user(uaddr, kaddr, len)
+#define FAT_GET_USER(c, ptr) get_user((c), ptr)
+#else
 #include <asm/segment.h>
+#define FAT_COPY_TO_USER(uaddr, kaddr, len) memcpy_tofs(uaddr, kaddr, len)
+#define FAT_COPY_FROM_USER(uaddr, kaddr, len) memcpy_fromfs(uaddr, kaddr, len)
+#define FAT_GET_USER(c, ptr) (c) = get_user(ptr)
+#endif
 #include <asm/system.h>
 
 #include "msbuffer.h"
@@ -32,7 +44,7 @@
 	fat_file_read,		/* read */
 	fat_file_write,		/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* select v2.0.x/poll v2.1.x - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
@@ -71,7 +83,7 @@
 	fat_file_read,		/* read */
 	fat_file_write,		/* write */
 	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
+	NULL,			/* select v2.0.x/poll v2.1.x - default */
 	NULL,			/* ioctl - default */
 	fat_mmap,		/* mmap */
 	NULL,			/* no special open is needed */
@@ -152,11 +164,12 @@
 /*
 	Read a file into user space
 */
-int fat_file_read(
-	struct inode *inode,
-	struct file *filp,
-	char *buf,
-	int count)
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+long fat_file_read(struct inode *inode,struct file *filp,char *buf,
+		   unsigned long count)
+#else
+int fat_file_read(struct inode *inode,struct file *filp,char *buf,int count)
+#endif
 {
 	struct super_block *sb = inode->i_sb;
 	char *start = buf;
@@ -175,7 +188,11 @@
 		printk("fat_file_read: mode = %07o\n",inode->i_mode);
 		return -EINVAL;
 	}
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+	if (filp->f_pos >= inode->i_size || count == 0) return 0;
+#else
 	if (filp->f_pos >= inode->i_size || count <= 0) return 0;
+#endif
 	/*
 		Tell the buffer cache which block we expect to read in advance
 		Since we are limited with the stack, we preread only MSDOS_PREFETCH
@@ -238,7 +255,7 @@
 		size = MIN(SECTOR_SIZE-offset,left_in_file);
 		if (MSDOS_I(inode)->i_binary) {
 			size = MIN(size,end-buf);
-			memcpy_tofs(buf,data,size);
+			FAT_COPY_TO_USER(buf,data,size);
 			buf += size;
 			filp->f_pos += size;
 		}else{
@@ -269,11 +286,12 @@
 /*
 	Write to a file either from user space
 */
-int fat_file_write(
-	struct inode *inode,
-	struct file *filp,
-	const char *buf,
-	int count)
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+long fat_file_write(struct inode *inode,struct file *filp,const char *buf,
+		    unsigned long count)
+#else
+int fat_file_write(struct inode *inode,struct file *filp,const char *buf,int count)
+#endif
 {
 	struct super_block *sb = inode->i_sb;
 	int sector,offset,size,left,written;
@@ -301,8 +319,11 @@
  */
 	if (filp->f_flags & O_APPEND)
 		filp->f_pos = inode->i_size;
-	if (count <= 0)
-		return 0;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+	if (count == 0) return 0;
+#else
+	if (count <= 0) return 0;
+#endif
 	error = carry = 0;
 	for (start = buf; count || carry; count -= size) {
 		while (!(sector = fat_smap(inode,filp->f_pos >> SECTOR_BITS)))
@@ -329,7 +350,7 @@
 			break;
 		}
 		if (binary_mode) {
-			memcpy_fromfs(bh->b_data+offset,buf,written = size);
+			FAT_COPY_FROM_USER(bh->b_data+offset,buf,written = size);
 			buf += size;
 		} else {
 			written = left = SECTOR_SIZE-offset;
@@ -340,7 +361,8 @@
 				carry = 0;
 			}
 			for (size = 0; size < count && left; size++) {
-				if ((ch = get_user(buf++)) == '\n') {
+				FAT_GET_USER(ch, buf++);
+				if (ch == '\n') {
 					*to++ = '\r';
 					left--;
 				}
diff -u --recursive --new-file v2.0.33/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.0.33/linux/fs/fat/inode.c	Sat Nov 30 02:27:38 1996
+++ linux/fs/fat/inode.c	Wed Jun  3 15:17:49 1998
@@ -5,10 +5,13 @@
  *  VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner
  */
 
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/msdos_fs.h>
+#include <linux/nls.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -18,14 +21,24 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/locks.h>
+#include <linux/malloc.h>
 
 #include "msbuffer.h"
-#include "tables.h"
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+#include <asm/uaccess.h>
+#define FAT_COPY_TO_USER(uaddr, kaddr, len) copy_to_user(uaddr, kaddr, len)
+#else
 #include <asm/segment.h>
+#define FAT_COPY_TO_USER(uaddr, kaddr, len) memcpy_tofs(uaddr, kaddr, len)
+#endif
 #include <asm/unaligned.h>
 
-
+#if 0
+#  define PRINTK(x) printk x
+#else
+#  define PRINTK(x)
+#endif
 
 void fat_put_inode(struct inode *inode)
 {
@@ -75,8 +88,22 @@
 
 void fat_put_super(struct super_block *sb)
 {
+	if (MSDOS_SB(sb)->fat_bits == 32) {
+		fat_clusters_flush(sb);
+	}
 	fat_cache_inval_dev(sb->s_dev);
 	set_blocksize (sb->s_dev,BLOCK_SIZE);
+	if (MSDOS_SB(sb)->nls_disk) {
+		unload_nls(MSDOS_SB(sb)->nls_disk);
+		MSDOS_SB(sb)->nls_disk = NULL;
+		MSDOS_SB(sb)->options.codepage = 0;
+	}
+	if (MSDOS_SB(sb)->nls_io) {
+		unload_nls(MSDOS_SB(sb)->nls_io);
+		MSDOS_SB(sb)->nls_io = NULL;
+		kfree(MSDOS_SB(sb)->options.iocharset);
+		MSDOS_SB(sb)->options.iocharset = NULL;
+	}
 	lock_super(sb);
 	sb->s_dev = 0;
 	unlock_super(sb);
@@ -88,27 +115,38 @@
 static int parse_options(char *options,int *fat, int *blksize, int *debug,
 			 struct fat_mount_options *opts)
 {
-	char *this_char,*value;
+	char *this_char,*value,save,*savep;
+	char *p;
+	int ret, len;
 
 	opts->name_check = 'n';
 	opts->conversion = 'b';
 	opts->fs_uid = current->uid;
 	opts->fs_gid = current->gid;
 	opts->fs_umask = current->fs->umask;
-	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = opts->isvfat = 0;
+	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0;
+	opts->codepage = 0;
+	opts->utf8 = 0;
+	opts->iocharset = NULL;
 	*debug = *fat = 0;
 
 	if (!options) return 1;
+	save = 0;
+	savep = NULL;
+	ret = 1;
 	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
-		if ((value = strchr(this_char,'=')) != NULL)
+		if ((value = strchr(this_char,'=')) != NULL) {
+			save = *value;
+			savep = value;
 			*value++ = 0;
+		}
 		if (!strcmp(this_char,"check") && value) {
 			if (value[0] && !value[1] && strchr("rns",*value))
 				opts->name_check = *value;
 			else if (!strcmp(value,"relaxed")) opts->name_check = 'r';
 			else if (!strcmp(value,"normal")) opts->name_check = 'n';
 			else if (!strcmp(value,"strict")) opts->name_check = 's';
-			else return 0;
+			else ret = 0;
 		}
 		else if (!strcmp(this_char,"conv") && value) {
 			if (value[0] && !value[1] && strchr("bta",*value))
@@ -116,7 +154,7 @@
 			else if (!strcmp(value,"binary")) opts->conversion = 'b';
 			else if (!strcmp(value,"text")) opts->conversion = 't';
 			else if (!strcmp(value,"auto")) opts->conversion = 'a';
-			else return 0;
+			else ret = 0;
 		}
 		else if (!strcmp(this_char,"dots")) {
 			opts->dotsOK = 1;
@@ -130,72 +168,99 @@
 		else if (!strcmp(this_char,"dotsOK") && value) {
 			if (!strcmp(value,"yes")) opts->dotsOK = 1;
 			else if (!strcmp(value,"no")) opts->dotsOK = 0;
-			else return 0;
+			else ret = 0;
 		}
 		else if (!strcmp(this_char,"uid")) {
-			if (!value || !*value)
-				return 0;
-			opts->fs_uid = simple_strtoul(value,&value,0);
-			if (*value)
-				return 0;
+			if (!value || !*value) ret = 0;
+			else {
+				opts->fs_uid = simple_strtoul(value,&value,0);
+				if (*value) ret = 0;
+			}
 		}
 		else if (!strcmp(this_char,"gid")) {
-			if (!value || !*value)
-				return 0;
-			opts->fs_gid = simple_strtoul(value,&value,0);
-			if (*value)
-				return 0;
+			if (!value || !*value) ret= 0;
+			else {
+				opts->fs_gid = simple_strtoul(value,&value,0);
+				if (*value) ret = 0;
+			}
 		}
 		else if (!strcmp(this_char,"umask")) {
-			if (!value || !*value)
-				return 0;
-			opts->fs_umask = simple_strtoul(value,&value,8);
-			if (*value)
-				return 0;
+			if (!value || !*value) ret = 0;
+			else {
+				opts->fs_umask = simple_strtoul(value,&value,8);
+				if (*value) ret = 0;
+			}
 		}
 		else if (!strcmp(this_char,"debug")) {
-			if (value) return 0;
-			*debug = 1;
+			if (value) ret = 0;
+			else *debug = 1;
 		}
 		else if (!strcmp(this_char,"fat")) {
-			if (!value || !*value)
-				return 0;
-			*fat = simple_strtoul(value,&value,0);
-			if (*value || (*fat != 12 && *fat != 16))
-				return 0;
+			if (!value || !*value) ret = 0;
+			else {
+				*fat = simple_strtoul(value,&value,0);
+				if (*value || (*fat != 12 && *fat != 16 &&
+					       *fat != 32)) 
+					ret = 0;
+			}
 		}
 		else if (!strcmp(this_char,"quiet")) {
-			if (value) return 0;
-			opts->quiet = 1;
+			if (value) ret = 0;
+			else opts->quiet = 1;
 		}
 		else if (!strcmp(this_char,"blocksize")) {
 			*blksize = simple_strtoul(value,&value,0);
-			if (*value)
-				return 0;
-			if (*blksize != 512 && *blksize != 1024){
+			if (*value) ret = 0;
+			else if (*blksize != 512 && *blksize != 1024){
 				printk ("MSDOS FS: Invalid blocksize (512 or 1024)\n");
 			}
 		}
 		else if (!strcmp(this_char,"sys_immutable")) {
-			if (value)
-				return 0;
-			opts->sys_immutable = 1;
+			if (value) ret = 0;
+			else opts->sys_immutable = 1;
 		}
+		else if (!strcmp(this_char,"codepage")) {
+			opts->codepage = simple_strtoul(value,&value,0);
+			if (*value) ret = 0;
+			else printk ("MSDOS FS: Using codepage %d\n", opts->codepage);
+		}
+		else if (!strcmp(this_char,"iocharset")) {
+			p = value;
+			while (*value && *value != ',') value++;
+			len = value - p;
+			if (len) {
+				opts->iocharset = kmalloc(len+1, GFP_KERNEL);
+				memcpy(opts->iocharset, p, len);
+				opts->iocharset[len] = 0;
+				printk ("MSDOS FS: Using IO charset %s\n",
+					opts->iocharset);
+			} else {
+				opts->iocharset = NULL;
+				ret = 0;
+			}
+		}
+
+		if (this_char != options) *(this_char-1) = ',';
+		if (value) *savep = save;
+		if (ret == 0) return 0;
 	}
 	return 1;
 }
 
 
 /* Read the super block of an MS-DOS FS. */
-
+/* XXX: Make sure we handle the case of no codepage (unable to load) */
 struct super_block *fat_read_super(struct super_block *sb,void *data, int silent)
 {
 	struct buffer_head *bh;
-	struct msdos_boot_sector *b;
+	struct fat_boot_sector *b;
 	int data_sectors,logical_sector_size,sector_mult,fat_clusters=0;
-	int debug,error,fat;
+	int debug,error,fat,cp;
 	int blksize = 512;
+	int fat32;
 	struct fat_mount_options opts;
+	char buf[50];
+	char *p;
 
 	MOD_INC_USE_COUNT;
 	if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
@@ -204,6 +269,7 @@
 			printk ("MSDOS: Hardware sector size is %d\n",blksize);
 		}
 	}
+	opts.isvfat = MSDOS_SB(sb)->options.isvfat;
 	if (!parse_options((char *) data, &fat, &blksize, &debug, &opts)
 		|| (blksize != 512 && blksize != 1024)) {
 		sb->s_dev = 0;
@@ -224,8 +290,8 @@
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
-	b = (struct msdos_boot_sector *) bh->b_data;
 	set_blocksize(sb->s_dev, blksize);
+
 /*
  * The DOS3 partition size limit is *not* 32M as many people think.  
  * Instead, it is 64K sectors (with the usual sector size being
@@ -244,15 +310,37 @@
 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
     /* don't divide by zero */
 
+	b = (struct fat_boot_sector *) bh->b_data;
 	logical_sector_size =
 		CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
 	sector_mult = logical_sector_size >> SECTOR_BITS;
 	MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult;
 	MSDOS_SB(sb)->fats = b->fats;
 	MSDOS_SB(sb)->fat_start = CF_LE_W(b->reserved)*sector_mult;
-	MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
-	MSDOS_SB(sb)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
-	    b->fat_length))*sector_mult;
+	if (!b->fat_length && b->fat32_length) {
+		struct fat_boot_fsinfo *fsinfo;
+
+		/* Must be FAT32 */
+		fat32 = 1;
+		MSDOS_SB(sb)->fat_length= CF_LE_W(b->fat32_length)*sector_mult;
+		MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster);
+		MSDOS_SB(sb)->fsinfo_offset =
+			CF_LE_W(b->info_sector) * logical_sector_size + 0x1e0;
+		fsinfo = (struct fat_boot_fsinfo *)
+			&bh->b_data[MSDOS_SB(sb)->fsinfo_offset];
+		if (CF_LE_L(fsinfo->signature) != 0x61417272) {
+			printk("fat_read_super: Did not find valid FSINFO signature. Found 0x%x\n", CF_LE_L(fsinfo->signature));
+		} else {
+			MSDOS_SB(sb)->free_clusters = CF_LE_L(fsinfo->free_clusters);
+		}
+	} else {
+		fat32 = 0;
+		MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
+		MSDOS_SB(sb)->root_cluster = 0;
+		MSDOS_SB(sb)->free_clusters = -1; /* Don't know yet */
+	}
+	MSDOS_SB(sb)->dir_start= CF_LE_W(b->reserved)*sector_mult+
+	    b->fats*MSDOS_SB(sb)->fat_length;
 	MSDOS_SB(sb)->dir_entries =
 		CF_LE_W(get_unaligned((unsigned short *) &b->dir_entries));
 	MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE((
@@ -267,8 +355,9 @@
 	if (!error) {
 		MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/
 		    b->cluster_size/sector_mult : 0;
-		MSDOS_SB(sb)->fat_bits = fat ? fat : MSDOS_SB(sb)->clusters >
-		    MSDOS_FAT12 ? 16 : 12;
+		MSDOS_SB(sb)->fat_bits = fat32 ? 32 :
+			(fat ? fat :
+			 (MSDOS_SB(sb)->clusters > MSDOS_FAT12 ? 16 : 12));
 		fat_clusters = MSDOS_SB(sb)->fat_length*SECTOR_SIZE*8/
 		    MSDOS_SB(sb)->fat_bits;
 		error = !MSDOS_SB(sb)->fats || (MSDOS_SB(sb)->dir_entries &
@@ -294,12 +383,13 @@
 		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
 		       MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : "");
 		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
-		       "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(sb)->cluster_size,
+		       "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",b->media,MSDOS_SB(sb)->cluster_size,
 		       MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,MSDOS_SB(sb)->fat_length,
 		       MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries,
 		       MSDOS_SB(sb)->data_start,
 		       CF_LE_W(*(unsigned short *) &b->sectors),
-		       (unsigned long)b->total_sect,logical_sector_size);
+		       (unsigned long)b->total_sect,logical_sector_size,
+		       MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters);
 		printk ("Transaction block size = %d\n",blksize);
 	}
 	if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
@@ -314,17 +404,54 @@
 	}
 	sb->s_magic = MSDOS_SUPER_MAGIC;
 	/* set up enough so that it can read an inode */
-	MSDOS_SB(sb)->free_clusters = -1; /* don't know yet */
 	MSDOS_SB(sb)->fat_wait = NULL;
 	MSDOS_SB(sb)->fat_lock = 0;
 	MSDOS_SB(sb)->prev_free = 0;
 	memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options));
+
+	cp = opts.codepage ? opts.codepage : 437;
+	sprintf(buf, "cp%d", cp);
+	MSDOS_SB(sb)->nls_disk = load_nls(buf);
+	if (! MSDOS_SB(sb)->nls_disk) {
+		/* Fail only if explicit charset specified */
+		if (opts.codepage == 0) {
+			MSDOS_SB(sb)->options.codepage = 0;
+			MSDOS_SB(sb)->nls_disk = load_nls_default();
+		} else {
+			sb->s_dev = 0;
+			MOD_DEC_USE_COUNT;
+			return NULL;
+		}
+	}
+
+	p = opts.iocharset ? opts.iocharset : "iso8859-1";
+	MSDOS_SB(sb)->nls_io = NULL;
+	if (MSDOS_SB(sb)->options.isvfat && !opts.utf8) {
+		MSDOS_SB(sb)->nls_io = load_nls(p);
+		if (! MSDOS_SB(sb)->nls_io) {
+			/* Fail only if explicit charset specified */
+			if (opts.iocharset) {
+				kfree(opts.iocharset);
+				unload_nls(MSDOS_SB(sb)->nls_disk);
+				sb->s_dev = 0;
+				MOD_DEC_USE_COUNT;
+				return NULL;
+			} else {
+				MSDOS_SB(sb)->nls_io = load_nls_default();
+			}
+		}
+	}
+
 	if (!(sb->s_mounted = iget(sb,MSDOS_ROOT_INO))) {
 		sb->s_dev = 0;
 		printk("get root inode failed\n");
+		unload_nls(MSDOS_SB(sb)->nls_disk);
+		if (MSDOS_SB(sb)->nls_io) unload_nls(MSDOS_SB(sb)->nls_io);
+		if (opts.iocharset) kfree(opts.iocharset);
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
+
 	return sb;
 }
 
@@ -352,7 +479,7 @@
 	tmp.f_files = 0;
 	tmp.f_ffree = 0;
 	tmp.f_namelen = 12;
-	memcpy_tofs(buf, &tmp, bufsiz);
+	FAT_COPY_TO_USER(buf, &tmp, bufsiz);
 }
 
 
@@ -362,7 +489,7 @@
 	int cluster,offset;
 
 	sb = MSDOS_SB(inode->i_sb);
-	if (inode->i_ino == MSDOS_ROOT_INO) {
+	if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) {
 		return sb->dir_start + block;
 	}
 	cluster = block/sb->cluster_size;
@@ -388,6 +515,8 @@
 	struct msdos_dir_entry *raw_entry;
 	int nr;
 
+	PRINTK(("fat_read_inode: inode=%p, sb->dir_start=0x%x\n",
+		inode, MSDOS_SB(sb)->dir_start));
 	MSDOS_I(inode)->i_busy = 0;
 	MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL;
 	MSDOS_I(inode)->i_linked = MSDOS_I(inode)->i_oldlink = NULL;
@@ -399,17 +528,33 @@
 		inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) |
 		    S_IFDIR;
 		inode->i_op = fs_dir_inode_ops;
-		inode->i_nlink = fat_subdirs(inode)+2;
-		    /* subdirs (neither . nor ..) plus . and "self" */
-		inode->i_size = MSDOS_SB(sb)->dir_entries*
-		    sizeof(struct msdos_dir_entry);
+		if (MSDOS_SB(sb)->fat_bits == 32) {
+			MSDOS_I(inode)->i_start = MSDOS_SB(sb)->root_cluster;
+			if ((nr = MSDOS_I(inode)->i_start) != 0) {
+				while (nr != -1) {
+					inode->i_size += SECTOR_SIZE*MSDOS_SB(sb)->cluster_size;
+					if (!(nr = fat_access(sb,nr,-1))) {
+						printk("Directory %ld: bad FAT\n",
+						       inode->i_ino);
+						break;
+					}
+				}
+			}
+		} else {
+			MSDOS_I(inode)->i_start = 0;
+			inode->i_size = MSDOS_SB(sb)->dir_entries*
+				sizeof(struct msdos_dir_entry);
+		}
 		inode->i_blksize = MSDOS_SB(sb)->cluster_size*
 		    SECTOR_SIZE;
 		inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
 		    inode->i_blksize*MSDOS_SB(sb)->cluster_size;
-		MSDOS_I(inode)->i_start = 0;
+		MSDOS_I(inode)->i_logstart = 0;
+
 		MSDOS_I(inode)->i_attrs = 0;
 		inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
+		inode->i_nlink = fat_subdirs(inode)+2;
+		    /* subdirs (neither . nor ..) plus . and "self" */
 		return;
 	}
 	if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) {
@@ -425,6 +570,11 @@
 		inode->i_op = fs_dir_inode_ops;
 
 		MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
+		if (MSDOS_SB(sb)->fat_bits == 32) {
+			MSDOS_I(inode)->i_start |=
+				(CF_LE_W(raw_entry->starthi) << 16);
+		}
+		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
 		inode->i_nlink = fat_subdirs(inode);
 		    /* includes .., compensating for "self" */
 #ifdef DEBUG
@@ -434,7 +584,7 @@
 		}
 #endif
 		inode->i_size = 0;
-		if ((nr = CF_LE_W(raw_entry->start)) != 0)
+		if ((nr = MSDOS_I(inode)->i_start) != 0)
 			while (nr != -1) {
 				inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->
 				    i_sb)->cluster_size;
@@ -455,6 +605,11 @@
 			? &fat_file_inode_operations_1024
 			: &fat_file_inode_operations;
 		MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
+		if (MSDOS_SB(sb)->fat_bits == 32) {
+			MSDOS_I(inode)->i_start |=
+				(CF_LE_W(raw_entry->starthi) << 16);
+		}
+		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
 		inode->i_nlink = 1;
 		inode->i_size = CF_LE_L(raw_entry->size);
 	}
@@ -526,7 +681,8 @@
 	}
 	raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
 	    MSDOS_I(inode)->i_attrs;
-	raw_entry->start = CT_LE_W(MSDOS_I(inode)->i_start);
+	raw_entry->start = CT_LE_W(MSDOS_I(inode)->i_logstart);
+	raw_entry->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16);
 	fat_date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date);
 	raw_entry->time = CT_LE_W(raw_entry->time);
 	raw_entry->date = CT_LE_W(raw_entry->date);
diff -u --recursive --new-file v2.0.33/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.0.33/linux/fs/fat/misc.c	Thu May  9 21:54:52 1996
+++ linux/fs/fat/misc.c	Wed Jun  3 15:17:49 1998
@@ -14,7 +14,11 @@
 
 #include "msbuffer.h"
 
-#define PRINTK(x)
+#if 0
+#  define PRINTK(x)	printk x
+#else
+#  define PRINTK(x)
+#endif
 #define Printk(x)	printk x
 
 /* Well-known binary file extensions - of course there are many more */
@@ -23,7 +27,7 @@
   "EXE" "COM" "BIN" "APP" "SYS" "DRV" "OVL" "OVR" "OBJ" "LIB" "DLL" "PIF" /* program code */
   "ARC" "ZIP" "LHA" "LZH" "ZOO" "TAR" "Z  " "ARJ"	/* common archivers */
   "TZ " "TAZ" "TZP" "TPZ"		/* abbreviations of tar.Z and tar.zip */
-  "GZ " "TGZ" "DEB"			/* .gz, .tar.gz and Debian packages   */
+  "GZ " "TGZ" "DEB" "RPM"		/* .gz, .tar.gz and Debian packages   */
   "GIF" "BMP" "TIF" "GL " "JPG" "PCX"	/* graphics */
   "TFM" "VF " "GF " "PK " "PXL" "DVI";	/* TeX */
 
@@ -77,7 +81,7 @@
 /* (rename might deadlock before detecting cross-FS moves.) */
 
 static struct wait_queue *creation_wait = NULL;
-static creation_lock = 0;
+static int creation_lock = 0;
 
 
 void fat_lock_creation(void)
@@ -107,6 +111,34 @@
 	wake_up(&MSDOS_SB(sb)->fat_wait);
 }
 
+/* Flushes the number of free clusters on FAT32 */
+/* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
+void fat_clusters_flush(struct super_block *sb)
+{
+	int offset;
+	struct buffer_head *bh;
+	struct fat_boot_fsinfo *fsinfo;
+
+	/* The fat32 boot fs info is at offset 0x3e0 by observation */
+	offset = MSDOS_SB(sb)->fsinfo_offset;
+	bh = fat_bread(sb, (offset >> SECTOR_BITS));
+	if (bh == NULL) {
+		printk("FAT bread failed in fat_clusters_flush\n");
+		return;
+	}
+	fsinfo = (struct fat_boot_fsinfo *)
+		&bh->b_data[offset & (SECTOR_SIZE-1)];
+
+	/* Sanity check */
+	if (CF_LE_L(fsinfo->signature) != 0x61417272) {
+		printk("fat_clusters_flush: Did not find valid FSINFO signature. Found 0x%x.  offset=0x%x\n", CF_LE_L(fsinfo->signature), offset);
+		fat_brelse(sb, bh);
+		return;
+	}
+	fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
+	fat_mark_buffer_dirty(sb, bh, 1);
+	fat_brelse(sb, bh);
+}
 
 /*
  * fat_add_cluster tries to allocate a new cluster and adds it to the file
@@ -120,7 +152,9 @@
 	struct buffer_head *bh;
 	int cluster_size = MSDOS_SB(sb)->cluster_size;
 
-	if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+	if (MSDOS_SB(sb)->fat_bits != 32) {
+		if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+	}
 	if (!MSDOS_SB(sb)->free_clusters) return -ENOSPC;
 	lock_fat(sb);
 	limit = MSDOS_SB(sb)->clusters;
@@ -139,10 +173,14 @@
 		unlock_fat(sb);
 		return -ENOSPC;
 	}
-	fat_access(sb,nr,MSDOS_SB(sb)->fat_bits == 12 ?
-	    0xff8 : 0xfff8);
-	if (MSDOS_SB(sb)->free_clusters != -1)
+	fat_access(sb,nr,MSDOS_SB(sb)->fat_bits == 12 ? EOF_FAT12 :
+		   MSDOS_SB(sb)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT32);
+	if (MSDOS_SB(sb)->free_clusters != -1) {
 		MSDOS_SB(sb)->free_clusters--;
+	}
+	if (MSDOS_SB(sb)->fat_bits == 32) {
+		fat_clusters_flush(sb);
+	}
 	unlock_fat(sb);
 #ifdef DEBUG
 printk("set to %x\n",fat_access(sb,nr,-1));
@@ -179,6 +217,7 @@
 	if (last) fat_access(sb,last,nr);
 	else {
 		MSDOS_I(inode)->i_start = nr;
+		MSDOS_I(inode)->i_logstart = nr;
 		inode->i_dirt = 1;
 	}
 #ifdef DEBUG
@@ -244,6 +283,9 @@
 	    month < 2 ? 1 : 0)+3653);
 			/* days since 1.1.70 plus 80's leap day */
 	secs += sys_tz.tz_minuteswest*60;
+	if (sys_tz.tz_dsttime) {
+	    secs -= 3600;
+	}
 	return secs;
 }
 
@@ -256,6 +298,8 @@
 	int day,year,nl_day,month;
 
 	unix_date -= sys_tz.tz_minuteswest*60;
+	if (sys_tz.tz_dsttime) unix_date += 3600;
+
 	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
 	    (((unix_date/3600) % 24) << 11);
 	day = unix_date/86400-3652;
@@ -298,7 +342,7 @@
 			fat_brelse(sb, *bh);
 		PRINTK (("get_entry sector apres brelse\n"));
 		if (!(*bh = fat_bread(sb, sector))) {
-			printk("Directory sread (sector %d) failed\n",sector);
+			printk("Directory sread (sector 0x%x) failed\n",sector);
 			continue;
 		}
 		PRINTK (("get_entry apres sread\n"));
@@ -340,7 +384,13 @@
      !(data[entry].attr & ATTR_VOLUME);
 
 #define RSS_START /* search for start cluster */ \
-    done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number;
+    done = !IS_FREE(data[entry].name) \
+      && ( \
+           ( \
+             (MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
+           ) \
+           | CF_LE_W(data[entry].start) \
+         ) == *number;
 
 #define RSS_FREE /* search for free entry */ \
     { \
@@ -393,6 +443,9 @@
 		if (done) {
 			if (ino) *ino = sector*MSDOS_DPS+entry;
 			start = CF_LE_W(data[entry].start);
+			if (MSDOS_SB(sb)->fat_bits == 32) {
+				start |= (CF_LE_W(data[entry].starthi) << 16);
+			}
 			if (!res_bh)
 				fat_brelse(sb, bh);
 			else {
@@ -488,6 +541,7 @@
 	static int zero = 0;
 	int error,curr,prev,nr;
 
+	PRINTK(("fat_parent_ino: Debug 0\n"));
 	if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
 	if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
 	if (!locked) fat_lock_creation(); /* prevent renames */
@@ -496,18 +550,27 @@
 		if (!locked) fat_unlock_creation();
 		return curr;
 	}
+	PRINTK(("fat_parent_ino: Debug 1 curr=%d\n", curr));
 	if (!curr) nr = MSDOS_ROOT_INO;
 	else {
+		PRINTK(("fat_parent_ino: Debug 2\n"));
 		if ((prev = raw_scan(dir->i_sb,curr,MSDOS_DOTDOT,&zero,NULL,
 		    NULL,NULL,SCAN_ANY)) < 0) {
+			PRINTK(("fat_parent_ino: Debug 3 prev=%d\n", prev));
 			if (!locked) fat_unlock_creation();
 			return prev;
 		}
+		PRINTK(("fat_parent_ino: Debug 4 prev=%d\n", prev));
+		if (prev == 0 && MSDOS_SB(dir->i_sb)->fat_bits == 32) {
+			prev = MSDOS_SB(dir->i_sb)->root_cluster;
+		}
 		if ((error = raw_scan(dir->i_sb,prev,NULL,&curr,&nr,NULL,
 		    NULL,SCAN_ANY)) < 0) {
+			PRINTK(("fat_parent_ino: Debug 5 error=%d\n", error));
 			if (!locked) fat_unlock_creation();
 			return error;
 		}
+		PRINTK(("fat_parent_ino: Debug 6 nr=%d\n", nr));
 	}
 	if (!locked) fat_unlock_creation();
 	return nr;
@@ -524,10 +587,12 @@
 	int count;
 
 	count = 0;
-	if (dir->i_ino == MSDOS_ROOT_INO)
+	if ((dir->i_ino == MSDOS_ROOT_INO) &&
+	    (MSDOS_SB(dir->i_sb)->fat_bits != 32)) {
 		(void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL,SCAN_ANY);
-	else {
-		if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */
+	} else {
+		if ((dir->i_ino != MSDOS_ROOT_INO) &&
+		    !MSDOS_I(dir)->i_start) return 0; /* in mkdir */
 		else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
 		    NULL,&count,NULL,NULL,NULL,SCAN_ANY);
 	}
@@ -545,10 +610,7 @@
 {
 	int res;
 
-	res = (name)
-		? raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
-		    name, NULL, ino, res_bh, res_de, scantype)
-		: raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
-		    NULL, NULL, ino, res_bh, res_de, scantype);
+	res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
+		       name, NULL, ino, res_bh, res_de, scantype);
 	return res<0 ? res : 0;
 }
diff -u --recursive --new-file v2.0.33/linux/fs/fat/mmap.c linux/fs/fat/mmap.c
--- v2.0.33/linux/fs/fat/mmap.c	Thu Feb  8 21:47:16 1996
+++ linux/fs/fat/mmap.c	Wed Jun  3 15:17:49 1998
@@ -7,6 +7,9 @@
  *	mmap handling for fat-based filesystems
  */
 
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
+
 #include <linux/stat.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -18,7 +21,11 @@
 #include <linux/malloc.h>
 #include <linux/msdos_fs.h>
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+#include <asm/uaccess.h>
+#else
 #include <asm/segment.h>
+#endif
 #include <asm/system.h>
 
 /*
diff -u --recursive --new-file v2.0.33/linux/fs/fat/tables.c linux/fs/fat/tables.c
--- v2.0.33/linux/fs/fat/tables.c	Tue Mar  5 03:03:26 1996
+++ linux/fs/fat/tables.c	Wed Jun  3 15:17:49 1998
@@ -1,7 +1,7 @@
 /*
  * linux/fs/fat/tables.c
  *
- * ASCII / Unicode translation tables for VFAT filename handling.
+ * Unicode escape translation tables for VFAT filename handling.
  * By Gordon Chaffee.
  *
  * Note: This file is used by all fat-based filesystems.
@@ -9,10 +9,9 @@
 
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/msdos_fs.h>
 
-#include "tables.h"
-
-unsigned char fat_uni2code[64] = {
+unsigned char fat_uni2esc[64] = {
 	'0', '1', '2', '3', '4', '5', '6', '7',
 	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
 	'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
@@ -23,7 +22,7 @@
 	'u', 'v', 'w', 'x', 'y', 'z', '+', '-'
 };
 
-unsigned char fat_code2uni[256] = {
+unsigned char fat_esc2uni[256] = {
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
@@ -58,209 +57,6 @@
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
 };
 
-static unsigned char page00[256] = {
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
-	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x08-0x0F */
-	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
-	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x18-0x1F */
-	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
-	0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, /* 0x28-0x2F */
-	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
-	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, /* 0x38-0x3F */
-	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
-	0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* 0x48-0x4F */
-	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
-	0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, /* 0x58-0x5F */
-	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
-	0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, /* 0x68-0x6F */
-	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
-	0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, /* 0x78-0x7F */
-
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, /* 0x98-0x9F */
-	0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, /* 0xA0-0xA7 */
-	0xF9, 0xB8, 0x00, 0xAE, 0xAA, 0xF0, 0x00, 0xEE, /* 0xA8-0xAF */
-	0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, /* 0xB0-0xB7 */
-	0xF7, 0xFB, 0x00, 0xAF, 0xAC, 0xAB, 0xF3, 0x00, /* 0xB8-0xBF */
-	0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, /* 0xC0-0xC7 */
-	0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, /* 0xC8-0xCF */
-	0x00, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, /* 0xD0-0xD7 */
-	0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, /* 0xD8-0xDF */
-	0xA1, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, /* 0xE0-0xE7 */
-	0x8A, 0x82, 0x88, 0x89, 0x8D, 0x00, 0x8C, 0x8B, /* 0xE8-0xEF */
-	0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, /* 0xF0-0xF7 */
-	0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98  /* 0xF8-0xFF */
-};
-
-
-static unsigned char page25[256] = {
-	0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
-	0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, /* 0x08-0x0F */
-	0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
-	0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, /* 0x18-0x1F */
-	0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
-	0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, /* 0x28-0x2F */
-	0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
-	0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, /* 0x38-0x3F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4F */
-	0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, /* 0x50-0x57 */
-	0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, /* 0x58-0x5F */
-	0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, /* 0x60-0x67 */
-	0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, /* 0x68-0x6F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7F */
-
-	0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, /* 0x80-0x87 */
-	0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */
-	0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9F */
-	0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAF */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBF */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCF */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDF */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEF */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF7 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xF8-0xFF */
-};
-
-
-unsigned char *fat_uni2asc_pg[256] = {
-	page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL,   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL,   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL,   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL,   NULL, NULL, NULL, page25
-};
-
-/* Conversion from ASCII name characters to the shortname character
- * should probably just just use XXX
- */
-unsigned char fat_a2alias[256] = 
-{
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
-	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x08-0x0F */
-	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
-	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x18-0x1F */
-	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
-	0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, /* 0x28-0x2F */
-	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
-	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, /* 0x38-0x3F */
-	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
-	0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* 0x48-0x4F */
-	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
-	0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, /* 0x58-0x5F */
-	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
-	0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, /* 0x68-0x6F */
-	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
-	0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, /* 0x78-0x7F */
-
-	0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80,	/* 0x80-0x87 */
-	0xD2, 0xD3, 0xD4, 0xD8, 0xD7, 0xDE, 0x8E, 0x8F,	/* 0x88-0x8F */
-	0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, 0xEA, 0xEB, /* 0x90-0x97 */
-/*_~1*/	0x98, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, /* 0x98-0x9F */
-	0xB5, 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA7, /* 0xA0-0xA7 */
-	0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, /* 0xA8-0xAF */
-	0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, /* 0xB0-0xB7 */
-	0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, /* 0xB8-0xBF */
-	0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 0xC0-0xC7 */
-	0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, /* 0xC8-0xCF */
-	0xD1, 0xD1, 0xD2, 0xD3, 0xD4, 0x49, 0xD6, 0xD7, /* 0xD0-0xD7 */
-	0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, /* 0xD8-0xDF */
-	0xE0, 0xE1, 0xE2, 0xE3, 0x05, 0x05, 0xE6, 0xE8, /* 0xE0-0xE7 */
-	0xE8, 0xE9, 0xEA, 0xEB, 0xED, 0xED, 0xEE, 0xEF, /* 0xE8-0xEF */
-	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 0xF0-0xF7 */
-	0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  /* 0xF8-0xFF */
-};
-
-struct unicode_value fat_a2uni[256] = {
-/* 0x00 */
-{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
-{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
-{0x08, 0x00}, {0x09, 0x00}, {0x0A, 0x00}, {0x0B, 0x00},
-{0x0C, 0x00}, {0x0D, 0x00}, {0x0E, 0x00}, {0x0F, 0x00},
-/* 0x10 */
-{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
-{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
-{0x18, 0x00}, {0x19, 0x00}, {0x1A, 0x00}, {0x1B, 0x00},
-{0x1C, 0x00}, {0x1D, 0x00}, {0x1E, 0x00}, {0x1F, 0x00},
-/* 0x20 */
-{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
-{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
-{0x28, 0x00}, {0x29, 0x00}, {0x2A, 0x00}, {0x2B, 0x00},
-{0x2C, 0x00}, {0x2D, 0x00}, {0x2E, 0x00}, {0x2F, 0x00},
-/* 0x30 */
-{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
-{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
-{0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x00},
-{0x3C, 0x00}, {0x3D, 0x00}, {0x3E, 0x00}, {0x3F, 0x00},
-/* 0x40 */
-{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
-{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
-{0x48, 0x00}, {0x49, 0x00}, {0x4A, 0x00}, {0x4B, 0x00},
-{0x4C, 0x00}, {0x4D, 0x00}, {0x4E, 0x00}, {0x4F, 0x00},
-/* 0x50 */
-{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
-{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
-{0x58, 0x00}, {0x59, 0x00}, {0x5A, 0x00}, {0x5B, 0x00},
-{0x5C, 0x00}, {0x5D, 0x00}, {0x5E, 0x00}, {0x5F, 0x00},
-/* 0x60 */
-{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
-{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
-{0x68, 0x00}, {0x69, 0x00}, {0x6A, 0x00}, {0x6B, 0x00},
-{0x6C, 0x00}, {0x6D, 0x00}, {0x6E, 0x00}, {0x6F, 0x00},
-/* 0x70 */
-{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
-{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
-{0x78, 0x00}, {0x79, 0x00}, {0x7A, 0x00}, {0x7B, 0x00},
-{0x7C, 0x00}, {0x7D, 0x00}, {0x7E, 0x00}, {0x7F, 0x00},
-/* 0x80 */
-{0xC7, 0x00}, {0xFC, 0x00}, {0xE9, 0x00}, {0xE2, 0x00},
-{0xE4, 0x00}, {0xE0, 0x00}, {0xE5, 0x00}, {0xE7, 0x00},
-{0xEA, 0x00}, {0xEB, 0x00}, {0xE8, 0x00}, {0xEF, 0x00},
-{0xEE, 0x00}, {0xEC, 0x00}, {0xC4, 0x00}, {0xC5, 0x00},
-/* 0x90 */
-{0xC9, 0x00}, {0xE6, 0x00}, {0xC6, 0x00}, {0xF4, 0x00},
-{0xF6, 0x00}, {0xF2, 0x00}, {0xFB, 0x00}, {0xF9, 0x00},
-{0xFF, 0x00}, {0xD6, 0x00}, {0xDC, 0x00}, {0xF8, 0x00},
-{0xA3, 0x00}, {0xD8, 0x00}, {0xD7, 0x00}, {0x92, 0x00},
-/* 0xA0 */
-{0xE1, 0x00}, {0xE0, 0x00}, {0xF3, 0x00}, {0xFA, 0x00},
-{0xF1, 0x00}, {0xD1, 0x00}, {0xAA, 0x00}, {0xBA, 0x00},
-{0xBF, 0x00}, {0xAE, 0x00}, {0xAC, 0x00}, {0xBD, 0x00},
-{0xBC, 0x00}, {0xA1, 0x00}, {0xAB, 0x00}, {0xBB, 0x00},
-/* 0xB0 */
-{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
-{0x24, 0x25}, {0xC1, 0x00}, {0xC2, 0x00}, {0xC0, 0x00},
-{0xA9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
-{0x5D, 0x25}, {0xA2, 0x00}, {0xA5, 0x00}, {0x10, 0x25},
-/* 0xC0 */
-{0x14, 0x25}, {0x34, 0x25}, {0x2C, 0x25}, {0x1C, 0x25},
-{0x00, 0x25}, {0x3C, 0x25}, {0xE3, 0x00}, {0xC3, 0x00},
-{0x5A, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
-{0x60, 0x25}, {0x50, 0x25}, {0x6C, 0x25}, {0xA4, 0x00},
-/* 0xD0 */
-{0xF0, 0x00}, {0xD0, 0x00}, {0xCA, 0x00}, {0xCB, 0x00},
-{0xC8, 0x00}, {0x31, 0x01}, {0xCD, 0x00}, {0xCE, 0x00},
-{0xCF, 0x00}, {0x18, 0x25}, {0x0C, 0x25}, {0x88, 0x25},
-{0x84, 0x25}, {0xA6, 0x00}, {0xCC, 0x00}, {0x80, 0x25},
-/* 0xE0 */
-{0xD3, 0x00}, {0xDF, 0x00}, {0xD4, 0x00}, {0xD2, 0x00},
-{0xF5, 0x00}, {0xD5, 0x00}, {0xB5, 0x00}, {0xFE, 0x00},
-{0xDE, 0x00}, {0xDA, 0x00}, {0xDB, 0x00}, {0xD9, 0x00},
-{0xFD, 0x00}, {0xDD, 0x00}, {0xAF, 0x00}, {0xB4, 0x00},
-/* 0xF0 */
-{0xAD, 0x00}, {0xB1, 0x00}, {0x17, 0x20}, {0xBE, 0x00},
-{0xB6, 0x00}, {0xA7, 0x00}, {0xF7, 0x00}, {0xB8, 0x00},
-{0xB0, 0x00}, {0xA8, 0x00}, {0xB7, 0x00}, {0xB9, 0x00},
-{0xB3, 0x00}, {0xB2, 0x00}, {0xA0, 0x25}, {0xA0, 0x00}};
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.0.33/linux/fs/fat/tables.h linux/fs/fat/tables.h
--- v2.0.33/linux/fs/fat/tables.h	Tue Mar  5 03:03:27 1996
+++ linux/fs/fat/tables.h	Wed Jun  3 15:17:49 1998
@@ -1,3 +1,6 @@
+#ifndef _FS_FAT_TABLES_H
+#define _FS_FAT_TABLES_H
+
 struct unicode_value {
 	unsigned char uni1;
 	unsigned char uni2;
@@ -33,3 +36,5 @@
  * c-continued-brace-offset: 0
  * End:
  */
+
+#endif /* _FS_FAT_TABLES_H */
diff -u --recursive --new-file v2.0.33/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.0.33/linux/fs/filesystems.c	Fri Sep  5 20:43:59 1997
+++ linux/fs/filesystems.c	Wed Jun  3 15:17:49 1998
@@ -9,6 +9,9 @@
 #include <linux/config.h>
 #include <linux/fs.h>
 
+#ifdef CONFIG_NLS
+#include <linux/nls.h>
+#endif
 #include <linux/minix_fs.h>
 #include <linux/ext_fs.h>
 #include <linux/ext2_fs.h>
@@ -42,6 +45,10 @@
 	device_setup();
 
 	binfmt_setup();
+
+#ifdef CONFIG_NLS
+	init_nls();
+#endif
 
 #ifdef CONFIG_EXT_FS
 	init_ext_fs();
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/Makefile linux/fs/isofs/Makefile
--- v2.0.33/linux/fs/isofs/Makefile	Tue Aug 15 05:07:02 1995
+++ linux/fs/isofs/Makefile	Wed Jun  3 15:17:49 1998
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := isofs.o
-O_OBJS   := namei.o inode.o file.o dir.o util.o rock.o symlink.o
+O_OBJS   := namei.o inode.o file.o dir.o util.o rock.o symlink.o joliet.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.0.33/linux/fs/isofs/dir.c	Tue Jul 23 00:26:40 1996
+++ linux/fs/isofs/dir.c	Wed Jun  3 15:17:49 1998
@@ -23,6 +23,7 @@
 
 #include <asm/segment.h>
 
+
 static int isofs_readdir(struct inode *, struct file *, void *, filldir_t);
 
 static struct file_operations isofs_dir_operations =
@@ -114,15 +115,18 @@
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
 	unsigned int block, offset;
-	int inode_number;
+	int inode_number = 0;	/* Quiet GCC */
 	struct buffer_head *bh;
-	int len, rrflag;
-	int high_sierra = 0;
-	char *name;
+	int len;
+	int map;
+	int high_sierra;
+	int first_de = 1;
+	char *p = NULL;		/* Quiet GCC */
 	struct iso_directory_record *de;
 
 	offset = filp->f_pos & (bufsize - 1);
 	block = isofs_bmap(inode, filp->f_pos >> bufbits);
+	high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 
 	if (!block)
 		return 0;
@@ -154,7 +158,7 @@
 		}
 
 		de = (struct iso_directory_record *) (bh->b_data + offset);
-		inode_number = (block << bufbits) + (offset & (bufsize - 1));
+		if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
 		de_len = *(unsigned char *) de;
 #ifdef DEBUG
@@ -215,6 +219,13 @@
 		}
 		offset = next_offset;
 
+		if(de->flags[-high_sierra] & 0x80) {
+			first_de = 0;
+			filp->f_pos += de_len;
+			continue;
+		}
+		first_de = 1;
+
 		/* Handle the case of the '.' directory */
 		if (de->name_len[0] == 1 && de->name[0] == 0) {
 			if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
@@ -223,6 +234,8 @@
 			continue;
 		}
 
+		len = 0;
+
 		/* Handle the case of the '..' directory */
 		if (de->name_len[0] == 1 && de->name[0] == 1) {
 			inode_number = parent_inode_number(inode, de);
@@ -236,46 +249,43 @@
 
 		/* Handle everything else.  Do name translation if there
 		   is no Rock Ridge NM field. */
-
 		if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
 			/* Do not report hidden or associated files */
-			high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 			if (de->flags[-high_sierra] & 5) {
 				filp->f_pos += de_len;
 				continue;
 			}
 		}
 
-		/* Check Rock Ridge name translation.. */
-		len = de->name_len[0];
-		name = de->name;
-		rrflag = get_rock_ridge_filename(de, &name, &len, inode);
-		if (rrflag) {
-			/* rrflag == 1 means that we have a new name (kmalloced) */
-			if (rrflag == 1) {
-				rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
-				dcache_add(inode, name, len, inode_number);
-				kfree(name); /* this was allocated in get_r_r_filename.. */
-				if (rrflag < 0)
-					break;
+		map = 1;
+		if (inode->i_sb->u.isofs_sb.s_rock) {
+			len = get_rock_ridge_filename(de, tmpname, inode);
+			if (len != 0) {
+				p = tmpname;
+				map = 0;
 			}
-			filp->f_pos += de_len;
-			continue;
 		}
-
-		if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
-			len = isofs_name_translate(name, len, tmpname);
-			if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
-				break;
-			dcache_add(inode, tmpname, len, inode_number);
-			filp->f_pos += de_len;
-			continue;
+		if (map) {
+			if (inode->i_sb->u.isofs_sb.s_joliet_level) {
+				len = get_joliet_filename(de, inode, tmpname);
+				p = tmpname;
+			} else {
+				if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
+					len = isofs_name_translate(de->name, de->name_len[0],
+								   tmpname);
+					p = tmpname;
+				} else {
+					p = de->name;
+					len = de->name_len[0];
+				}
+			}
 		}
+		if (len > 0) {
+			if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0)
+				break;
 
-		if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
-			break;
-
-		dcache_add(inode, name, len, inode_number);
+			dcache_add(inode, p, len, inode_number);
+		}
 		filp->f_pos += de_len;
 		continue;
 	}
@@ -301,7 +311,7 @@
 	tmpname = (char *) __get_free_page(GFP_KERNEL);
 	if (!tmpname)
 		return -ENOMEM;
-	tmpde = (struct iso_directory_record *) (tmpname+256);
+	tmpde = (struct iso_directory_record *) (tmpname+1024);
 
 	result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
 
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.0.33/linux/fs/isofs/inode.c	Fri Aug 15 11:11:45 1997
+++ linux/fs/isofs/inode.c	Wed Jun  3 15:17:49 1998
@@ -21,6 +21,7 @@
 #include <linux/malloc.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
+#include <linux/nls.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -38,6 +39,10 @@
 
 void isofs_put_super(struct super_block *sb)
 {
+	if (sb->u.isofs_sb.s_nls_iocharset) {
+		unload_nls(sb->u.isofs_sb.s_nls_iocharset);
+		sb->u.isofs_sb.s_nls_iocharset = NULL;
+	}
 	lock_super(sb);
 
 #ifdef LEAK_CHECK
@@ -64,6 +69,7 @@
 struct iso9660_options{
   char map;
   char rock;
+  char joliet;
   char cruft;
   char unhide;
   unsigned char check;
@@ -72,14 +78,18 @@
   mode_t mode;
   gid_t gid;
   uid_t uid;
+  char *iocharset;
+  unsigned char utf8;
 };
 
 static int parse_options(char *options, struct iso9660_options * popt)
 {
-	char *this_char,*value;
+	char *this_char,*value,*p;
+	int len;
 
 	popt->map = 'n';
 	popt->rock = 'y';
+	popt->joliet = 'y';
 	popt->cruft = 'n';
 	popt->unhide = 'n';
 	popt->check = 's';		/* default: strict */
@@ -88,12 +98,18 @@
 	popt->mode = S_IRUGO;
 	popt->gid = 0;
 	popt->uid = 0;
+	popt->iocharset = NULL;
+	popt->utf8 = 0;
 	if (!options) return 1;
 	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
 	        if (strncmp(this_char,"norock",6) == 0) {
 		  popt->rock = 'n';
 		  continue;
 		}
+	        if (strncmp(this_char,"nojoliet",8) == 0) {
+		  popt->joliet = 'n';
+		  continue;
+		}
 	        if (strncmp(this_char,"unhide",6) == 0) {
 		  popt->unhide = 'y';
 		  continue;
@@ -102,9 +118,27 @@
 		  popt->cruft = 'y';
 		  continue;
 		}
+	        if (strncmp(this_char,"utf8",4) == 0) {
+		  popt->utf8 = 1;
+		  continue;
+		}
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
-		if (!strcmp(this_char,"map") && value) {
+
+		if (!strcmp(this_char,"iocharset")) {
+			p = value;
+			while (*value && *value != ',') value++;
+			len = value - p;
+			if (len) {
+				popt->iocharset = kmalloc(len+1, GFP_KERNEL);
+				memcpy(popt->iocharset, p, len);
+				popt->iocharset[len] = 0;
+			} else {
+				popt->iocharset = NULL;
+				return 0;
+			}
+		}
+		else if (!strcmp(this_char,"map") && value) {
 			if (value[0] && !value[1] && strchr("on",*value))
 				popt->map = *value;
 			else if (!strcmp(value,"off")) popt->map = 'o';
@@ -227,11 +261,14 @@
 	kdev_t dev = s->s_dev;
 	unsigned int vol_desc_start;
 	int orig_zonesize;
+	char *p;
+	int joliet_level = 0;
 
 	struct iso_volume_descriptor *vdp;
 	struct hs_volume_descriptor *hdp;
 
 	struct iso_primary_descriptor *pri = NULL;
+	struct iso_supplementary_descriptor *sec = NULL;
 	struct hs_primary_descriptor *h_pri = NULL;
 
 	struct iso_directory_record *rootp;
@@ -249,6 +286,7 @@
 #if 0
 	printk("map = %c\n", opt.map);
 	printk("rock = %c\n", opt.rock);
+	printk("joliet = %c\n", opt.joliet);
 	printk("check = %c\n", opt.check);
 	printk("cruft = %c\n", opt.cruft);
 	printk("unhide = %c\n", opt.unhide);
@@ -275,57 +313,84 @@
 	vol_desc_start = isofs_get_last_session(dev);
 	
 	for (iso_blknum = vol_desc_start+16;
-             iso_blknum < vol_desc_start+100; iso_blknum++) {
-                int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
-
-		if (!(bh = bread(dev,b,opt.blocksize))) {
-			s->s_dev = 0;
-			printk("isofs_read_super: bread failed, dev "
-			       "%s iso_blknum %d block %d\n",
-			       kdevname(dev), iso_blknum, b);
-			unlock_super(s);
-			MOD_DEC_USE_COUNT;
-			return NULL;
-		}
+             iso_blknum < vol_desc_start+100; iso_blknum++)
+	{
+	    int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
 
-		vdp = (struct iso_volume_descriptor *)bh->b_data;
-		hdp = (struct hs_volume_descriptor *)bh->b_data;
+	    if (!(bh = bread(dev,b,opt.blocksize))) {
+		s->s_dev = 0;
+		printk("isofs_read_super: bread failed, dev "
+		       "%s iso_blknum %d block %d\n",
+		       kdevname(dev), iso_blknum, b);
+		unlock_super(s);
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	    }
 
+	    vdp = (struct iso_volume_descriptor *)bh->b_data;
+	    hdp = (struct hs_volume_descriptor *)bh->b_data;
+	    
+	    if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
+		if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
+		    goto out;
+		if (isonum_711 (hdp->type) == ISO_VD_END)
+		    goto out;
 		
-		if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
-		  if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
-			goto out;
-		  if (isonum_711 (hdp->type) == ISO_VD_END)
-		        goto out;
-		
-		        s->u.isofs_sb.s_high_sierra = 1;
-			high_sierra = 1;
-		        opt.rock = 'n';
-		        h_pri = (struct hs_primary_descriptor *)vdp;
+		s->u.isofs_sb.s_high_sierra = 1;
+		high_sierra = 1;
+		opt.rock = 'n';
+		h_pri = (struct hs_primary_descriptor *)vdp;
+		break;
+	    }
+
+	    if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
+		if (isonum_711 (vdp->type) == ISO_VD_END)
+		    break;
+		if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) {
+		    if (pri == NULL) {
+			pri = (struct iso_primary_descriptor *)vdp;
+		    }
+		} else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) {
+		    sec = (struct iso_supplementary_descriptor *)vdp;
+		    if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
+			if (opt.joliet == 'y') {
+			    if (sec->escape[2] == 0x40) {
+				joliet_level = 1;
+			    } else if (sec->escape[2] == 0x43) {
+				joliet_level = 2;
+			    } else if (sec->escape[2] == 0x45) {
+				joliet_level = 3;
+			    }
+			    printk("ISO9660 Extensions: Microsoft Joliet Level %d\n",
+				   joliet_level);
+			}
 			break;
+		    } else {
+			/* Unknown supplementary volume descriptor */
+			sec = NULL;
+		    }
 		}
-		
-		if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
-		  if (isonum_711 (vdp->type) != ISO_VD_PRIMARY)
-			goto out;
-		  if (isonum_711 (vdp->type) == ISO_VD_END)
-			goto out;
-		
-		        pri = (struct iso_primary_descriptor *)vdp;
-			break;
-	        }
+		/* Just skip any volume descriptors we don't recognize */
+	    }
 
-		brelse(bh);
-	      }
-	if(iso_blknum == vol_desc_start + 100) {
-		if (!silent)
-			printk("Unable to identify CD-ROM format.\n");
-		s->s_dev = 0;
-		unlock_super(s);
-		MOD_DEC_USE_COUNT;
-		return NULL;
+	    brelse(bh);
 	}
-	
+	if ((pri == NULL) && (sec == NULL) && (h_pri == NULL)) {
+	    if (!silent)
+		printk("Unable to identify CD-ROM format.\n");
+	    s->s_dev = 0;
+	    unlock_super(s);
+	    MOD_DEC_USE_COUNT;
+	    return NULL;
+	}
+	s->u.isofs_sb.s_joliet_level = joliet_level;
+	if (joliet_level && opt.rock == 'n') {
+	    /* This is the case of Joliet with the norock mount flag.
+	     * A disc with both Joliet and Rock Ridge is handled later
+	     */
+	    pri = (struct iso_primary_descriptor *) sec;
+	}
+
 	if(high_sierra){
 	  rootp = (struct iso_directory_record *) h_pri->root_directory_record;
 #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
@@ -365,11 +430,6 @@
 	      goto out;
 	  }
 
-	/* RDE: data zone now byte offset! */
-
-	s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) + 
-					   isonum_711 (rootp->ext_attr_length))
-					 << s -> u.isofs_sb.s_log_zone_size);
 	s->s_magic = ISOFS_SUPER_MAGIC;
 	
 	/* The CDROM is read-only, has no nodes (devices) on it, and since
@@ -381,13 +441,17 @@
 	
 	brelse(bh);
 	
+	/* RDE: data zone now byte offset! */
+
+	s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) + 
+					   isonum_711 (rootp->ext_attr_length))
+					 << s -> u.isofs_sb.s_log_zone_size);
 	printk(KERN_DEBUG "Max size:%ld   Log zone size:%ld\n",
 	       s->u.isofs_sb.s_max_size, 
 	       1UL << s->u.isofs_sb.s_log_zone_size);
-	printk(KERN_DEBUG "First datazone:%ld   Root inode number %d\n",
+	printk(KERN_DEBUG "First datazone:%ld   Root inode number %ld\n",
 	       s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size,
-	       (isonum_733(rootp->extent) + isonum_711(rootp->ext_attr_length))
-			<< s -> u.isofs_sb.s_log_zone_size);
+	       s->u.isofs_sb.s_firstdatazone);
 	if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n");
 	unlock_super(s);
 	/* set up enough so that it can read an inode */
@@ -412,16 +476,36 @@
 	    printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize);
 	  }
 
+	s->u.isofs_sb.s_nls_iocharset = NULL;
+	if (joliet_level == 0) {
+		if (opt.iocharset) {
+			kfree(opt.iocharset);
+			opt.iocharset = NULL;
+		}
+	} else if (opt.utf8 == 0) {
+		p = opt.iocharset ? opt.iocharset : "iso8859-1";
+		s->u.isofs_sb.s_nls_iocharset = load_nls(p);
+		if (! s->u.isofs_sb.s_nls_iocharset) {
+			/* Fail only if explicit charset specified */
+			if (opt.iocharset) {
+				kfree(opt.iocharset);
+				goto out;
+			} else {
+				s->u.isofs_sb.s_nls_iocharset = load_nls_default();
+			}
+		}
+	}
 	s->s_dev = dev;
 	s->s_op = &isofs_sops;
 	s->u.isofs_sb.s_mapping = opt.map;
-	s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 1 : 0);
+	s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0);
 	s->u.isofs_sb.s_name_check = opt.check;
 	s->u.isofs_sb.s_conversion = opt.conversion;
 	s->u.isofs_sb.s_cruft = opt.cruft;
 	s->u.isofs_sb.s_unhide = opt.unhide;
 	s->u.isofs_sb.s_uid = opt.uid;
 	s->u.isofs_sb.s_gid = opt.gid;
+	s->u.isofs_sb.s_utf8 = opt.utf8;
 	/*
 	 * It would be incredibly stupid to allow people to mark every file on the disk
 	 * as suid, so we merely allow them to set the default permissions.
@@ -429,21 +513,47 @@
 	s->u.isofs_sb.s_mode = opt.mode & 0777;
 	s->s_blocksize = opt.blocksize;
 	s->s_blocksize_bits = blocksize_bits;
-	s->s_mounted = iget(s, (isonum_733(rootp->extent) + 
-			    isonum_711(rootp->ext_attr_length))
-				<< s -> u.isofs_sb.s_log_zone_size);
+	s->s_mounted = iget(s, s->u.isofs_sb.s_firstdatazone);
+
+	/*
+	 * If this disk has both Rock Ridge and Joliet on it, then we
+	 * want to use Rock Ridge by default.  This can be overridden
+	 * by using the norock mount option.  There is still one other
+	 * possibility that is not taken into account: a Rock Ridge
+	 * CD with Unicode names.  Until someone sees such a beast, it
+	 * will not be supported.
+	 */
+	if (joliet_level && opt.rock == 'y' && s->u.isofs_sb.s_rock != 1) {
+		iput(s->s_mounted);
+		pri = (struct iso_primary_descriptor *) sec;
+		rootp = (struct iso_directory_record *)
+			pri->root_directory_record;
+		s->u.isofs_sb.s_firstdatazone =
+			((isonum_733 (rootp->extent) +
+			  isonum_711 (rootp->ext_attr_length))
+			 << s -> u.isofs_sb.s_log_zone_size);
+		s->s_mounted = iget(s, s->u.isofs_sb.s_firstdatazone);
+		s->u.isofs_sb.s_rock = 0;
+	}
 	unlock_super(s);
 
 	if (!(s->s_mounted)) {
 		s->s_dev = 0;
 		printk("get root inode failed\n");
+		if (s->u.isofs_sb.s_nls_iocharset)
+			unload_nls(s->u.isofs_sb.s_nls_iocharset);
+		if (opt.iocharset) kfree(opt.iocharset);
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 
 	if(!check_disk_change(s->s_dev)) {
-	  return s;
+		return s;
 	}
+	if (s->u.isofs_sb.s_nls_iocharset)
+		unload_nls(s->u.isofs_sb.s_nls_iocharset);
+	if (opt.iocharset) kfree(opt.iocharset);
+
  out: /* Kick out for various error conditions */
 	brelse(bh);
 	s->s_dev = 0;
@@ -470,17 +580,24 @@
 
 int isofs_bmap(struct inode * inode,int block)
 {
+	off_t b_off, offset, size;
+	struct inode *ino;
+	unsigned int firstext;
+	unsigned long nextino;
+	int i;
 
 	if (block<0) {
 		printk("_isofs_bmap: block<0");
 		return 0;
 	}
 
+	b_off = block << ISOFS_BUFFER_BITS(inode);
+
 	/*
 	 * If we are beyond the end of this file, don't give out any
 	 * blocks.
 	 */
-	if( (block << ISOFS_BUFFER_BITS(inode)) > inode->i_size )
+	if( b_off > inode->i_size )
 	  {
 	    off_t	max_legal_read_offset;
 
@@ -494,7 +611,7 @@
 	     */
 	    max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1) 
 	      & ~(PAGE_SIZE - 1);
-	    if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset )
+	    if( b_off >= max_legal_read_offset )
 	      {
 
 		printk("_isofs_bmap: block>= EOF(%d, %ld)", block, 
@@ -503,7 +620,44 @@
 	    return 0;
 	  }
 
-	return (inode->u.isofs_i.i_first_extent >> ISOFS_BUFFER_BITS(inode)) + block;
+	offset = 0;
+	firstext = inode->u.isofs_i.i_first_extent;
+	size = inode->u.isofs_i.i_section_size;
+	nextino = inode->u.isofs_i.i_next_section_ino;
+#ifdef DEBUG
+	printk("first inode: inode=%lu nextino=%lu firstext=%u size=%lu\n",
+		inode->i_ino, nextino, firstext, size);
+#endif
+	i = 0;
+	if (nextino) {
+		while(b_off >= offset + size) {
+			offset += size;
+
+			if(nextino == 0) return 0;
+			ino = iget(inode->i_sb, nextino);
+			if(!ino) return 0;
+			firstext = ino->u.isofs_i.i_first_extent;
+			size = ino->u.isofs_i.i_section_size;
+#ifdef DEBUG
+			printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
+			       inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
+#endif
+			nextino = ino->u.isofs_i.i_next_section_ino;
+			iput(ino);
+		
+			if(++i > 100) {
+				printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
+				printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
+				       inode->i_ino, block, firstext, (unsigned)size, nextino);
+				return 0;
+			}
+		}
+	}
+#ifdef DEBUG
+	printk("isofs_bmap: mapped inode:block %lu:%d to block %lu\n",
+		inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
+#endif
+	return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
 }
 
 
@@ -517,6 +671,82 @@
 	}
 }
 
+static int isofs_read_level3_size(struct inode * inode)
+{
+	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
+	struct buffer_head * bh = NULL;
+	struct iso_directory_record * raw_inode = NULL;		/* quiet gcc */
+	unsigned char *pnt = NULL;
+	void *cpnt = NULL;
+	int block = 0;			/* Quiet GCC */
+	unsigned long ino;
+	int i;
+
+	inode->i_size = 0;
+	inode->u.isofs_i.i_next_section_ino = 0;
+	ino = inode->i_ino;
+	i = 0;
+	do {
+		if(i > 100) {
+			printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n"
+			       "isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino);
+			return 0;
+		}
+
+		if(bh == NULL || block != ino >> ISOFS_BUFFER_BITS(inode)) {
+			if(bh) brelse(bh);
+			block = ino >> ISOFS_BUFFER_BITS(inode);
+			if (!(bh=bread(inode->i_dev,block, bufsize))) {
+				printk("unable to read i-node block");
+				return 1;
+			}
+		}
+		pnt = ((unsigned char *) bh->b_data
+		       + (ino & (bufsize - 1)));
+	
+		if ((ino & (bufsize - 1)) + *pnt > bufsize){
+		        int frag1, offset;
+	
+			offset = (ino & (bufsize - 1));
+			frag1 = bufsize - offset;
+		        cpnt = kmalloc(*pnt,GFP_KERNEL);
+			if (cpnt == NULL) {
+				printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino);
+				brelse(bh);
+				return 1;
+			}
+			memcpy(cpnt, bh->b_data + offset, frag1);
+			brelse(bh);
+			if (!(bh = bread(inode->i_dev,++block, bufsize))) {
+				kfree(cpnt);
+				printk("unable to read i-node block");
+				return 1;
+			}
+			offset += *pnt - bufsize;
+			memcpy((char *)cpnt+frag1, bh->b_data, offset);
+			pnt = ((unsigned char *) cpnt);
+		}
+		
+		if(*pnt == 0) {
+			ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE;
+			continue;
+		}
+		raw_inode = ((struct iso_directory_record *) pnt);
+
+		inode->i_size += isonum_733 (raw_inode->size);
+		if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
+
+		ino += *pnt;
+		if (cpnt) {
+			kfree (cpnt);
+			cpnt = NULL;
+		}
+		i++;
+	} while(raw_inode->flags[-inode->i_sb->u.isofs_sb.s_high_sierra] & 0x80);
+	brelse(bh);
+	return 0;
+}
+
 void isofs_read_inode(struct inode * inode)
 {
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
@@ -584,7 +814,13 @@
 	}
 	inode->i_uid = inode->i_sb->u.isofs_sb.s_uid;
 	inode->i_gid = inode->i_sb->u.isofs_sb.s_gid;
-	inode->i_size = isonum_733 (raw_inode->size);
+
+	inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size);
+	if(raw_inode->flags[-high_sierra] & 0x80) {
+		if(isofs_read_level3_size(inode)) goto fail;
+	} else {
+		inode->i_size = isonum_733 (raw_inode->size);
+	}
 
 	/* There are defective discs out there - we do this to protect
 	   ourselves.  A cdrom will never contain more than 800Mb */
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/joliet.c linux/fs/isofs/joliet.c
--- v2.0.33/linux/fs/isofs/joliet.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/isofs/joliet.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,111 @@
+/*
+ *  linux/fs/isofs/joliet.c
+ *
+ *  (C) 1996 Gordon Chaffee
+ *
+ *  Joliet: Microsoft's Unicode extensions to iso9660
+ */
+
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/nls.h>
+#include <linux/malloc.h>
+#include <linux/iso_fs.h>
+
+/*
+ * Convert Unicode 16 to UTF8 or ascii.
+ */
+static int
+uni16_to_x8(unsigned char *ascii, unsigned char *uni, int len,
+	    struct nls_table *nls)
+{
+	unsigned char *ip, *op;
+	unsigned char ch, cl;
+	unsigned char *uni_page;
+
+	ip = uni;
+	op = ascii;
+
+	while ((*ip || ip[1]) && len) {
+		ch = *ip++;
+		cl = *ip++;
+
+		uni_page = nls->page_uni2charset[ch];
+		if (uni_page && uni_page[cl]) {
+			*op++ = uni_page[cl];
+		} else {
+			*op++ = '?';
+		}
+		len--;
+	}
+	*op = 0;
+	return (op - ascii);
+}
+
+/* Convert big endian wide character string to utf8 */
+static int
+wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
+{
+	const __u8 *ip;
+	__u8 *op;
+	int size;
+	__u16 c;
+
+	op = s;
+	ip = pwcs;
+	while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
+		c = (*ip << 8) | ip[1];
+		if (c > 0x7f) {
+			size = utf8_wctomb(op, c, maxlen);
+			if (size == -1) {
+				/* Ignore character and move on */
+				maxlen--;
+			} else {
+				op += size;
+				maxlen -= size;
+			}
+		} else {
+			*op++ = (__u8) c;
+		}
+		ip += 2;
+		inlen--;
+	}
+	return (op - s);
+}
+
+int
+get_joliet_filename(struct iso_directory_record * de, struct inode * inode,
+		    unsigned char *outname)
+{
+	unsigned char utf8;
+	struct nls_table *nls;
+	unsigned char len = 0;
+	int i;
+	char c;
+
+	utf8 = inode->i_sb->u.isofs_sb.s_utf8;
+	nls = inode->i_sb->u.isofs_sb.s_nls_iocharset;
+
+	if (utf8) {
+		len = wcsntombs_be(outname, de->name,
+				   de->name_len[0] >> 1, PAGE_SIZE);
+	} else {
+		len = uni16_to_x8(outname, de->name,
+				  de->name_len[0] >> 1, nls);
+	}
+	if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
+		len -= 2;
+	}
+
+        if (inode->i_sb->u.isofs_sb.s_name_check == 'r') {
+               for (i = 0; i < len; i++) {
+                       c = outname[i];
+                       /* lower case */
+                       if (c >= 'A' && c <= 'Z') c |= 0x20;
+                       if (c == ';') c = '.';
+                       outname[i] = c;
+               }
+	}
+
+	return len;
+}
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.0.33/linux/fs/isofs/namei.c	Tue Aug 12 14:06:35 1997
+++ linux/fs/isofs/namei.c	Wed Jun  3 15:17:49 1998
@@ -58,8 +58,9 @@
  * itself (as an inode number). It does NOT read the inode of the
  * entry - you'll have to do that yourself if you want to.
  */
-static struct buffer_head * isofs_find_entry(struct inode * dir,
-	const char * name, int namelen, unsigned long * ino, unsigned long * ino_back)
+static struct buffer_head *
+isofs_find_entry(struct inode * dir, const char * name, int namelen,
+		 unsigned long * ino, unsigned long * ino_back)
 {
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
@@ -68,8 +69,9 @@
 	void * cpnt = NULL;
 	unsigned int old_offset;
 	unsigned int backlink;
-	int dlen, rrflag, match;
+	int dlen, match;
 	char * dpnt;
+	unsigned char *page = NULL;
 	struct iso_directory_record * de;
 	char c;
 
@@ -100,7 +102,7 @@
 				 + ISOFS_BLOCK_SIZE);
 			block = isofs_bmap(dir,f_pos>>bufbits);
 			if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
-				return 0;
+				return NULL;
 			continue; /* Will kick out if past end of directory */
 		}
 
@@ -114,7 +116,7 @@
 		        unsigned int frag1;
 			frag1 = bufsize - old_offset;
 			cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
-			if (!cpnt) return 0;
+			if (!cpnt) return NULL;
 			memcpy(cpnt, bh->b_data + old_offset, frag1);
 
 			de = (struct iso_directory_record *) cpnt;
@@ -123,21 +125,24 @@
 			block = isofs_bmap(dir,f_pos>>bufbits);
 			if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
 			        kfree(cpnt);
-				return 0;
+				return NULL;
 			};
 			memcpy((char *)cpnt+frag1, bh->b_data, offset);
 		}
-		
+
+		dlen = de->name_len[0];
+		dpnt = de->name;
+
 		/* Handle the '.' case */
 		
-		if (de->name[0]==0 && de->name_len[0]==1) {
+		if (*dpnt==0 && dlen==1) {
 			inode_number = dir->i_ino;
 			backlink = 0;
 		}
 		
 		/* Handle the '..' case */
 
-		if (de->name[0]==1 && de->name_len[0]==1) {
+		else if (*dpnt==1 && dlen==1) {
 #if 0
 			printk("Doing .. (%d %d)",
 			       dir->i_sb->s_firstdatazone,
@@ -148,31 +153,39 @@
 			else
 				inode_number = dir->i_ino;
 			backlink = 0;
-		}
-    
-		dlen = de->name_len[0];
-		dpnt = de->name;
-		/* Now convert the filename in the buffer to lower case */
-		rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir);
-		if (rrflag) {
-		  if (rrflag == -1) goto out; /* Relocated deep directory */
 		} else {
-		  if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
-		    for (i = 0; i < dlen; i++) {
-		      c = dpnt[i];
-		      if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
-		      if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
-			dlen -= 2;
-			break;
-		      }
-		      if (c == ';') c = '.';
-		      de->name[i] = c;
-		    }
-		    /* This allows us to match with and without a trailing
-		       period.  */
-		    if(dpnt[dlen-1] == '.' && namelen == dlen-1)
-		      dlen--;
-		  }
+			if (dir->i_sb->u.isofs_sb.s_rock ||
+			    dir->i_sb->u.isofs_sb.s_joliet_level) {
+				page = (unsigned char *)
+					__get_free_page(GFP_KERNEL);
+				if (!page) return NULL;
+			}
+			if (dir->i_sb->u.isofs_sb.s_rock &&
+			    ((i = get_rock_ridge_filename(de, page, dir)))){
+				if (i == -1)
+					goto out;/* Relocated deep directory */
+				dlen = i;
+				dpnt = page;
+			} else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
+				dlen = get_joliet_filename(de, dir, page);
+				dpnt = page;
+			} else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
+				for (i = 0; i < dlen; i++) {
+					c = dpnt[i];
+					/* lower case */
+					if (c >= 'A' && c <= 'Z') c |= 0x20;
+					if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
+						dlen -= 2;
+						break;
+					}
+					if (c == ';') c = '.';
+					dpnt[i] = c;
+				}
+				/* This allows us to match with and without
+				 * a trailing period. */
+				if(dpnt[dlen-1] == '.' && namelen == dlen-1)
+					dlen--;
+			}
 		}
 		/*
 		 * Skip hidden or associated files unless unhide is set 
@@ -190,7 +203,7 @@
 			cpnt = NULL;
 		}
 
-		if(rrflag) kfree(dpnt);
+		if (page) free_page((unsigned long) page);
 		if (match) {
 			if(inode_number == -1) {
 				/* Should only happen for the '..' entry */
@@ -239,6 +252,7 @@
 
 	if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
 
+
 	if (!ino) {
 		char *lcname;
 
@@ -265,8 +279,9 @@
 			iput(dir);
 	  		return -ENOENT;
 		}
-		if (ino_back == dir->i_ino)
+		if (ino_back == dir->i_ino) {
 			dcache_add(dir, name, len, ino);
+		}
 		brelse(bh);
 	}
 
@@ -282,7 +297,7 @@
 	*/
 	
 	if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
-	  (*result)->u.isofs_i.i_backlink = ino_back; 
+		(*result)->u.isofs_i.i_backlink = ino_back; 
 	}
 	
 	iput(dir);
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- v2.0.33/linux/fs/isofs/rock.c	Fri Aug 15 11:10:51 1997
+++ linux/fs/isofs/rock.c	Wed Jun  3 15:17:49 1998
@@ -168,15 +168,16 @@
 }
 
 int get_rock_ridge_filename(struct iso_directory_record * de,
-			   char ** name, int * namlen, struct inode * inode)
+			    char * retname, struct inode * inode)
 {
   int len;
   unsigned char * chr;
   CONTINUE_DECLS;
-  char * retname = NULL;
   int retnamlen = 0, truncate=0;
  
   if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
+  *retname = 0;
+  retnamlen = 0;
 
   SETUP_ROCK_RIDGE(de, chr, len);
  repeat:
@@ -207,18 +208,6 @@
 	  printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
 	  break;
 	};
-	if (!retname){
-	  retname = (char *) kmalloc (255,GFP_KERNEL);
-	  /* This may be a waste, but we only
-	     need this for a moment.  The layers
-	     that call this function should
-	     deallocate the mem fairly soon
-	     after control is returned */
-
-	  if (!retname) goto out;
-	  *retname = 0; /* Zero length string */
-	  retnamlen = 0;
-	};
 	if((strlen(retname) + rr->len - 5) >= 254) {
 	  truncate = 1;
 	  break;
@@ -231,7 +220,6 @@
 	printk("RR: RE (%x)\n", inode->i_ino);
 #endif
 	if (buffer) kfree(buffer);
-	if (retname) kfree(retname);
 	return -1;
       default:
 	break;
@@ -239,15 +227,9 @@
     };
   }
   MAYBE_CONTINUE(repeat,inode);
-  if(retname){
-    *name = retname;
-    *namlen = retnamlen;
-    return 1;
-  };
-  return 0;  /* This file did not have a NM field */
+  return retnamlen; /* If 0, this file did not have a NM field */
  out:
   if(buffer) kfree(buffer);
-  if (retname) kfree(retname);
   return 0;
 }
 
@@ -287,6 +269,7 @@
 	CHECK_CE;
 	break;
       case SIG('E','R'):
+	inode->i_sb->u.isofs_sb.s_rock = 1;
 	printk(KERN_DEBUG"ISO9660 Extensions: ");
 	{ int p;
 	  for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/util.c linux/fs/isofs/util.c
--- v2.0.33/linux/fs/isofs/util.c	Tue May 28 21:26:48 1996
+++ linux/fs/isofs/util.c	Wed Jun  3 15:17:49 1998
@@ -9,6 +9,8 @@
  *  the 386bsd iso9660 filesystem, by Pace Willisson <pace@blitz.com>.
  */
 
+#include <linux/time.h>
+
 int
 isonum_711 (char * p)
 {
@@ -84,10 +86,9 @@
 	return (isonum_731 (p));
 }
 
-/* We have to convert from a MM/DD/YY format to the unix ctime format.  We have to
-   take into account leap years and all of that good stuff.  Unfortunately, the kernel
-   does not have the information on hand to take into account daylight savings time,
-   so there will be cases (roughly half the time) where the dates are off by one hour. */
+/* We have to convert from a MM/DD/YY format to the unix ctime format.
+ * We have to take into account leap years and all of that good stuff.
+ */
 int iso_date(char * p, int flag)
 {
 	int year, month, day, hour ,minute, second, tz;
@@ -106,6 +107,8 @@
 		crtime = 0;
 	} else {
 		int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+		extern struct timezone sys_tz;
+
 		days = year * 365;
 		if (year > 2)
 			days += (year+1) / 4;
@@ -116,7 +119,9 @@
 		days += day - 1;
 		crtime = ((((days * 24) + hour) * 60 + minute) * 60)
 			+ second;
-		
+		if (sys_tz.tz_dsttime)
+			crtime -= 3600;
+
 		/* sign extend */
 		if (tz & 0x80)
 			tz |= (-1 << 8);
diff -u --recursive --new-file v2.0.33/linux/fs/locks.c linux/fs/locks.c
--- v2.0.33/linux/fs/locks.c	Tue Dec  2 13:52:32 1997
+++ linux/fs/locks.c	Wed Jun  3 15:17:49 1998
@@ -51,7 +51,7 @@
  *
  *  Removed some race conditions in flock_lock_file(), marked other possible
  *  races. Just grep for FIXME to see them. 
- *  Dmitry Gorodchanin (begemot@bgm.rosprint.net), February 09, 1996.
+ *  Dmitry Gorodchanin (pgmdsg@ibi.com), February 09, 1996.
  *
  *  Addressed Dmitry's concerns. Deadlock checking no longer recursive.
  *  Lock allocation changed to GFP_ATOMIC as we can't afford to sleep
diff -u --recursive --new-file v2.0.33/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v2.0.33/linux/fs/minix/bitmap.c	Sat Nov 30 02:21:20 1996
+++ linux/fs/minix/bitmap.c	Wed Jun  3 15:17:49 1998
@@ -187,7 +187,7 @@
 		return;
 	}
 	if (inode->i_count != 1) {
-		printk("free_inode: inode has count=%d\n",inode->i_count);
+		printk("free_inode: inode has count=%ld\n",inode->i_count);
 		return;
 	}
 	if (inode->i_nlink) {
diff -u --recursive --new-file v2.0.33/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.0.33/linux/fs/msdos/namei.c	Sat Nov 30 02:21:21 1996
+++ linux/fs/msdos/namei.c	Wed Jun  3 15:17:49 1998
@@ -60,6 +60,7 @@
 
 	MOD_INC_USE_COUNT;
 
+	MSDOS_SB(sb)->options.isvfat = 0;
 	sb->s_op = &msdos_sops;
 	res =  fat_read_super(sb, data, silent);
 	if (res == NULL)
@@ -263,7 +264,9 @@
 
 	if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
 		if (res != -ENOENT) return res;
-		if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+		if ((dir->i_ino == MSDOS_ROOT_INO) &&
+		    (MSDOS_SB(sb)->fat_bits != 32))
+			return -ENOSPC;
 		if ((res = fat_add_cluster(dir)) < 0) return res;
 		if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) return res;
 	}
@@ -273,10 +276,10 @@
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->i_dirt = 1;
 	memcpy(de->name,name,MSDOS_NAME);
-	memset(de->unused, 0, sizeof(de->unused));
 	de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 	de->attr = is_hid ? (de->attr|ATTR_HIDDEN) : (de->attr&~ATTR_HIDDEN);
 	de->start = 0;
+	de->starthi = 0;
 	fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
 	de->size = 0;
 	fat_mark_buffer_dirty(sb, bh, 1);
@@ -367,6 +370,9 @@
 		pos = 0;
 		bh = NULL;
 		while (fat_get_entry(dir,&pos,&bh,&de) > -1)
+			/* Ignore vfat longname entries */
+			if (de->attr == ATTR_EXT)
+				continue;
 			if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
 			    MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
 			    MSDOS_NAME)) {
@@ -456,6 +462,7 @@
 		goto mkdir_error;
 	dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
 	MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
+	MSDOS_I(dot)->i_logstart = MSDOS_I(inode)->i_logstart;
 	dot->i_nlink = inode->i_nlink;
 	dot->i_dirt = 1;
 	iput(dot);
@@ -464,6 +471,7 @@
 	fat_unlock_creation();
 	dot->i_size = dir->i_size;
 	MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
+	MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
 	dot->i_nlink = dir->i_nlink;
 	dot->i_dirt = 1;
 	MSDOS_I(inode)->i_busy = 0;
@@ -718,8 +726,10 @@
 			error = -EIO;
 			goto rename_done;
 		}
-		dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
-		    MSDOS_I(new_dir)->i_start;
+		MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
+		MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
+		dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
+		dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
 		dotdot_inode->i_dirt = 1;
 		fat_mark_buffer_dirty(sb, dotdot_bh, 1);
 		old_dir->i_nlink--;
diff -u --recursive --new-file v2.0.33/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.0.33/linux/fs/ncpfs/inode.c	Tue Aug  5 09:33:12 1997
+++ linux/fs/ncpfs/inode.c	Wed Jun  3 15:17:49 1998
@@ -145,7 +145,7 @@
 	lock_super(sb);
 
 	if (inode->i_count > 1) {
-printk("ncp_put_inode: inode in use device %s, inode %ld, count=%d\n", 
+printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n", 
 kdevname(inode->i_dev), inode->i_ino, inode->i_count);
 		goto unlock;
 	}
diff -u --recursive --new-file v2.0.33/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.0.33/linux/fs/nfs/dir.c	Tue Apr  8 08:47:46 1997
+++ linux/fs/nfs/dir.c	Wed Jun  3 15:17:49 1998
@@ -491,6 +491,8 @@
 			nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
 	}
 	iput(dir);
+	/* The parent dir link count may have changed */
+	nfs_lookup_cache_remove( NULL, dir, NULL);
 	return error;
 }
 
@@ -693,7 +695,17 @@
 		return;
 	}
 	was_empty = (inode->i_mode == 0);
-	inode->i_mode = fattr->mode;
+	
+	/*
+	 * Some (broken?) NFS servers return 0 as the file type.
+	 * We'll assume that 0 means the file type has not changed.
+	 */
+	if(!(fattr->mode & S_IFMT)){
+		inode->i_mode = (inode->i_mode & S_IFMT) |
+				(fattr->mode & ~S_IFMT);
+	}else{
+		inode->i_mode = fattr->mode;
+	}
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
 	inode->i_gid = fattr->gid;
diff -u --recursive --new-file v2.0.33/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- v2.0.33/linux/fs/nfs/proc.c	Wed Jul  3 03:52:09 1996
+++ linux/fs/nfs/proc.c	Wed Jun  3 15:17:49 1998
@@ -1002,6 +1002,7 @@
 	{ NFSERR_EAGAIN,	EAGAIN		},
 	{ NFSERR_ACCES,		EACCES		},
 	{ NFSERR_EXIST,		EEXIST		},
+	{ NFSERR_XDEV,		EXDEV		},
 	{ NFSERR_NODEV,		ENODEV		},
 	{ NFSERR_NOTDIR,	ENOTDIR		},
 	{ NFSERR_ISDIR,		EISDIR		},
diff -u --recursive --new-file v2.0.33/linux/fs/nls.c linux/fs/nls.c
--- v2.0.33/linux/fs/nls.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,528 @@
+/*
+ * linux/fs/nls.c
+ *
+ * Native language support--charsets and unicode translations.
+ * By Gordon Chaffee 1996, 1997
+ *
+ */
+#ifndef _LINUX_FS_NLS_C
+#define _LINUX_FS_NLS_C
+
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/nls.h>
+#include <linux/malloc.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+#include <asm/byteorder.h>
+
+static struct nls_table *tables = (struct nls_table *) NULL;
+
+/*
+ * Sample implementation from Unicode home page.
+ * http://www.stonehand.com/unicode/standard/fss-utf.html
+ */
+struct utf8_table {
+	int     cmask;
+	int     cval;
+	int     shift;
+	long    lmask;
+	long    lval;
+};
+
+static struct utf8_table utf8_table[] =
+{
+    {0x80,  0x00,   0*6,    0x7F,           0,         /* 1 byte sequence */},
+    {0xE0,  0xC0,   1*6,    0x7FF,          0x80,      /* 2 byte sequence */},
+    {0xF0,  0xE0,   2*6,    0xFFFF,         0x800,     /* 3 byte sequence */},
+    {0xF8,  0xF0,   3*6,    0x1FFFFF,       0x10000,   /* 4 byte sequence */},
+    {0xFC,  0xF8,   4*6,    0x3FFFFFF,      0x200000,  /* 5 byte sequence */},
+    {0xFE,  0xFC,   5*6,    0x7FFFFFFF,     0x4000000, /* 6 byte sequence */},
+    {0,						       /* end of table    */}
+};
+
+int
+utf8_mbtowc(__u16 *p, const __u8 *s, int n)
+{
+	long l;
+	int c0, c, nc;
+	struct utf8_table *t;
+  
+	printk("utf8_mbtowc\n");
+	nc = 0;
+	c0 = *s;
+	l = c0;
+	for (t = utf8_table; t->cmask; t++) {
+		nc++;
+		if ((c0 & t->cmask) == t->cval) {
+			l &= t->lmask;
+			if (l < t->lval)
+				return -1;
+			*p = l;
+			return nc;
+		}
+		if (n <= nc)
+			return -1;
+		s++;
+		c = (*s ^ 0x80) & 0xFF;
+		if (c & 0xC0)
+			return -1;
+		l = (l << 6) | c;
+	}
+	return -1;
+}
+
+int
+utf8_mbstowcs(__u16 *pwcs, const __u8 *s, int n)
+{
+	__u16 *op;
+	const __u8 *ip;
+	int size;
+
+	printk("\nutf8_mbstowcs: n=%d\n", n);
+	op = pwcs;
+	ip = s;
+	while (*ip && n > 0) {
+		printk(" %02x", *ip);
+		if (*ip & 0x80) {
+			size = utf8_mbtowc(op, ip, n);
+			if (size == -1) {
+				/* Ignore character and move on */
+				ip++;
+				n--;
+			} else {
+				op += size;
+				ip += size;
+				n -= size;
+			}
+		} else {
+			*op++ = *ip++;
+		}
+	}
+	return (op - pwcs);
+}
+
+int
+utf8_wctomb(__u8 *s, __u16 wc, int maxlen)
+{
+	long l;
+	int c, nc;
+	struct utf8_table *t;
+  
+	if (s == 0)
+		return 0;
+  
+	l = wc;
+	nc = 0;
+	for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
+		nc++;
+		if (l <= t->lmask) {
+			c = t->shift;
+			*s = t->cval | (l >> c);
+			while (c > 0) {
+				c -= 6;
+				s++;
+				*s = 0x80 | ((l >> c) & 0x3F);
+			}
+			return nc;
+		}
+	}
+	return -1;
+}
+
+int
+utf8_wcstombs(__u8 *s, const __u16 *pwcs, int maxlen)
+{
+	const __u16 *ip;
+	__u8 *op;
+	int size;
+
+	op = s;
+	ip = pwcs;
+	while (*ip && maxlen > 0) {
+		if (*ip > 0x7f) {
+			size = utf8_wctomb(op, *ip, maxlen);
+			if (size == -1) {
+				/* Ignore character and move on */
+				maxlen--;
+			} else {
+				op += size;
+				maxlen -= size;
+			}
+		} else {
+			*op++ = (__u8) *ip;
+		}
+		ip++;
+	}
+	return (op - s);
+}
+
+int register_nls(struct nls_table * nls)
+{
+	struct nls_table ** tmp = &tables;
+
+	if (!nls)
+		return -EINVAL;
+	if (nls->next)
+		return -EBUSY;
+	while (*tmp) {
+		if (nls == *tmp) {
+			return -EBUSY;
+		}
+		tmp = &(*tmp)->next;
+	}
+	nls->next = tables;
+	tables = nls;
+	return 0;	
+}
+
+int unregister_nls(struct nls_table * nls)
+{
+	struct nls_table ** tmp = &tables;
+
+	while (*tmp) {
+		if (nls == *tmp) {
+			*tmp = nls->next;
+			return 0;
+		}
+		tmp = &(*tmp)->next;
+	}
+	return -EINVAL;
+}
+
+struct nls_table *find_nls(char *charset)
+{
+	struct nls_table *nls = tables;
+	while (nls) {
+		if (! strcmp(nls->charset, charset))
+			return nls;
+		nls = nls->next;
+	}
+	return NULL;
+}
+
+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) {
+		nls->inc_use_count();
+		return nls;
+	}
+
+#ifndef CONFIG_KERNELD
+	return NULL;
+#else
+	if (strlen(charset) > sizeof(buf) - sizeof("nls_")) {
+		printk("Unable to load NLS charset %s: name too long\n", charset);
+		return NULL;
+	}
+		
+	sprintf(buf, "nls_%s", charset);
+	ret = strlen(buf);
+
+	/* Hack to get around genksyms problem */
+	if (buf[ret-2] == '-')
+		buf[ret-2] = '_';
+	if (buf[ret-3] == '-')
+		buf[ret-3] = '_';
+
+	ret = request_module(buf);
+	if (ret != 0) {
+		printk("Unable to load NLS charset %s(%s)\n", charset, buf);
+		return NULL;
+	}
+	nls = find_nls(charset);
+	if (nls) {
+		nls->inc_use_count();
+	}
+	return nls;
+#endif
+}
+
+void unload_nls(struct nls_table *nls)
+{
+	nls->dec_use_count();
+}
+
+struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x80, 0x00}, {0x81, 0x00}, {0x82, 0x00}, {0x83, 0x00},
+	{0x84, 0x00}, {0x85, 0x00}, {0x86, 0x00}, {0x87, 0x00},
+	{0x88, 0x00}, {0x89, 0x00}, {0x8a, 0x00}, {0x8b, 0x00},
+	{0x8c, 0x00}, {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0x00},
+	/* 0x90*/
+	{0x90, 0x00}, {0x91, 0x00}, {0x92, 0x00}, {0x93, 0x00},
+	{0x94, 0x00}, {0x95, 0x00}, {0x96, 0x00}, {0x97, 0x00},
+	{0x98, 0x00}, {0x99, 0x00}, {0x9a, 0x00}, {0x9b, 0x00},
+	{0x9c, 0x00}, {0x9d, 0x00}, {0x9e, 0x00}, {0x9f, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+	{0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+	{0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+	{0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+	{0xb8, 0x00}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+	{0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0xbf, 0x00},
+	/* 0xc0*/
+	{0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+	{0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+	{0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+	{0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+	/* 0xd0*/
+	{0xd0, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+	{0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+	{0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+	{0xdc, 0x00}, {0xdd, 0x00}, {0xde, 0x00}, {0xdf, 0x00},
+	/* 0xe0*/
+	{0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+	{0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+	{0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+	{0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+	/* 0xf0*/
+	{0xf0, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+	{0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+	{0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+	{0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00
+};
+
+
+void inc_use_count(void)
+{
+}
+
+void dec_use_count(void)
+{
+}
+
+static struct nls_table default_table = {
+	"default",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+
+
+/* Returns a simple default translation table */
+struct nls_table *load_nls_default(void)
+{
+	return &default_table;
+}
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+#define X(sym) EXPORT_SYMBOL(sym);
+#define X_PUNCT ;
+#else
+#define X_PUNCT ,
+static struct symbol_table nls_syms = {
+#include <linux/symtab_begin.h>
+#endif
+X(register_nls) X_PUNCT
+X(unregister_nls) X_PUNCT
+X(unload_nls) X_PUNCT
+X(find_nls) X_PUNCT
+X(load_nls) X_PUNCT
+X(load_nls_default) X_PUNCT
+X(utf8_mbtowc) X_PUNCT
+X(utf8_mbstowcs) X_PUNCT
+X(utf8_wctomb) X_PUNCT
+X(utf8_wcstombs) X_PUNCT
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#include <linux/symtab_end.h>
+};                                           
+#endif
+
+int init_nls(void)
+{
+#ifdef CONFIG_NLS_ISO8859_1
+	init_nls_iso8859_1();
+#endif
+#ifdef CONFIG_NLS_ISO8859_2
+	init_nls_iso8859_2();
+#endif
+#ifdef CONFIG_NLS_ISO8859_3
+	init_nls_iso8859_3();
+#endif
+#ifdef CONFIG_NLS_ISO8859_4
+	init_nls_iso8859_4();
+#endif
+#ifdef CONFIG_NLS_ISO8859_5
+	init_nls_iso8859_5();
+#endif
+#ifdef CONFIG_NLS_ISO8859_6
+	init_nls_iso8859_6();
+#endif
+#ifdef CONFIG_NLS_ISO8859_7
+	init_nls_iso8859_7();
+#endif
+#ifdef CONFIG_NLS_ISO8859_8
+	init_nls_iso8859_8();
+#endif
+#ifdef CONFIG_NLS_ISO8859_9
+	init_nls_iso8859_9();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_437
+	init_nls_cp437();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_737
+	init_nls_cp737();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_775
+	init_nls_cp775();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_850
+	init_nls_cp850();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_852
+	init_nls_cp852();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_855
+	init_nls_cp855();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_857
+	init_nls_cp857();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_860
+	init_nls_cp860();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_861
+	init_nls_cp861();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_862
+	init_nls_cp862();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_863
+	init_nls_cp863();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_864
+	init_nls_cp864();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_865
+	init_nls_cp865();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_866
+	init_nls_cp866();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_869
+	init_nls_cp869();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_874
+	init_nls_cp874();
+#endif
+#ifdef CONFIG_NLS_KOI8_R
+	init_nls_koi8_r();
+#endif
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+	return 0;
+#else
+	return register_symtab(&nls_syms);
+#endif
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls();
+}
+
+
+void cleanup_module(void)
+{
+}
+#endif /* ifdef MODULE */
+
+#endif /* _LINUX_FS_NLS_C */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp437.c linux/fs/nls_cp437.c
--- v2.0.33/linux/fs/nls_cp437.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp437.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,452 @@
+/*
+ * linux/fs/nls_cp437.c
+ *
+ * Charset cp437 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+	{0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+	{0xee, 0x00}, {0xec, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+	{0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+	{0xff, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xa2, 0x00},
+	{0xa3, 0x00}, {0xa5, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+	{0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+	{0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+	{0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+	{0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+	/* 0xf0*/
+	{0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+	{0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+	0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+	0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+	0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+	0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp437",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp437(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp437();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp737.c linux/fs/nls_cp737.c
--- v2.0.33/linux/fs/nls_cp737.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp737.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,380 @@
+/*
+ * linux/fs/nls_cp737.c
+ *
+ * Charset cp737 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x91, 0x03}, {0x92, 0x03}, {0x93, 0x03}, {0x94, 0x03},
+	{0x95, 0x03}, {0x96, 0x03}, {0x97, 0x03}, {0x98, 0x03},
+	{0x99, 0x03}, {0x9a, 0x03}, {0x9b, 0x03}, {0x9c, 0x03},
+	{0x9d, 0x03}, {0x9e, 0x03}, {0x9f, 0x03}, {0xa0, 0x03},
+	/* 0x90*/
+	{0xa1, 0x03}, {0xa3, 0x03}, {0xa4, 0x03}, {0xa5, 0x03},
+	{0xa6, 0x03}, {0xa7, 0x03}, {0xa8, 0x03}, {0xa9, 0x03},
+	{0xb1, 0x03}, {0xb2, 0x03}, {0xb3, 0x03}, {0xb4, 0x03},
+	{0xb5, 0x03}, {0xb6, 0x03}, {0xb7, 0x03}, {0xb8, 0x03},
+	/* 0xa0*/
+	{0xb9, 0x03}, {0xba, 0x03}, {0xbb, 0x03}, {0xbc, 0x03},
+	{0xbd, 0x03}, {0xbe, 0x03}, {0xbf, 0x03}, {0xc0, 0x03},
+	{0xc1, 0x03}, {0xc3, 0x03}, {0xc2, 0x03}, {0xc4, 0x03},
+	{0xc5, 0x03}, {0xc6, 0x03}, {0xc7, 0x03}, {0xc8, 0x03},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xc9, 0x03}, {0xac, 0x03}, {0xad, 0x03}, {0xae, 0x03},
+	{0xca, 0x03}, {0xaf, 0x03}, {0xcc, 0x03}, {0xcd, 0x03},
+	{0xcb, 0x03}, {0xce, 0x03}, {0x86, 0x03}, {0x88, 0x03},
+	{0x89, 0x03}, {0x8a, 0x03}, {0x8c, 0x03}, {0x8e, 0x03},
+	/* 0xf0*/
+	{0x8f, 0x03}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+	{0xaa, 0x03}, {0xab, 0x03}, {0xf7, 0x00}, {0x48, 0x22},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0x00, 0x00, 0x00, 0x00, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, /* 0x80-0x87 */
+	0xeb, 0xec, 0xed, 0x00, 0xee, 0x00, 0xef, 0xf0, /* 0x88-0x8f */
+	0x00, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, /* 0x90-0x97 */
+	0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, /* 0x98-0x9f */
+	0x8f, 0x90, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, /* 0xa0-0xa7 */
+	0x96, 0x97, 0xf4, 0xf5, 0xe1, 0xe2, 0xe3, 0xe5, /* 0xa8-0xaf */
+	0x00, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, /* 0xb0-0xb7 */
+	0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, /* 0xb8-0xbf */
+	0xa7, 0xa8, 0xaa, 0xa9, 0xab, 0xac, 0xad, 0xae, /* 0xc0-0xc7 */
+	0xaf, 0xe0, 0xe4, 0xe8, 0xe6, 0xe7, 0xe9, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp737",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp737(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp737();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp775.c linux/fs/nls_cp775.c
--- v2.0.33/linux/fs/nls_cp775.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp775.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,380 @@
+/*
+ * linux/fs/nls_cp775.c
+ *
+ * Charset cp775 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x06, 0x01}, {0xfc, 0x00}, {0xe9, 0x00}, {0x01, 0x01},
+	{0xe4, 0x00}, {0x23, 0x01}, {0xe5, 0x00}, {0x07, 0x01},
+	{0x42, 0x01}, {0x13, 0x01}, {0x56, 0x01}, {0x57, 0x01},
+	{0x2b, 0x01}, {0x79, 0x01}, {0xc4, 0x00}, {0xc5, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0x4d, 0x01},
+	{0xf6, 0x00}, {0x22, 0x01}, {0xa2, 0x00}, {0x5a, 0x01},
+	{0x5b, 0x01}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+	{0xa3, 0x00}, {0xd8, 0x00}, {0xd7, 0x00}, {0xa4, 0x00},
+	/* 0xa0*/
+	{0x00, 0x01}, {0x2a, 0x01}, {0xf3, 0x00}, {0x7b, 0x01},
+	{0x7c, 0x01}, {0x7a, 0x01}, {0x1d, 0x20}, {0xa6, 0x00},
+	{0xa9, 0x00}, {0xae, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0x41, 0x01}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x04, 0x01}, {0x0c, 0x01}, {0x18, 0x01},
+	{0x16, 0x01}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x2e, 0x01}, {0x60, 0x01}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x72, 0x01}, {0x6a, 0x01},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x7d, 0x01},
+	/* 0xd0*/
+	{0x05, 0x01}, {0x0d, 0x01}, {0x19, 0x01}, {0x17, 0x01},
+	{0x2f, 0x01}, {0x61, 0x01}, {0x73, 0x01}, {0x6b, 0x01},
+	{0x7e, 0x01}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xd3, 0x00}, {0xdf, 0x00}, {0x4c, 0x01}, {0x43, 0x01},
+	{0xf5, 0x00}, {0xd5, 0x00}, {0xb5, 0x00}, {0x44, 0x01},
+	{0x36, 0x01}, {0x37, 0x01}, {0x3b, 0x01}, {0x3c, 0x01},
+	{0x46, 0x01}, {0x12, 0x01}, {0x45, 0x01}, {0x19, 0x20},
+	/* 0xf0*/
+	{0xad, 0x00}, {0xb1, 0x00}, {0x1c, 0x20}, {0xbe, 0x00},
+	{0xb6, 0x00}, {0xa7, 0x00}, {0xf7, 0x00}, {0x1e, 0x20},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0xb9, 0x00},
+	{0xb3, 0x00}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0x00, 0x96, 0x9c, 0x9f, 0x00, 0xa7, 0xf5, /* 0xa0-0xa7 */
+	0x00, 0xa8, 0x00, 0xae, 0xaa, 0xf0, 0xa9, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0xfc, 0x00, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0xfb, 0x00, 0xaf, 0xac, 0xab, 0xf3, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0xe0, 0x00, 0xe5, 0x99, 0x9e, /* 0xd0-0xd7 */
+	0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x84, 0x86, 0x91, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0xa2, 0x00, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */
+	0x9b, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0xa0, 0x83, 0x00, 0x00, 0xb5, 0xd0, 0x80, 0x87, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xb6, 0xd1, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0xed, 0x89, 0x00, 0x00, 0xb8, 0xd3, /* 0x10-0x17 */
+	0xb7, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x95, 0x85, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0xa1, 0x8c, 0x00, 0x00, 0xbd, 0xd4, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe9, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0xea, 0xeb, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0xad, 0x88, 0xe3, 0xe7, 0xee, 0xec, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0xe2, 0x93, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x8b, /* 0x50-0x57 */
+	0x00, 0x00, 0x97, 0x98, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0xbe, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0xc7, 0xd7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0xc6, 0xd6, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x8d, 0xa5, 0xa3, 0xa4, 0xcf, 0xd8, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xef, 0x00, 0x00, 0xf2, 0xa6, 0xf7, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+	0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+	0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+	0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x8a, 0x00, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x00, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0x00, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0x00, 0xe2, 0xe3, 0x00, 0xe5, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0x00, 0xea, 0x00, 0x00, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp775",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp775(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp775();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp850.c linux/fs/nls_cp850.c
--- v2.0.33/linux/fs/nls_cp850.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp850.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,344 @@
+/*
+ * linux/fs/nls_cp850.c
+ *
+ * Charset cp850 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+	{0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+	{0xee, 0x00}, {0xec, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+	{0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+	{0xff, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+	{0xa3, 0x00}, {0xd8, 0x00}, {0xd7, 0x00}, {0x92, 0x01},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+	{0xbf, 0x00}, {0xae, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc0, 0x00},
+	{0xa9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0xa2, 0x00}, {0xa5, 0x00}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0xe3, 0x00}, {0xc3, 0x00},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+	/* 0xd0*/
+	{0xf0, 0x00}, {0xd0, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+	{0xc8, 0x00}, {0x31, 0x01}, {0xcd, 0x00}, {0xce, 0x00},
+	{0xcf, 0x00}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0xa6, 0x00}, {0xcc, 0x00}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xd3, 0x00}, {0xdf, 0x00}, {0xd4, 0x00}, {0xd2, 0x00},
+	{0xf5, 0x00}, {0xd5, 0x00}, {0xb5, 0x00}, {0xfe, 0x00},
+	{0xde, 0x00}, {0xda, 0x00}, {0xdb, 0x00}, {0xd9, 0x00},
+	{0xfd, 0x00}, {0xdd, 0x00}, {0xaf, 0x00}, {0xb4, 0x00},
+	/* 0xf0*/
+	{0xad, 0x00}, {0xb1, 0x00}, {0x17, 0x20}, {0xbe, 0x00},
+	{0xb6, 0x00}, {0xa7, 0x00}, {0xf7, 0x00}, {0xb8, 0x00},
+	{0xb0, 0x00}, {0xa8, 0x00}, {0xb7, 0x00}, {0xb9, 0x00},
+	{0xb3, 0x00}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* 0xa0-0xa7 */
+	0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */
+	0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* 0xb8-0xbf */
+	0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+	0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* 0xc8-0xcf */
+	0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* 0xd0-0xd7 */
+	0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* 0xd8-0xdf */
+	0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+	0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+	0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */
+	0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+	0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+	0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+	0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   NULL,   NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0x00, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0x00, 0xe2, 0xe3, 0x00, 0xe5, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0x00, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp850",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp850(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp850();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp852.c linux/fs/nls_cp852.c
--- v2.0.33/linux/fs/nls_cp852.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp852.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,344 @@
+/*
+ * linux/fs/nls_cp852.c
+ *
+ * Charset cp852 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xe4, 0x00}, {0x6f, 0x01}, {0x07, 0x01}, {0xe7, 0x00},
+	{0x42, 0x01}, {0xeb, 0x00}, {0x50, 0x01}, {0x51, 0x01},
+	{0xee, 0x00}, {0x79, 0x01}, {0xc4, 0x00}, {0x06, 0x01},
+	/* 0x90*/
+	{0xc9, 0x00}, {0x39, 0x01}, {0x3a, 0x01}, {0xf4, 0x00},
+	{0xf6, 0x00}, {0x3d, 0x01}, {0x3e, 0x01}, {0x5a, 0x01},
+	{0x5b, 0x01}, {0xd6, 0x00}, {0xdc, 0x00}, {0x64, 0x01},
+	{0x65, 0x01}, {0x41, 0x01}, {0xd7, 0x00}, {0x0d, 0x01},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0x04, 0x01}, {0x05, 0x01}, {0x7d, 0x01}, {0x7e, 0x01},
+	{0x18, 0x01}, {0x19, 0x01}, {0xac, 0x00}, {0x7a, 0x01},
+	{0x0c, 0x01}, {0x5f, 0x01}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0xc1, 0x00}, {0xc2, 0x00}, {0x1a, 0x01},
+	{0x5e, 0x01}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x7b, 0x01}, {0x7c, 0x01}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x02, 0x01}, {0x03, 0x01},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+	/* 0xd0*/
+	{0x11, 0x01}, {0x10, 0x01}, {0x0e, 0x01}, {0xcb, 0x00},
+	{0x0f, 0x01}, {0x47, 0x01}, {0xcd, 0x00}, {0xce, 0x00},
+	{0x1b, 0x01}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x62, 0x01}, {0x6e, 0x01}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xd3, 0x00}, {0xdf, 0x00}, {0xd4, 0x00}, {0x43, 0x01},
+	{0x44, 0x01}, {0x48, 0x01}, {0x60, 0x01}, {0x61, 0x01},
+	{0x54, 0x01}, {0xda, 0x00}, {0x55, 0x01}, {0x70, 0x01},
+	{0xfd, 0x00}, {0xdd, 0x00}, {0x63, 0x01}, {0xb4, 0x00},
+	/* 0xf0*/
+	{0xad, 0x00}, {0xdd, 0x02}, {0xdb, 0x02}, {0xc7, 0x02},
+	{0xd8, 0x02}, {0xa7, 0x00}, {0xf7, 0x00}, {0xb8, 0x00},
+	{0xb0, 0x00}, {0xa8, 0x00}, {0xd9, 0x02}, {0x71, 0x01},
+	{0x58, 0x01}, {0x59, 0x01}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0xf5, /* 0xa0-0xa7 */
+	0xf9, 0x00, 0x00, 0xae, 0xaa, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0xf7, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0xb5, 0xb6, 0x00, 0x8e, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */
+	0x00, 0x90, 0x00, 0xd3, 0x00, 0xd6, 0xd7, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0xe0, 0xe2, 0x00, 0x99, 0x9e, /* 0xd0-0xd7 */
+	0x00, 0x00, 0xe9, 0x00, 0x9a, 0xed, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x00, 0xa0, 0x83, 0x00, 0x84, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */
+	0x00, 0x82, 0x00, 0x89, 0x00, 0xa1, 0x8c, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+	0x00, 0x00, 0xa3, 0x00, 0x81, 0xec, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0xc6, 0xc7, 0xa4, 0xa5, 0x8f, 0x86, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xac, 0x9f, 0xd2, 0xd4, /* 0x08-0x0f */
+	0xd1, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xa8, 0xa9, 0xb7, 0xd8, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x91, 0x92, 0x00, 0x00, 0x95, 0x96, 0x00, /* 0x38-0x3f */
+	0x00, 0x9d, 0x88, 0xe3, 0xe4, 0x00, 0x00, 0xd5, /* 0x40-0x47 */
+	0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x8a, 0x8b, 0x00, 0x00, 0xe8, 0xea, 0x00, 0x00, /* 0x50-0x57 */
+	0xfc, 0xfd, 0x97, 0x98, 0x00, 0x00, 0xb8, 0xad, /* 0x58-0x5f */
+	0xe6, 0xe7, 0xdd, 0xee, 0x9b, 0x9c, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x85, /* 0x68-0x6f */
+	0xeb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x8d, 0xab, 0xbd, 0xbe, 0xa6, 0xa7, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0xf4, 0xfa, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+	0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+	0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+	0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, page02, NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x8a, 0x00, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x00, 0x00, 0x00, 0x95, 0x00, 0x97, /* 0x90-0x97 */
+	0x00, 0x99, 0x9a, 0x9b, 0x00, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0x00, /* 0xa0-0xa7 */
+	0xa8, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0x00, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0x00, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0x00, 0xd1, 0xd2, 0xd3, 0x00, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0x00, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0x00, 0xe2, 0xe3, 0x00, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0x00, 0xfc, 0x00, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp852",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp852(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp852();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp855.c linux/fs/nls_cp855.c
--- v2.0.33/linux/fs/nls_cp855.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp855.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,344 @@
+/*
+ * linux/fs/nls_cp855.c
+ *
+ * Charset cp855 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x52, 0x04}, {0x02, 0x04}, {0x53, 0x04}, {0x03, 0x04},
+	{0x51, 0x04}, {0x01, 0x04}, {0x54, 0x04}, {0x04, 0x04},
+	{0x55, 0x04}, {0x05, 0x04}, {0x56, 0x04}, {0x06, 0x04},
+	{0x57, 0x04}, {0x07, 0x04}, {0x58, 0x04}, {0x08, 0x04},
+	/* 0x90*/
+	{0x59, 0x04}, {0x09, 0x04}, {0x5a, 0x04}, {0x0a, 0x04},
+	{0x5b, 0x04}, {0x0b, 0x04}, {0x5c, 0x04}, {0x0c, 0x04},
+	{0x5e, 0x04}, {0x0e, 0x04}, {0x5f, 0x04}, {0x0f, 0x04},
+	{0x4e, 0x04}, {0x2e, 0x04}, {0x4a, 0x04}, {0x2a, 0x04},
+	/* 0xa0*/
+	{0x30, 0x04}, {0x10, 0x04}, {0x31, 0x04}, {0x11, 0x04},
+	{0x46, 0x04}, {0x26, 0x04}, {0x34, 0x04}, {0x14, 0x04},
+	{0x35, 0x04}, {0x15, 0x04}, {0x44, 0x04}, {0x24, 0x04},
+	{0x33, 0x04}, {0x13, 0x04}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x45, 0x04}, {0x25, 0x04}, {0x38, 0x04},
+	{0x18, 0x04}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x39, 0x04}, {0x19, 0x04}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x3a, 0x04}, {0x1a, 0x04},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+	/* 0xd0*/
+	{0x3b, 0x04}, {0x1b, 0x04}, {0x3c, 0x04}, {0x1c, 0x04},
+	{0x3d, 0x04}, {0x1d, 0x04}, {0x3e, 0x04}, {0x1e, 0x04},
+	{0x3f, 0x04}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x1f, 0x04}, {0x4f, 0x04}, {0x80, 0x25},
+	/* 0xe0*/
+	{0x2f, 0x04}, {0x40, 0x04}, {0x20, 0x04}, {0x41, 0x04},
+	{0x21, 0x04}, {0x42, 0x04}, {0x22, 0x04}, {0x43, 0x04},
+	{0x23, 0x04}, {0x36, 0x04}, {0x16, 0x04}, {0x32, 0x04},
+	{0x12, 0x04}, {0x4c, 0x04}, {0x2c, 0x04}, {0x16, 0x21},
+	/* 0xf0*/
+	{0xad, 0x00}, {0x4b, 0x04}, {0x2b, 0x04}, {0x37, 0x04},
+	{0x17, 0x04}, {0x48, 0x04}, {0x28, 0x04}, {0x4d, 0x04},
+	{0x2d, 0x04}, {0x49, 0x04}, {0x29, 0x04}, {0x47, 0x04},
+	{0x27, 0x04}, {0xa7, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0xfd, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0xae, 0x00, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+	0x00, 0x85, 0x81, 0x83, 0x87, 0x89, 0x8b, 0x8d, /* 0x00-0x07 */
+	0x8f, 0x91, 0x93, 0x95, 0x97, 0x00, 0x99, 0x9b, /* 0x08-0x0f */
+	0xa1, 0xa3, 0xec, 0xad, 0xa7, 0xa9, 0xea, 0xf4, /* 0x10-0x17 */
+	0xb8, 0xbe, 0xc7, 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, /* 0x18-0x1f */
+	0xe2, 0xe4, 0xe6, 0xe8, 0xab, 0xb6, 0xa5, 0xfc, /* 0x20-0x27 */
+	0xf6, 0xfa, 0x9f, 0xf2, 0xee, 0xf8, 0x9d, 0xe0, /* 0x28-0x2f */
+	0xa0, 0xa2, 0xeb, 0xac, 0xa6, 0xa8, 0xe9, 0xf3, /* 0x30-0x37 */
+	0xb7, 0xbd, 0xc6, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, /* 0x38-0x3f */
+	0xe1, 0xe3, 0xe5, 0xe7, 0xaa, 0xb5, 0xa4, 0xfb, /* 0x40-0x47 */
+	0xf5, 0xf9, 0x9e, 0xf1, 0xed, 0xf7, 0x9c, 0xde, /* 0x48-0x4f */
+	0x00, 0x84, 0x80, 0x82, 0x86, 0x88, 0x8a, 0x8c, /* 0x50-0x57 */
+	0x8e, 0x90, 0x92, 0x94, 0x96, 0x00, 0x98, 0x9a, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page21[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+	0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+	0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+	0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   page04, NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   page21, NULL,   NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x00, 0x81, 0x00, 0x83, 0x00, 0x85, 0x00, 0x87, /* 0x80-0x87 */
+	0x00, 0x89, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x8f, /* 0x88-0x8f */
+	0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, /* 0x90-0x97 */
+	0x00, 0x99, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9f, /* 0x98-0x9f */
+	0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
+	0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0x00, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0x00, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0x00, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd7, /* 0xd0-0xd7 */
+	0x00, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0x00, 0xea, 0x00, 0xec, 0x00, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0x00, 0xf2, 0x00, 0xf4, 0x00, 0xf6, 0x00, /* 0xf0-0xf7 */
+	0xf8, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp855",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp855(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp855();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp857.c linux/fs/nls_cp857.c
--- v2.0.33/linux/fs/nls_cp857.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp857.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,308 @@
+/*
+ * linux/fs/nls_cp857.c
+ *
+ * Charset cp857 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+	{0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+	{0xee, 0x00}, {0x31, 0x01}, {0xc4, 0x00}, {0xc5, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+	{0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+	{0x30, 0x01}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+	{0xa3, 0x00}, {0xd8, 0x00}, {0x5e, 0x01}, {0x5f, 0x01},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xf1, 0x00}, {0xd1, 0x00}, {0x1e, 0x01}, {0x1f, 0x01},
+	{0xbf, 0x00}, {0xae, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc0, 0x00},
+	{0xa9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0xa2, 0x00}, {0xa5, 0x00}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0xe3, 0x00}, {0xc3, 0x00},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+	/* 0xd0*/
+	{0xba, 0x00}, {0xaa, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+	{0xc8, 0x00}, {0x00, 0x00}, {0xcd, 0x00}, {0xce, 0x00},
+	{0xcf, 0x00}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0xa6, 0x00}, {0xcc, 0x00}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xd3, 0x00}, {0xdf, 0x00}, {0xd4, 0x00}, {0xd2, 0x00},
+	{0xf5, 0x00}, {0xd5, 0x00}, {0xb5, 0x00}, {0x00, 0x00},
+	{0xd7, 0x00}, {0xda, 0x00}, {0xdb, 0x00}, {0xd9, 0x00},
+	{0xec, 0x00}, {0xff, 0x00}, {0xaf, 0x00}, {0xb4, 0x00},
+	/* 0xf0*/
+	{0xad, 0x00}, {0xb1, 0x00}, {0x00, 0x00}, {0xbe, 0x00},
+	{0xb6, 0x00}, {0xa7, 0x00}, {0xf7, 0x00}, {0xb8, 0x00},
+	{0xb0, 0x00}, {0xa8, 0x00}, {0xb7, 0x00}, {0xb9, 0x00},
+	{0xb3, 0x00}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* 0xa0-0xa7 */
+	0xf9, 0xb8, 0xd1, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */
+	0xf7, 0xfb, 0xd0, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* 0xb8-0xbf */
+	0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+	0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* 0xc8-0xcf */
+	0x00, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xe8, /* 0xd0-0xd7 */
+	0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+	0x8a, 0x82, 0x88, 0x89, 0xec, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+	0x00, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */
+	0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0xed, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xa7, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x98, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x9f, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+	0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+	0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+	0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0x00, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0x00, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0x00, 0xe2, 0xe3, 0x00, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0x00, 0x00, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp857",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp857(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp857();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp860.c linux/fs/nls_cp860.c
--- v2.0.33/linux/fs/nls_cp860.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp860.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,416 @@
+/*
+ * linux/fs/nls_cp860.c
+ *
+ * Charset cp860 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xe3, 0x00}, {0xe0, 0x00}, {0xc1, 0x00}, {0xe7, 0x00},
+	{0xea, 0x00}, {0xca, 0x00}, {0xe8, 0x00}, {0xcd, 0x00},
+	{0xd4, 0x00}, {0xec, 0x00}, {0xc3, 0x00}, {0xc2, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xc0, 0x00}, {0xc8, 0x00}, {0xf4, 0x00},
+	{0xf5, 0x00}, {0xf2, 0x00}, {0xda, 0x00}, {0xf9, 0x00},
+	{0xcc, 0x00}, {0xd5, 0x00}, {0xdc, 0x00}, {0xa2, 0x00},
+	{0xa3, 0x00}, {0xd9, 0x00}, {0xa7, 0x20}, {0xd3, 0x00},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+	{0xbf, 0x00}, {0xd2, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+	{0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+	{0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+	{0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+	/* 0xf0*/
+	{0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+	{0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0xad, 0x9b, 0x9c, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+	0x91, 0x86, 0x8f, 0x8e, 0x00, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */
+	0x92, 0x90, 0x89, 0x00, 0x98, 0x8b, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0xa5, 0xa9, 0x9f, 0x8c, 0x99, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x9d, 0x96, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x85, 0xa0, 0x83, 0x84, 0x00, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */
+	0x8a, 0x82, 0x88, 0x00, 0x8d, 0xa1, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0xa4, 0x95, 0xa2, 0x93, 0x94, 0x00, 0xf6, /* 0xf0-0xf7 */
+	0x00, 0x97, 0xa3, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, /* 0x80-0x87 */
+	0x00, 0x89, 0x00, 0x8b, 0x8c, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x96, 0x00, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp860",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp860(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp860();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp861.c linux/fs/nls_cp861.c
--- v2.0.33/linux/fs/nls_cp861.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp861.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,452 @@
+/*
+ * linux/fs/nls_cp861.c
+ *
+ * Charset cp861 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+	{0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xd0, 0x00},
+	{0xf0, 0x00}, {0xde, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+	{0xf6, 0x00}, {0xfe, 0x00}, {0xfb, 0x00}, {0xdd, 0x00},
+	{0xfd, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+	{0xa3, 0x00}, {0xd8, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xc1, 0x00}, {0xcd, 0x00}, {0xd3, 0x00}, {0xda, 0x00},
+	{0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+	{0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+	{0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+	{0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+	/* 0xf0*/
+	{0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+	{0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0xad, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+	0x00, 0xa4, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+	0x00, 0x90, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, /* 0xc8-0xcf */
+	0x8b, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
+	0x9d, 0x00, 0xa7, 0x00, 0x9a, 0x97, 0x8d, 0xe1, /* 0xd8-0xdf */
+	0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+	0x8a, 0x82, 0x88, 0x89, 0x00, 0xa1, 0x00, 0x00, /* 0xe8-0xef */
+	0x8c, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+	0x9b, 0x00, 0xa3, 0x96, 0x81, 0x98, 0x95, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x8b, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x97, /* 0x90-0x97 */
+	0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp861",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp861(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp861();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp862.c linux/fs/nls_cp862.c
--- v2.0.33/linux/fs/nls_cp862.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp862.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,488 @@
+/*
+ * linux/fs/nls_cp862.c
+ *
+ * Charset cp862 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xd0, 0x05}, {0xd1, 0x05}, {0xd2, 0x05}, {0xd3, 0x05},
+	{0xd4, 0x05}, {0xd5, 0x05}, {0xd6, 0x05}, {0xd7, 0x05},
+	{0xd8, 0x05}, {0xd9, 0x05}, {0xda, 0x05}, {0xdb, 0x05},
+	{0xdc, 0x05}, {0xdd, 0x05}, {0xde, 0x05}, {0xdf, 0x05},
+	/* 0x90*/
+	{0xe0, 0x05}, {0xe1, 0x05}, {0xe2, 0x05}, {0xe3, 0x05},
+	{0xe4, 0x05}, {0xe5, 0x05}, {0xe6, 0x05}, {0xe7, 0x05},
+	{0xe8, 0x05}, {0xe9, 0x05}, {0xea, 0x05}, {0xa2, 0x00},
+	{0xa3, 0x00}, {0xa5, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+	{0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+	{0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+	{0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+	{0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+	/* 0xf0*/
+	{0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+	{0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0xa4, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */
+	0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page05[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0xd0-0xd7 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0xd8-0xdf */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0xe0-0xe7 */
+	0x98, 0x99, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   page03, NULL,   page05, NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp862",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp862(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp862();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp863.c linux/fs/nls_cp863.c
--- v2.0.33/linux/fs/nls_cp863.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp863.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,452 @@
+/*
+ * linux/fs/nls_cp863.c
+ *
+ * Charset cp863 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xc2, 0x00}, {0xe0, 0x00}, {0xb6, 0x00}, {0xe7, 0x00},
+	{0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+	{0xee, 0x00}, {0x17, 0x20}, {0xc0, 0x00}, {0xa7, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xc8, 0x00}, {0xca, 0x00}, {0xf4, 0x00},
+	{0xcb, 0x00}, {0xcf, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+	{0xa4, 0x00}, {0xd4, 0x00}, {0xdc, 0x00}, {0xa2, 0x00},
+	{0xa3, 0x00}, {0xd9, 0x00}, {0xdb, 0x00}, {0x92, 0x01},
+	/* 0xa0*/
+	{0xa6, 0x00}, {0xb4, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xa8, 0x00}, {0xb8, 0x00}, {0xb3, 0x00}, {0xaf, 0x00},
+	{0xce, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xbe, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+	{0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+	{0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+	{0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+	/* 0xf0*/
+	{0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+	{0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0x00, 0x9b, 0x9c, 0x98, 0x00, 0xa0, 0x8f, /* 0xa0-0xa7 */
+	0xa4, 0x00, 0x00, 0xae, 0xaa, 0x00, 0x00, 0xa7, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0xa6, 0xa1, 0xe6, 0x86, 0xfa, /* 0xb0-0xb7 */
+	0xa5, 0x00, 0x00, 0xaf, 0xac, 0xab, 0xad, 0x00, /* 0xb8-0xbf */
+	0x8e, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */
+	0x91, 0x90, 0x92, 0x94, 0x00, 0x00, 0xa8, 0x95, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x9d, 0x00, 0x9e, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x85, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */
+	0x8a, 0x82, 0x88, 0x89, 0x00, 0x00, 0x8c, 0x8b, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */
+	0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x84, 0x00, 0x86, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x94, 0x95, 0x00, 0x00, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0xa0, 0xa1, 0x00, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp863",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp863(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp863();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp864.c linux/fs/nls_cp864.c
--- v2.0.33/linux/fs/nls_cp864.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp864.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,443 @@
+/*
+ * linux/fs/nls_cp864.c
+ *
+ * Charset cp864 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x6a, 0x06}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xb0, 0x00}, {0xb7, 0x00}, {0x19, 0x22}, {0x1a, 0x22},
+	{0x92, 0x25}, {0x00, 0x25}, {0x02, 0x25}, {0x3c, 0x25},
+	{0x24, 0x25}, {0x2c, 0x25}, {0x1c, 0x25}, {0x34, 0x25},
+	{0x10, 0x25}, {0x0c, 0x25}, {0x14, 0x25}, {0x18, 0x25},
+	/* 0x90*/
+	{0xb2, 0x03}, {0x1e, 0x22}, {0xc6, 0x03}, {0xb1, 0x00},
+	{0xbd, 0x00}, {0xbc, 0x00}, {0x48, 0x22}, {0xab, 0x00},
+	{0xbb, 0x00}, {0xf7, 0xfe}, {0xf8, 0xfe}, {0x00, 0x00},
+	{0x00, 0x00}, {0xfb, 0xfe}, {0xfc, 0xfe}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0xad, 0x00}, {0x82, 0xfe}, {0xa3, 0x00},
+	{0xa4, 0x00}, {0x84, 0xfe}, {0x00, 0x00}, {0x00, 0x00},
+	{0x8e, 0xfe}, {0x8f, 0xfe}, {0x95, 0xfe}, {0x99, 0xfe},
+	{0x0c, 0x06}, {0x9d, 0xfe}, {0xa1, 0xfe}, {0xa5, 0xfe},
+	/* 0xb0*/
+	{0x60, 0x06}, {0x61, 0x06}, {0x62, 0x06}, {0x63, 0x06},
+	{0x64, 0x06}, {0x65, 0x06}, {0x66, 0x06}, {0x67, 0x06},
+	{0x68, 0x06}, {0x69, 0x06}, {0xd1, 0xfe}, {0x1b, 0x06},
+	{0xb1, 0xfe}, {0xb5, 0xfe}, {0xb9, 0xfe}, {0x1f, 0x06},
+	/* 0xc0*/
+	{0xa2, 0x00}, {0x80, 0xfe}, {0x81, 0xfe}, {0x83, 0xfe},
+	{0x85, 0xfe}, {0xca, 0xfe}, {0x8b, 0xfe}, {0x8d, 0xfe},
+	{0x91, 0xfe}, {0x93, 0xfe}, {0x97, 0xfe}, {0x9b, 0xfe},
+	{0x9f, 0xfe}, {0xa3, 0xfe}, {0xa7, 0xfe}, {0xa9, 0xfe},
+	/* 0xd0*/
+	{0xab, 0xfe}, {0xad, 0xfe}, {0xaf, 0xfe}, {0xb3, 0xfe},
+	{0xb7, 0xfe}, {0xbb, 0xfe}, {0xbf, 0xfe}, {0xc1, 0xfe},
+	{0xc5, 0xfe}, {0xcb, 0xfe}, {0xcf, 0xfe}, {0xa6, 0x00},
+	{0xac, 0x00}, {0xf7, 0x00}, {0xd7, 0x00}, {0xc9, 0xfe},
+	/* 0xe0*/
+	{0x40, 0x06}, {0xd3, 0xfe}, {0xd7, 0xfe}, {0xdb, 0xfe},
+	{0xdf, 0xfe}, {0xe3, 0xfe}, {0xe7, 0xfe}, {0xeb, 0xfe},
+	{0xed, 0xfe}, {0xef, 0xfe}, {0xf3, 0xfe}, {0xbd, 0xfe},
+	{0xcc, 0xfe}, {0xce, 0xfe}, {0xcd, 0xfe}, {0xe1, 0xfe},
+	/* 0xf0*/
+	{0x7d, 0xfe}, {0x51, 0x06}, {0xe5, 0xfe}, {0xe9, 0xfe},
+	{0xec, 0xfe}, {0xf0, 0xfe}, {0xf2, 0xfe}, {0xd0, 0xfe},
+	{0xd5, 0xfe}, {0xf5, 0xfe}, {0xf6, 0xfe}, {0xdd, 0xfe},
+	{0xd9, 0xfe}, {0xf1, 0xfe}, {0xa0, 0x25}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x00, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0xc0, 0xa3, 0xa4, 0x00, 0xdb, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x97, 0xdc, 0xa1, 0x00, 0x00, /* 0xa8-0xaf */
+	0x80, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x98, 0x95, 0x94, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page06[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x60-0x67 */
+	0xb8, 0xb9, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x82, 0x83, 0x00, 0x00, 0x00, 0x91, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0x85, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x8c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x8f, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char pagefe[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xc1, 0xc2, 0xa2, 0xc3, 0xa5, 0xc4, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0xc6, 0x00, 0xc7, 0xa8, 0xa9, /* 0x88-0x8f */
+	0x00, 0xc8, 0x00, 0xc9, 0x00, 0xaa, 0x00, 0xca, /* 0x90-0x97 */
+	0x00, 0xab, 0x00, 0xcb, 0x00, 0xad, 0x00, 0xcc, /* 0x98-0x9f */
+	0x00, 0xae, 0x00, 0xcd, 0x00, 0xaf, 0x00, 0xce, /* 0xa0-0xa7 */
+	0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, /* 0xa8-0xaf */
+	0x00, 0xbc, 0x00, 0xd3, 0x00, 0xbd, 0x00, 0xd4, /* 0xb0-0xb7 */
+	0x00, 0xbe, 0x00, 0xd5, 0x00, 0xeb, 0x00, 0xd6, /* 0xb8-0xbf */
+	0x00, 0xd7, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0xdf, 0xc5, 0xd9, 0xec, 0xee, 0xed, 0xda, /* 0xc8-0xcf */
+	0xf7, 0xba, 0x00, 0xe1, 0x00, 0xf8, 0x00, 0xe2, /* 0xd0-0xd7 */
+	0x00, 0xfc, 0x00, 0xe3, 0x00, 0xfb, 0x00, 0xe4, /* 0xd8-0xdf */
+	0x00, 0xef, 0x00, 0xe5, 0x00, 0xf2, 0x00, 0xe6, /* 0xe0-0xe7 */
+	0x00, 0xf3, 0x00, 0xe7, 0xf4, 0xe8, 0x00, 0xe9, /* 0xe8-0xef */
+	0xf5, 0xfd, 0xf6, 0xea, 0x00, 0xf9, 0xfa, 0x99, /* 0xf0-0xf7 */
+	0x9a, 0x00, 0x00, 0x9d, 0x9e, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   page03, NULL,   NULL,   page06, NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   page22, NULL,   NULL,   page25, NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   pagefe, NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp864",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp864(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp864();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp865.c linux/fs/nls_cp865.c
--- v2.0.33/linux/fs/nls_cp865.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp865.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,452 @@
+/*
+ * linux/fs/nls_cp865.c
+ *
+ * Charset cp865 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+	{0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+	{0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+	{0xee, 0x00}, {0xec, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+	/* 0x90*/
+	{0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+	{0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+	{0xff, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+	{0xa3, 0x00}, {0xd8, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+	/* 0xa0*/
+	{0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+	{0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+	{0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+	{0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xa4, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+	{0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+	{0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+	{0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+	/* 0xf0*/
+	{0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+	{0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0xad, 0x00, 0x9c, 0xaf, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0x00, 0xa7, 0x00, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+	0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
+	0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+	0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+	0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+	0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+	0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp865",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp865(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp865();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp866.c linux/fs/nls_cp866.c
--- v2.0.33/linux/fs/nls_cp866.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp866.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,380 @@
+/*
+ * linux/fs/nls_cp866.c
+ *
+ * Charset cp866 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x10, 0x04}, {0x11, 0x04}, {0x12, 0x04}, {0x13, 0x04},
+	{0x14, 0x04}, {0x15, 0x04}, {0x16, 0x04}, {0x17, 0x04},
+	{0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04}, {0x1b, 0x04},
+	{0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04}, {0x1f, 0x04},
+	/* 0x90*/
+	{0x20, 0x04}, {0x21, 0x04}, {0x22, 0x04}, {0x23, 0x04},
+	{0x24, 0x04}, {0x25, 0x04}, {0x26, 0x04}, {0x27, 0x04},
+	{0x28, 0x04}, {0x29, 0x04}, {0x2a, 0x04}, {0x2b, 0x04},
+	{0x2c, 0x04}, {0x2d, 0x04}, {0x2e, 0x04}, {0x2f, 0x04},
+	/* 0xa0*/
+	{0x30, 0x04}, {0x31, 0x04}, {0x32, 0x04}, {0x33, 0x04},
+	{0x34, 0x04}, {0x35, 0x04}, {0x36, 0x04}, {0x37, 0x04},
+	{0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04}, {0x3b, 0x04},
+	{0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04}, {0x3f, 0x04},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+	{0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+	/* 0xd0*/
+	{0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+	{0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+	{0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+	/* 0xe0*/
+	{0x40, 0x04}, {0x41, 0x04}, {0x42, 0x04}, {0x43, 0x04},
+	{0x44, 0x04}, {0x45, 0x04}, {0x46, 0x04}, {0x47, 0x04},
+	{0x48, 0x04}, {0x49, 0x04}, {0x4a, 0x04}, {0x4b, 0x04},
+	{0x4c, 0x04}, {0x4d, 0x04}, {0x4e, 0x04}, {0x4f, 0x04},
+	/* 0xf0*/
+	{0x01, 0x04}, {0x51, 0x04}, {0x04, 0x04}, {0x54, 0x04},
+	{0x07, 0x04}, {0x57, 0x04}, {0x0e, 0x04}, {0x5e, 0x04},
+	{0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+	{0x16, 0x21}, {0xa4, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+	0x00, 0xf0, 0x00, 0x00, 0xf2, 0x00, 0x00, 0xf4, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x00, /* 0x08-0x0f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x10-0x17 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x18-0x1f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x20-0x27 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x28-0x2f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x30-0x37 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x38-0x3f */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+	0x00, 0xf1, 0x00, 0x00, 0xf3, 0x00, 0x00, 0xf5, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page21[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+	0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+	0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+	0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   page04, NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   page21, page22, NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0xf0, 0x00, 0xf2, 0x00, 0xf4, 0x00, 0xf6, 0x00, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp866",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp866(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp866();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp869.c linux/fs/nls_cp869.c
--- v2.0.33/linux/fs/nls_cp869.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp869.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,344 @@
+/*
+ * linux/fs/nls_cp869.c
+ *
+ * Charset cp869 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x86, 0x03}, {0x00, 0x00},
+	{0xb7, 0x00}, {0xac, 0x00}, {0xa6, 0x00}, {0x18, 0x20},
+	{0x19, 0x20}, {0x88, 0x03}, {0x15, 0x20}, {0x89, 0x03},
+	/* 0x90*/
+	{0x8a, 0x03}, {0xaa, 0x03}, {0x8c, 0x03}, {0x00, 0x00},
+	{0x00, 0x00}, {0x8e, 0x03}, {0xab, 0x03}, {0xa9, 0x00},
+	{0x8f, 0x03}, {0xb2, 0x00}, {0xb3, 0x00}, {0xac, 0x03},
+	{0xa3, 0x00}, {0xad, 0x03}, {0xae, 0x03}, {0xaf, 0x03},
+	/* 0xa0*/
+	{0xca, 0x03}, {0x90, 0x03}, {0xcc, 0x03}, {0xcd, 0x03},
+	{0x91, 0x03}, {0x92, 0x03}, {0x93, 0x03}, {0x94, 0x03},
+	{0x95, 0x03}, {0x96, 0x03}, {0x97, 0x03}, {0xbd, 0x00},
+	{0x98, 0x03}, {0x99, 0x03}, {0xab, 0x00}, {0xbb, 0x00},
+	/* 0xb0*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+	{0x24, 0x25}, {0x9a, 0x03}, {0x9b, 0x03}, {0x9c, 0x03},
+	{0x9d, 0x03}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+	{0x5d, 0x25}, {0x9e, 0x03}, {0x9f, 0x03}, {0x10, 0x25},
+	/* 0xc0*/
+	{0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+	{0x00, 0x25}, {0x3c, 0x25}, {0xa0, 0x03}, {0xa1, 0x03},
+	{0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+	{0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa3, 0x03},
+	/* 0xd0*/
+	{0xa4, 0x03}, {0xa5, 0x03}, {0xa6, 0x03}, {0xa7, 0x03},
+	{0xa8, 0x03}, {0xa9, 0x03}, {0xb1, 0x03}, {0xb2, 0x03},
+	{0xb3, 0x03}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+	{0x84, 0x25}, {0xb4, 0x03}, {0xb5, 0x03}, {0x80, 0x25},
+	/* 0xe0*/
+	{0xb6, 0x03}, {0xb7, 0x03}, {0xb8, 0x03}, {0xb9, 0x03},
+	{0xba, 0x03}, {0xbb, 0x03}, {0xbc, 0x03}, {0xbd, 0x03},
+	{0xbe, 0x03}, {0xbf, 0x03}, {0xc0, 0x03}, {0xc1, 0x03},
+	{0xc3, 0x03}, {0xc2, 0x03}, {0xc4, 0x03}, {0x84, 0x03},
+	/* 0xf0*/
+	{0xad, 0x00}, {0xb1, 0x00}, {0xc5, 0x03}, {0xc6, 0x03},
+	{0xc7, 0x03}, {0xa7, 0x00}, {0xc8, 0x03}, {0x85, 0x03},
+	{0xb0, 0x00}, {0xa8, 0x00}, {0xc9, 0x03}, {0xcb, 0x03},
+	{0xb0, 0x03}, {0xce, 0x03}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xff, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x8a, 0xf5, /* 0xa0-0xa7 */
+	0xf9, 0x97, 0x00, 0xae, 0x89, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */
+	0xf8, 0xf1, 0x99, 0x9a, 0x00, 0x00, 0x00, 0x88, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0xaf, 0x00, 0xab, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0xef, 0xf7, 0x86, 0x00, /* 0x80-0x87 */
+	0x8d, 0x8f, 0x90, 0x00, 0x92, 0x00, 0x95, 0x98, /* 0x88-0x8f */
+	0xa1, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, /* 0x90-0x97 */
+	0xac, 0xad, 0xb5, 0xb6, 0xb7, 0xb8, 0xbd, 0xbe, /* 0x98-0x9f */
+	0xc6, 0xc7, 0x00, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, /* 0xa0-0xa7 */
+	0xd4, 0xd5, 0x91, 0x96, 0x9b, 0x9d, 0x9e, 0x9f, /* 0xa8-0xaf */
+	0xfc, 0xd6, 0xd7, 0xd8, 0xdd, 0xde, 0xe0, 0xe1, /* 0xb0-0xb7 */
+	0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, /* 0xb8-0xbf */
+	0xea, 0xeb, 0xed, 0xec, 0xee, 0xf2, 0xf3, 0xf4, /* 0xc0-0xc7 */
+	0xf6, 0xfa, 0xa0, 0xfb, 0xa2, 0xa3, 0xfd, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, /* 0x10-0x17 */
+	0x8b, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+	0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+	0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+	0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   NULL,   NULL,   NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x00, 0x9c, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0x00, 0x00, 0x00, 0xf5, 0x00, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp869",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp869(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp869();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_cp874.c linux/fs/nls_cp874.c
--- v2.0.33/linux/fs/nls_cp874.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_cp874.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,308 @@
+/*
+ * linux/fs/nls_cp874.c
+ *
+ * Charset cp874 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#ifndef _NLS_CP
+#define _NLS_CP
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x26, 0x20}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x18, 0x20}, {0x19, 0x20}, {0x1c, 0x20},
+	{0x1d, 0x20}, {0x22, 0x20}, {0x13, 0x20}, {0x14, 0x20},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0x01, 0x0e}, {0x02, 0x0e}, {0x03, 0x0e},
+	{0x04, 0x0e}, {0x05, 0x0e}, {0x06, 0x0e}, {0x07, 0x0e},
+	{0x08, 0x0e}, {0x09, 0x0e}, {0x0a, 0x0e}, {0x0b, 0x0e},
+	{0x0c, 0x0e}, {0x0d, 0x0e}, {0x0e, 0x0e}, {0x0f, 0x0e},
+	/* 0xb0*/
+	{0x10, 0x0e}, {0x11, 0x0e}, {0x12, 0x0e}, {0x13, 0x0e},
+	{0x14, 0x0e}, {0x15, 0x0e}, {0x16, 0x0e}, {0x17, 0x0e},
+	{0x18, 0x0e}, {0x19, 0x0e}, {0x1a, 0x0e}, {0x1b, 0x0e},
+	{0x1c, 0x0e}, {0x1d, 0x0e}, {0x1e, 0x0e}, {0x1f, 0x0e},
+	/* 0xc0*/
+	{0x20, 0x0e}, {0x21, 0x0e}, {0x22, 0x0e}, {0x23, 0x0e},
+	{0x24, 0x0e}, {0x25, 0x0e}, {0x26, 0x0e}, {0x27, 0x0e},
+	{0x28, 0x0e}, {0x29, 0x0e}, {0x2a, 0x0e}, {0x2b, 0x0e},
+	{0x2c, 0x0e}, {0x2d, 0x0e}, {0x2e, 0x0e}, {0x2f, 0x0e},
+	/* 0xd0*/
+	{0x30, 0x0e}, {0x31, 0x0e}, {0x32, 0x0e}, {0x33, 0x0e},
+	{0x34, 0x0e}, {0x35, 0x0e}, {0x36, 0x0e}, {0x37, 0x0e},
+	{0x38, 0x0e}, {0x39, 0x0e}, {0x3a, 0x0e}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x3f, 0x0e},
+	/* 0xe0*/
+	{0x40, 0x0e}, {0x41, 0x0e}, {0x42, 0x0e}, {0x43, 0x0e},
+	{0x44, 0x0e}, {0x45, 0x0e}, {0x46, 0x0e}, {0x47, 0x0e},
+	{0x48, 0x0e}, {0x49, 0x0e}, {0x4a, 0x0e}, {0x4b, 0x0e},
+	{0x4c, 0x0e}, {0x4d, 0x0e}, {0x4e, 0x0e}, {0x4f, 0x0e},
+	/* 0xf0*/
+	{0x50, 0x0e}, {0x51, 0x0e}, {0x52, 0x0e}, {0x53, 0x0e},
+	{0x54, 0x0e}, {0x55, 0x0e}, {0x56, 0x0e}, {0x57, 0x0e},
+	{0x58, 0x0e}, {0x59, 0x0e}, {0x5a, 0x0e}, {0x5b, 0x0e},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page0e[256] = {
+	0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x08-0x0f */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0x18-0x1f */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */
+	0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0x38-0x3f */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x50-0x57 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x91, 0x92, 0x00, 0x00, 0x93, 0x94, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   page0e, NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"cp874",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_cp874(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_cp874();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
+#endif /* _NLS_CP */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_1.c linux/fs/nls_iso8859_1.c
--- v2.0.33/linux/fs/nls_iso8859_1.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_1.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,227 @@
+/*
+ * linux/fs/nls_iso8859-1.c
+ *
+ * Charset iso8859-1 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+	{0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+	{0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+	{0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+	{0xb8, 0x00}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+	{0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0xbf, 0x00},
+	/* 0xc0*/
+	{0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+	{0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+	{0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+	{0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+	/* 0xd0*/
+	{0xd0, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+	{0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+	{0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+	{0xdc, 0x00}, {0xdd, 0x00}, {0xde, 0x00}, {0xdf, 0x00},
+	/* 0xe0*/
+	{0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+	{0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+	{0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+	{0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+	/* 0xf0*/
+	{0xf0, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+	{0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+	{0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+	{0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-1",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_1(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_1();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_2.c linux/fs/nls_iso8859_2.c
--- v2.0.33/linux/fs/nls_iso8859_2.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_2.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,299 @@
+/*
+ * linux/fs/nls_iso8859-2.c
+ *
+ * Charset iso8859-2 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0x04, 0x01}, {0xd8, 0x02}, {0x41, 0x01},
+	{0xa4, 0x00}, {0x3d, 0x01}, {0x5a, 0x01}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0x60, 0x01}, {0x5e, 0x01}, {0x64, 0x01},
+	{0x79, 0x01}, {0xad, 0x00}, {0x7d, 0x01}, {0x7b, 0x01},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0x05, 0x01}, {0xdb, 0x02}, {0x42, 0x01},
+	{0xb4, 0x00}, {0x3e, 0x01}, {0x5b, 0x01}, {0xc7, 0x02},
+	{0xb8, 0x00}, {0x61, 0x01}, {0x5f, 0x01}, {0x65, 0x01},
+	{0x7a, 0x01}, {0xdd, 0x02}, {0x7e, 0x01}, {0x7c, 0x01},
+	/* 0xc0*/
+	{0x54, 0x01}, {0xc1, 0x00}, {0xc2, 0x00}, {0x02, 0x01},
+	{0xc4, 0x00}, {0x39, 0x01}, {0x06, 0x01}, {0xc7, 0x00},
+	{0x0c, 0x01}, {0xc9, 0x00}, {0x18, 0x01}, {0xcb, 0x00},
+	{0x1a, 0x01}, {0xcd, 0x00}, {0xce, 0x00}, {0x0e, 0x01},
+	/* 0xd0*/
+	{0x10, 0x01}, {0x43, 0x01}, {0x47, 0x01}, {0xd3, 0x00},
+	{0xd4, 0x00}, {0x50, 0x01}, {0xd6, 0x00}, {0xd7, 0x00},
+	{0x58, 0x01}, {0x6e, 0x01}, {0xda, 0x00}, {0x70, 0x01},
+	{0xdc, 0x00}, {0xdd, 0x00}, {0x62, 0x01}, {0xdf, 0x00},
+	/* 0xe0*/
+	{0x55, 0x01}, {0xe1, 0x00}, {0xe2, 0x00}, {0x03, 0x01},
+	{0xe4, 0x00}, {0x3a, 0x01}, {0x07, 0x01}, {0xe7, 0x00},
+	{0x0d, 0x01}, {0xe9, 0x00}, {0x19, 0x01}, {0xeb, 0x00},
+	{0x1b, 0x01}, {0xed, 0x00}, {0xee, 0x00}, {0x0f, 0x01},
+	/* 0xf0*/
+	{0x11, 0x01}, {0x44, 0x01}, {0x48, 0x01}, {0xf3, 0x00},
+	{0xf4, 0x00}, {0x51, 0x01}, {0xf6, 0x00}, {0xf7, 0x00},
+	{0x59, 0x01}, {0x6f, 0x01}, {0xfa, 0x00}, {0x71, 0x01},
+	{0xfc, 0x00}, {0xfd, 0x00}, {0x63, 0x01}, {0xd9, 0x02},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+	0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */
+	0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0x00, 0x00, 0xda, 0x00, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */
+	0x00, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */
+	0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */
+	0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x38-0x3f */
+	0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x40-0x47 */
+	0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x50-0x57 */
+	0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x58-0x5f */
+	0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x68-0x6f */
+	0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, page02, NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-2",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_2(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_2();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_3.c linux/fs/nls_iso8859_3.c
--- v2.0.33/linux/fs/nls_iso8859_3.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_3.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,299 @@
+/*
+ * linux/fs/nls_iso8859-3.c
+ *
+ * Charset iso8859-3 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0x26, 0x01}, {0xd8, 0x02}, {0xa3, 0x00},
+	{0xa4, 0x00}, {0x00, 0x00}, {0x24, 0x01}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0x30, 0x01}, {0x5e, 0x01}, {0x1e, 0x01},
+	{0x34, 0x01}, {0xad, 0x00}, {0x00, 0x00}, {0x7b, 0x01},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0x27, 0x01}, {0xb2, 0x00}, {0xb3, 0x00},
+	{0xb4, 0x00}, {0xb5, 0x00}, {0x25, 0x01}, {0xb7, 0x00},
+	{0xb8, 0x00}, {0x31, 0x01}, {0x5f, 0x01}, {0x1f, 0x01},
+	{0x35, 0x01}, {0xbd, 0x00}, {0x00, 0x00}, {0x7c, 0x01},
+	/* 0xc0*/
+	{0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0x00, 0x00},
+	{0xc4, 0x00}, {0x0a, 0x01}, {0x08, 0x01}, {0xc7, 0x00},
+	{0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+	{0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+	/* 0xd0*/
+	{0x00, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+	{0xd4, 0x00}, {0x20, 0x01}, {0xd6, 0x00}, {0xd7, 0x00},
+	{0x1c, 0x01}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+	{0xdc, 0x00}, {0x6c, 0x01}, {0x5c, 0x01}, {0xdf, 0x00},
+	/* 0xe0*/
+	{0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0x00, 0x00},
+	{0xe4, 0x00}, {0x0b, 0x01}, {0x09, 0x01}, {0xe7, 0x00},
+	{0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+	{0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+	/* 0xf0*/
+	{0x00, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+	{0xf4, 0x00}, {0x21, 0x01}, {0xf6, 0x00}, {0xf7, 0x00},
+	{0x1d, 0x01}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+	{0xfc, 0x00}, {0x6d, 0x01}, {0x5d, 0x01}, {0xd9, 0x02},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0xa3, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+	0xb0, 0x00, 0xb2, 0xb3, 0xb4, 0xb5, 0x00, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0x00, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0xc6, 0xe6, 0xc5, 0xe5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0xd8, 0xf8, 0xab, 0xbb, /* 0x18-0x1f */
+	0xd5, 0xf5, 0x00, 0x00, 0xa6, 0xb6, 0xa1, 0xb1, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0xa9, 0xb9, 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0xde, 0xfe, 0xaa, 0xba, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0xdd, 0xfd, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0xaf, 0xbf, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0xa2, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, page02, NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0x00, 0xb2, 0xb3, 0xb4, 0xb5, 0x00, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-3",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_3(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_3();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_4.c linux/fs/nls_iso8859_4.c
--- v2.0.33/linux/fs/nls_iso8859_4.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_4.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,299 @@
+/*
+ * linux/fs/nls_iso8859-4.c
+ *
+ * Charset iso8859-4 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0x04, 0x01}, {0x38, 0x01}, {0x56, 0x01},
+	{0xa4, 0x00}, {0x28, 0x01}, {0x3b, 0x01}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0x60, 0x01}, {0x12, 0x01}, {0x22, 0x01},
+	{0x66, 0x01}, {0xad, 0x00}, {0x7d, 0x01}, {0xaf, 0x00},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0x05, 0x01}, {0xdb, 0x02}, {0x57, 0x01},
+	{0xb4, 0x00}, {0x29, 0x01}, {0x3c, 0x01}, {0xc7, 0x02},
+	{0xb8, 0x00}, {0x61, 0x01}, {0x13, 0x01}, {0x23, 0x01},
+	{0x67, 0x01}, {0x4a, 0x01}, {0x7e, 0x01}, {0x4b, 0x01},
+	/* 0xc0*/
+	{0x00, 0x01}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+	{0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0x2e, 0x01},
+	{0x0c, 0x01}, {0xc9, 0x00}, {0x18, 0x01}, {0xcb, 0x00},
+	{0x16, 0x01}, {0xcd, 0x00}, {0xce, 0x00}, {0x2a, 0x01},
+	/* 0xd0*/
+	{0x10, 0x01}, {0x45, 0x01}, {0x4c, 0x01}, {0x36, 0x01},
+	{0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+	{0xd8, 0x00}, {0x72, 0x01}, {0xda, 0x00}, {0xdb, 0x00},
+	{0xdc, 0x00}, {0x68, 0x01}, {0x6a, 0x01}, {0xdf, 0x00},
+	/* 0xe0*/
+	{0x01, 0x01}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+	{0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0x2f, 0x01},
+	{0x0d, 0x01}, {0xe9, 0x00}, {0x19, 0x01}, {0xeb, 0x00},
+	{0x17, 0x01}, {0xed, 0x00}, {0xee, 0x00}, {0x2b, 0x01},
+	/* 0xf0*/
+	{0x11, 0x01}, {0x46, 0x01}, {0x4d, 0x01}, {0x37, 0x01},
+	{0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+	{0xf8, 0x00}, {0x73, 0x01}, {0xfa, 0x00}, {0xfb, 0x00},
+	{0xfc, 0x00}, {0x69, 0x01}, {0x6b, 0x01}, {0xd9, 0x02},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0x00, /* 0xc0-0xc7 */
+	0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0x00, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+	0x00, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0x00, /* 0xe0-0xe7 */
+	0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0x00, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0xc0, 0xe0, 0x00, 0x00, 0xa1, 0xb1, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */
+	0xd0, 0xf0, 0xaa, 0xba, 0x00, 0x00, 0xcc, 0xec, /* 0x10-0x17 */
+	0xca, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0xab, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0xa5, 0xb5, 0xcf, 0xef, 0x00, 0x00, 0xc7, 0xe7, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xf3, /* 0x30-0x37 */
+	0xa2, 0x00, 0x00, 0xa6, 0xb6, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf1, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0xbd, 0xbf, 0xd2, 0xf2, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xb3, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0xa9, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xac, 0xbc, /* 0x60-0x67 */
+	0xdd, 0xfd, 0xde, 0xfe, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0xd9, 0xf9, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xbe, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0xff, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, page02, NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0x00, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-4",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_4(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_4();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_5.c linux/fs/nls_iso8859_5.c
--- v2.0.33/linux/fs/nls_iso8859_5.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_5.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,303 @@
+/*
+ * linux/fs/nls_iso8859-5.c
+ *
+ * Charset iso8859-5 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0x01, 0x04}, {0x02, 0x04}, {0x03, 0x04},
+	{0x04, 0x04}, {0x05, 0x04}, {0x06, 0x04}, {0x07, 0x04},
+	{0x08, 0x04}, {0x09, 0x04}, {0x0a, 0x04}, {0x0b, 0x04},
+	{0x0c, 0x04}, {0xad, 0x00}, {0x0e, 0x04}, {0x0f, 0x04},
+	/* 0xb0*/
+	{0x10, 0x04}, {0x11, 0x04}, {0x12, 0x04}, {0x13, 0x04},
+	{0x14, 0x04}, {0x15, 0x04}, {0x16, 0x04}, {0x17, 0x04},
+	{0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04}, {0x1b, 0x04},
+	{0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04}, {0x1f, 0x04},
+	/* 0xc0*/
+	{0x20, 0x04}, {0x21, 0x04}, {0x22, 0x04}, {0x23, 0x04},
+	{0x24, 0x04}, {0x25, 0x04}, {0x26, 0x04}, {0x27, 0x04},
+	{0x28, 0x04}, {0x29, 0x04}, {0x2a, 0x04}, {0x2b, 0x04},
+	{0x2c, 0x04}, {0x2d, 0x04}, {0x2e, 0x04}, {0x2f, 0x04},
+	/* 0xd0*/
+	{0x30, 0x04}, {0x31, 0x04}, {0x32, 0x04}, {0x33, 0x04},
+	{0x34, 0x04}, {0x35, 0x04}, {0x36, 0x04}, {0x37, 0x04},
+	{0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04}, {0x3b, 0x04},
+	{0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04}, {0x3f, 0x04},
+	/* 0xe0*/
+	{0x40, 0x04}, {0x41, 0x04}, {0x42, 0x04}, {0x43, 0x04},
+	{0x44, 0x04}, {0x45, 0x04}, {0x46, 0x04}, {0x47, 0x04},
+	{0x48, 0x04}, {0x49, 0x04}, {0x4a, 0x04}, {0x4b, 0x04},
+	{0x4c, 0x04}, {0x4d, 0x04}, {0x4e, 0x04}, {0x4f, 0x04},
+	/* 0xf0*/
+	{0x16, 0x21}, {0x51, 0x04}, {0x52, 0x04}, {0x53, 0x04},
+	{0x54, 0x04}, {0x55, 0x04}, {0x56, 0x04}, {0x57, 0x04},
+	{0x58, 0x04}, {0x59, 0x04}, {0x5a, 0x04}, {0x5b, 0x04},
+	{0x5c, 0x04}, {0xa7, 0x00}, {0x5e, 0x04}, {0x5f, 0x04},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+	0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, /* 0x08-0x0f */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0x18-0x1f */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0x38-0x3f */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+	0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x50-0x57 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0xfe, 0xff, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page21[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   page04, NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   page21, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-5",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_5(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_5();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_6.c linux/fs/nls_iso8859_6.c
--- v2.0.33/linux/fs/nls_iso8859_6.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_6.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,263 @@
+/*
+ * linux/fs/nls_iso8859-6.c
+ *
+ * Charset iso8859-6 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x60, 0x06}, {0x61, 0x06}, {0x62, 0x06}, {0x63, 0x06},
+	{0x64, 0x06}, {0x65, 0x06}, {0x66, 0x06}, {0x67, 0x06},
+	{0x68, 0x06}, {0x69, 0x06}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0xa4, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x0c, 0x06}, {0xad, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xb0*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x1b, 0x06},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x1f, 0x06},
+	/* 0xc0*/
+	{0x00, 0x00}, {0x21, 0x06}, {0x22, 0x06}, {0x23, 0x06},
+	{0x24, 0x06}, {0x25, 0x06}, {0x26, 0x06}, {0x27, 0x06},
+	{0x28, 0x06}, {0x29, 0x06}, {0x2a, 0x06}, {0x2b, 0x06},
+	{0x2c, 0x06}, {0x2d, 0x06}, {0x2e, 0x06}, {0x2f, 0x06},
+	/* 0xd0*/
+	{0x30, 0x06}, {0x31, 0x06}, {0x32, 0x06}, {0x33, 0x06},
+	{0x34, 0x06}, {0x35, 0x06}, {0x36, 0x06}, {0x37, 0x06},
+	{0x38, 0x06}, {0x39, 0x06}, {0x3a, 0x06}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xe0*/
+	{0x40, 0x06}, {0x41, 0x06}, {0x42, 0x06}, {0x43, 0x06},
+	{0x44, 0x06}, {0x45, 0x06}, {0x46, 0x06}, {0x47, 0x06},
+	{0x48, 0x06}, {0x49, 0x06}, {0x4a, 0x06}, {0x4b, 0x06},
+	{0x4c, 0x06}, {0x4d, 0x06}, {0x4e, 0x06}, {0x4f, 0x06},
+	/* 0xf0*/
+	{0x50, 0x06}, {0x51, 0x06}, {0x52, 0x06}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page06[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0x18-0x1f */
+	0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */
+	0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+	0xf0, 0xf1, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x60-0x67 */
+	0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   NULL,   NULL,   page06, NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-6",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_6(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_6();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_7.c linux/fs/nls_iso8859_7.c
--- v2.0.33/linux/fs/nls_iso8859_7.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_7.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,339 @@
+/*
+ * linux/fs/nls_iso8859-7.c
+ *
+ * Charset iso8859-7 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0xbd, 0x02}, {0xbc, 0x02}, {0xa3, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0xa9, 0x00}, {0x00, 0x00}, {0xab, 0x00},
+	{0xac, 0x00}, {0xad, 0x00}, {0x00, 0x00}, {0x15, 0x20},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+	{0x84, 0x03}, {0x85, 0x03}, {0x86, 0x03}, {0xb7, 0x00},
+	{0x88, 0x03}, {0x89, 0x03}, {0x8a, 0x03}, {0xbb, 0x00},
+	{0x8c, 0x03}, {0xbd, 0x00}, {0x8e, 0x03}, {0x8f, 0x03},
+	/* 0xc0*/
+	{0x90, 0x03}, {0x91, 0x03}, {0x92, 0x03}, {0x93, 0x03},
+	{0x94, 0x03}, {0x95, 0x03}, {0x96, 0x03}, {0x97, 0x03},
+	{0x98, 0x03}, {0x99, 0x03}, {0x9a, 0x03}, {0x9b, 0x03},
+	{0x9c, 0x03}, {0x9d, 0x03}, {0x9e, 0x03}, {0x9f, 0x03},
+	/* 0xd0*/
+	{0xa0, 0x03}, {0xa1, 0x03}, {0x00, 0x00}, {0xa3, 0x03},
+	{0xa4, 0x03}, {0xa5, 0x03}, {0xa6, 0x03}, {0xa7, 0x03},
+	{0xa8, 0x03}, {0xa9, 0x03}, {0xaa, 0x03}, {0xab, 0x03},
+	{0xac, 0x03}, {0xad, 0x03}, {0xae, 0x03}, {0xaf, 0x03},
+	/* 0xe0*/
+	{0xb0, 0x03}, {0xb1, 0x03}, {0xb2, 0x03}, {0xb3, 0x03},
+	{0xb4, 0x03}, {0xb5, 0x03}, {0xb6, 0x03}, {0xb7, 0x03},
+	{0xb8, 0x03}, {0xb9, 0x03}, {0xba, 0x03}, {0xbb, 0x03},
+	{0xbc, 0x03}, {0xbd, 0x03}, {0xbe, 0x03}, {0xbf, 0x03},
+	/* 0xf0*/
+	{0xc0, 0x03}, {0xc1, 0x03}, {0xc2, 0x03}, {0xc3, 0x03},
+	{0xc4, 0x03}, {0xc5, 0x03}, {0xc6, 0x03}, {0xc7, 0x03},
+	{0xc8, 0x03}, {0xc9, 0x03}, {0xca, 0x03}, {0xcb, 0x03},
+	{0xcc, 0x03}, {0xcd, 0x03}, {0xce, 0x03}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0xa2, 0xa1, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0xb4, 0xb5, 0xb6, 0x00, /* 0x80-0x87 */
+	0xb8, 0xb9, 0xba, 0x00, 0xbc, 0x00, 0xbe, 0xbf, /* 0x88-0x8f */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x90-0x97 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x98-0x9f */
+	0xd0, 0xd1, 0x00, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xa0-0xa7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xa8-0xaf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xb0-0xb7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xb8-0xbf */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xc0-0xc7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   page02, page03, NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-7",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_7(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_7();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_8.c linux/fs/nls_iso8859_8.c
--- v2.0.33/linux/fs/nls_iso8859_8.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_8.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,303 @@
+/*
+ * linux/fs/nls_iso8859-8.c
+ *
+ * Charset iso8859-8 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0x00, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+	{0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0xa9, 0x00}, {0xd7, 0x00}, {0xab, 0x00},
+	{0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0x3e, 0x20},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+	{0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+	{0xb8, 0x00}, {0xb9, 0x00}, {0xf7, 0x00}, {0xbb, 0x00},
+	{0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0x00, 0x00},
+	/* 0xc0*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xd0*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x17, 0x20},
+	/* 0xe0*/
+	{0xd0, 0x05}, {0xd1, 0x05}, {0xd2, 0x05}, {0xd3, 0x05},
+	{0xd4, 0x05}, {0xd5, 0x05}, {0xd6, 0x05}, {0xd7, 0x05},
+	{0xd8, 0x05}, {0xd9, 0x05}, {0xda, 0x05}, {0xdb, 0x05},
+	{0xdc, 0x05}, {0xdd, 0x05}, {0xde, 0x05}, {0xdf, 0x05},
+	/* 0xf0*/
+	{0xe0, 0x05}, {0xe1, 0x05}, {0xe2, 0x05}, {0xe3, 0x05},
+	{0xe4, 0x05}, {0xe5, 0x05}, {0xe6, 0x05}, {0xe7, 0x05},
+	{0xe8, 0x05}, {0xe9, 0x05}, {0xea, 0x05}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page05[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */
+	0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   NULL,   page05, NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	page20, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-8",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_8(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_8();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_iso8859_9.c linux/fs/nls_iso8859_9.c
--- v2.0.33/linux/fs/nls_iso8859_9.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_9.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,263 @@
+/*
+ * linux/fs/nls_iso8859-9.c
+ *
+ * Charset iso8859-9 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0x90*/
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	{0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+	/* 0xa0*/
+	{0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+	{0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+	{0xa8, 0x00}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+	{0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+	/* 0xb0*/
+	{0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+	{0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+	{0xb8, 0x00}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+	{0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0xbf, 0x00},
+	/* 0xc0*/
+	{0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+	{0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+	{0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+	{0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+	/* 0xd0*/
+	{0x1e, 0x01}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+	{0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+	{0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+	{0xdc, 0x00}, {0x30, 0x01}, {0x5e, 0x01}, {0xdf, 0x00},
+	/* 0xe0*/
+	{0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+	{0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+	{0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+	{0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+	/* 0xf0*/
+	{0x1f, 0x01}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+	{0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+	{0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+	{0xfc, 0x00}, {0x31, 0x01}, {0x5f, 0x01}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0xdd, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xfe, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"iso8859-9",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_iso8859_9(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_iso8859_9();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/nls_koi8_r.c linux/fs/nls_koi8_r.c
--- v2.0.33/linux/fs/nls_koi8_r.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_koi8_r.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,375 @@
+/*
+ * linux/fs/nls_koi8-r.c
+ *
+ * Charset koi8-r translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x25}, {0x02, 0x25}, {0x0c, 0x25}, {0x10, 0x25},
+	{0x14, 0x25}, {0x18, 0x25}, {0x1c, 0x25}, {0x24, 0x25},
+	{0x2c, 0x25}, {0x34, 0x25}, {0x3c, 0x25}, {0x80, 0x25},
+	{0x84, 0x25}, {0x88, 0x25}, {0x8c, 0x25}, {0x90, 0x25},
+	/* 0x90*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x20, 0x23},
+	{0xa0, 0x25}, {0x19, 0x22}, {0x1a, 0x22}, {0x48, 0x22},
+	{0x64, 0x22}, {0x65, 0x22}, {0xa0, 0x00}, {0x21, 0x23},
+	{0xb0, 0x00}, {0xb2, 0x00}, {0xb7, 0x00}, {0xf7, 0x00},
+	/* 0xa0*/
+	{0x50, 0x25}, {0x51, 0x25}, {0x52, 0x25}, {0x51, 0x04},
+	{0x53, 0x25}, {0x54, 0x25}, {0x55, 0x25}, {0x56, 0x25},
+	{0x57, 0x25}, {0x58, 0x25}, {0x59, 0x25}, {0x5a, 0x25},
+	{0x5b, 0x25}, {0x5c, 0x25}, {0x5d, 0x25}, {0x5e, 0x25},
+	/* 0xb0*/
+	{0x5f, 0x25}, {0x60, 0x25}, {0x61, 0x25}, {0x01, 0x04},
+	{0x62, 0x25}, {0x63, 0x25}, {0x64, 0x25}, {0x65, 0x25},
+	{0x66, 0x25}, {0x67, 0x25}, {0x68, 0x25}, {0x69, 0x25},
+	{0x6a, 0x25}, {0x6b, 0x25}, {0x6c, 0x25}, {0xa9, 0x00},
+	/* 0xc0*/
+	{0x4e, 0x04}, {0x30, 0x04}, {0x31, 0x04}, {0x46, 0x04},
+	{0x34, 0x04}, {0x35, 0x04}, {0x44, 0x04}, {0x33, 0x04},
+	{0x45, 0x04}, {0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04},
+	{0x3b, 0x04}, {0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04},
+	/* 0xd0*/
+	{0x3f, 0x04}, {0x4f, 0x04}, {0x40, 0x04}, {0x41, 0x04},
+	{0x42, 0x04}, {0x43, 0x04}, {0x36, 0x04}, {0x32, 0x04},
+	{0x4c, 0x04}, {0x4b, 0x04}, {0x37, 0x04}, {0x48, 0x04},
+	{0x4d, 0x04}, {0x49, 0x04}, {0x47, 0x04}, {0x4a, 0x04},
+	/* 0xe0*/
+	{0x2e, 0x04}, {0x10, 0x04}, {0x11, 0x04}, {0x26, 0x04},
+	{0x14, 0x04}, {0x15, 0x04}, {0x24, 0x04}, {0x13, 0x04},
+	{0x25, 0x04}, {0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04},
+	{0x1b, 0x04}, {0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04},
+	/* 0xf0*/
+	{0x1f, 0x04}, {0x2f, 0x04}, {0x20, 0x04}, {0x21, 0x04},
+	{0x22, 0x04}, {0x23, 0x04}, {0x16, 0x04}, {0x12, 0x04},
+	{0x2c, 0x04}, {0x2b, 0x04}, {0x17, 0x04}, {0x28, 0x04},
+	{0x2d, 0x04}, {0x29, 0x04}, {0x27, 0x04}, {0x2a, 0x04},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+	0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */
+	0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */
+	0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */
+	0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */
+	0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */
+	0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */
+	0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */
+	0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */
+	0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xa0, 0xa1, 0xa2, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, /* 0x50-0x57 */
+	0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */
+	0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, /* 0x60-0x67 */
+	0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   page04, NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"koi8-r",
+	page_uni2charset,
+	charset2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int init_nls_koi8_r(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_koi8_r();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v2.0.33/linux/fs/select.c linux/fs/select.c
--- v2.0.33/linux/fs/select.c	Mon Dec 30 05:57:02 1996
+++ linux/fs/select.c	Wed Jun  3 15:17:49 1998
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/personality.h>
 #include <linux/mm.h>
+#include <linux/file.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -57,6 +58,34 @@
 }
 
 /*
+ *	File handle locking
+ */
+ 
+static void lock_fd_bits(int n, int x)
+{
+	int i;
+	for(i=0;i<__NFDBITS;i++)
+	{
+		if(x&(1<<i))
+			fget(n+i);
+	}
+}
+
+static void unlock_fd_bits(int n, int x)
+{
+	int i;
+	for(i=0;i<__NFDBITS;i++)
+	{
+		if(x&(1<<i))
+		{
+			/* ick */
+			struct file *f=current->files->fd[n+i];
+			fput(f, f->f_inode);
+		}
+	}
+}
+
+/*
  * The check function checks the ready status of a file using the vfs layer.
  *
  * If the file was not ready we were added to its wait queue.  But in
@@ -83,7 +112,7 @@
 }
 
 static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
-	fd_set *res_in, fd_set *res_out, fd_set *res_ex)
+	fd_set *res_in, fd_set *res_out, fd_set *res_ex, fd_set *locked)
 {
 	int count;
 	select_table wait_table, *wait;
@@ -91,7 +120,7 @@
 	unsigned long set;
 	int i,j;
 	int max = -1;
-
+	int threaded = 0;
 	j = 0;
 	for (;;) {
 		i = j * __NFDBITS;
@@ -113,8 +142,34 @@
 	}
 end_check:
 	n = max + 1;
+	
+	/* Now we _must_ lock the handles before we get the page otherwise
+	   they may get closed on us during the kmalloc causing explosions.. */
+	
+	if(current->files->count>1)
+	{	
+	
+		/*
+		 *	Only for the threaded cases must we do work.
+		 */
+		j = 0;
+		for (;;) {
+			i = j * __NFDBITS;
+			if (i >= n)
+				break;
+			lock_fd_bits(i,in->fds_bits[j]);
+			lock_fd_bits(i,out->fds_bits[j]);
+			lock_fd_bits(i,ex->fds_bits[j]);
+			j++;
+		}
+		threaded=1;
+	}
+		
 	if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
+	{
+		count = -ENOMEM; 
+		goto bale;
+	}
 	count = 0;
 	wait_table.nr = 0;
 	wait_table.entry = entry;
@@ -149,6 +204,22 @@
 	free_wait(&wait_table);
 	free_page((unsigned long) entry);
 	current->state = TASK_RUNNING;
+bale:
+
+	if(threaded)
+	{
+		/* Unlock handles now */	
+		j = 0;
+		for (;;) {
+			i = j * __NFDBITS;
+			if (i >= n)
+				break;
+			unlock_fd_bits(i,in->fds_bits[j]);
+			unlock_fd_bits(i,out->fds_bits[j]);
+			unlock_fd_bits(i,ex->fds_bits[j]);
+			j++;
+		}
+	}
 	return count;
 }
 
@@ -243,6 +314,7 @@
 	limited_fd_set res_in, in;
 	limited_fd_set res_out, out;
 	limited_fd_set res_ex, ex;
+	limited_fd_set locked;
 	unsigned long timeout;
 
 	error = -EINVAL;
@@ -273,7 +345,8 @@
 		(fd_set *) &ex,
 		(fd_set *) &res_in,
 		(fd_set *) &res_out,
-		(fd_set *) &res_ex);
+		(fd_set *) &res_ex,
+		(fd_set *) &locked);
 	timeout = current->timeout - jiffies - 1;
 	current->timeout = 0;
 	if ((long) timeout < 0)
diff -u --recursive --new-file v2.0.33/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.0.33/linux/fs/smbfs/dir.c	Wed Aug 13 09:57:46 1997
+++ linux/fs/smbfs/dir.c	Wed Jun  3 15:17:49 1998
@@ -107,21 +107,6 @@
 	return result;
 }
 
-static int
-compare_filename(const struct smb_server *server,
-		 const char *s1, int len, struct smb_dirent *entry)
-{
-	if (len != entry->len)
-	{
-		return 1;
-	}
-	if (server->case_handling == CASE_DEFAULT)
-	{
-		return strncasecmp(s1, entry->name, len);
-	}
-	return strncmp(s1, entry->name, len);
-}
-
 struct smb_inode_info *
 smb_find_inode(struct smb_server *server, ino_t ino)
 {
@@ -507,9 +492,33 @@
 	return;
 }
 
-/* We will search the inode that belongs to this name, currently by a
-   complete linear search through the inodes belonging to this
-   filesystem. This has to be fixed. */
+static int
+compare_filename(const struct smb_server *server,
+		 const char *s1, int len, struct smb_dirent *entry)
+{
+	if (len != entry->len)
+	{
+#if 0
+		/* Check whether the entry is about to be removed */
+		if (!entry->len)
+			printk("SMBFS: dead entry %s\n", entry->name);
+#endif
+		return 1;
+	}
+	if (server->case_handling == CASE_DEFAULT)
+	{
+		return strncasecmp(s1, entry->name, len);
+	}
+	return strncmp(s1, entry->name, len);
+}
+
+/*
+ * Search for the smb_inode_info that belongs to this name,
+ * currently by a complete linear search through the inodes
+ * belonging to this filesystem.
+ *
+ * Note that this returns files as well as directories.
+ */
 static struct smb_inode_info *
 smb_find_dir_inode(struct inode *parent, const char *name, int len)
 {
diff -u --recursive --new-file v2.0.33/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.0.33/linux/fs/smbfs/inode.c	Mon Sep 15 10:02:41 1997
+++ linux/fs/smbfs/inode.c	Wed Jun  3 15:17:49 1998
@@ -95,11 +95,10 @@
 {
 	struct smb_server *server = SMB_SERVER(inode);
 	struct smb_inode_info *info = SMB_INOP(inode);
-	struct smb_dirent *finfo;
 	__u32 mtime = inode->i_mtime;
 
 	if (inode->i_count > 1) {
-		printk("smb_put_inode: in use device %s, inode %ld count=%d\n",
+		printk("smb_put_inode: in use device %s, inode %ld count=%ld\n",
 			kdevname(inode->i_dev), inode->i_ino, inode->i_count);
 		return;
 	}
@@ -107,6 +106,12 @@
 	if (S_ISDIR(inode->i_mode))
 	{
 		smb_invalid_dir_cache(inode->i_ino);
+	} else
+	{
+		/*
+		 * Clear the length so the info structure can't be found.
+		 */
+		info->finfo.len = 0;
 	}
 	clear_inode(inode);
 
@@ -116,13 +121,13 @@
 	 */
 	inode->i_count++;
 	if (info) {
-		finfo = &info->finfo;
-		if (finfo->opened != 0)
+		if (info->finfo.opened != 0)
 		{
-			if (smb_proc_close(server, finfo->fileid, mtime))
+			if (smb_proc_close(server, info->finfo.fileid, mtime))
 			{
 				/* We can't do anything but complain. */
-				printk("smb_put_inode: could not close\n");
+				printk("smb_put_inode: could not close %s\n",
+					info->finfo.name);
 			}
 		}
 		smb_free_inode_info(info);
diff -u --recursive --new-file v2.0.33/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.0.33/linux/fs/smbfs/proc.c	Mon Sep 15 10:02:41 1997
+++ linux/fs/smbfs/proc.c	Wed Jun  3 15:17:49 1998
@@ -570,6 +570,8 @@
 			smb_unlock_server(server);
 			return error;
 		}
+		/* N.B. Packet may change after request */
+		buf = server->packet;
 		p = smb_setup_header(server, SMBopen, 2, 0);
 		WSET(buf, smb_vwv0, 0x40);	/* read only */
 		WSET(buf, smb_vwv1, o_attr);
@@ -589,6 +591,8 @@
 	}
 	/* We should now have data in vwv[0..6]. */
 
+	/* N.B. Packet may change after request */
+	buf = server->packet;
 	entry->fileid = WVAL(buf, smb_vwv0);
 	entry->attr = WVAL(buf, smb_vwv1);
 	entry->f_ctime = entry->f_atime =
@@ -646,7 +650,7 @@
 		smb_unlock_server(server);
 		return error;
 	}
-	returned_count = WVAL(buf, smb_vwv0);
+	returned_count = WVAL(server->packet, smb_vwv0);
 
 	smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);
 
@@ -682,7 +686,7 @@
 
 	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
 	{
-		res = WVAL(buf, smb_vwv0);
+		res = WVAL(server->packet, smb_vwv0);
 	}
 	smb_unlock_server(server);
 
@@ -718,7 +722,7 @@
 		smb_unlock_server(server);
 		return error;
 	}
-	fileid = WVAL(buf, smb_vwv0);
+	fileid = WVAL(server->packet, smb_vwv0);
 	smb_unlock_server(server);
 
 	smb_proc_close(server, fileid, CURRENT_TIME);
@@ -1345,6 +1349,10 @@
 					      entry);
 }
 
+/*
+ * This version uses the core protocol to get the attribute info.
+ * It works OK with Win 3.11, 95 and NT 3.51, but NOT with NT 4 (bad mtime).
+ */
 static int
 smb_proc_getattr_core(struct inode *dir, const char *name, int len,
 		      struct smb_dirent *entry)
@@ -1356,7 +1364,7 @@
 
 	smb_lock_server(server);
 
-	DDPRINTK("smb_proc_getattr: %s\n", name);
+	DDPRINTK("smb_proc_getattr_core: %s\n", name);
 
       retry:
 	buf = server->packet;
@@ -1374,15 +1382,105 @@
 		smb_unlock_server(server);
 		return result;
 	}
+	/* N.B. Packet may change after request */
+	buf = server->packet;
 	entry->attr = WVAL(buf, smb_vwv0);
 	entry->f_ctime = entry->f_atime =
 	    entry->f_mtime = local2utc(DVAL(buf, smb_vwv1));
 
+	DDPRINTK("smb_proc_getattr_core: mtime=%ld\n", entry->f_mtime);
+
 	entry->f_size = DVAL(buf, smb_vwv3);
 	smb_unlock_server(server);
 	return 0;
 }
 
+/*
+ * This version uses the trans2 findfirst to get the attribute info.
+ * It works fine with NT 3.51 and NT 4 (any SP), but not with Win95 (ERRerror).
+ */
+static int
+smb_proc_getattr_ff(struct inode *dir, const char *name, int len,
+		    struct smb_dirent *entry)
+{
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	char param[SMB_MAXPATHLEN + 1 + 12];
+	int mask_len;
+	unsigned char *mask = &(param[12]);
+
+	int result;
+	char *p;
+	struct smb_server *server = SMB_SERVER(dir);
+
+	mask_len = smb_encode_path(server, mask,
+				   SMB_INOP(dir), name, len) - mask;
+
+	mask[mask_len] = 0;
+
+	DDPRINTK("smb_proc_getattr_ff: mask=%s\n", mask);
+
+	smb_lock_server(server);
+
+      retry:
+
+	WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
+	WSET(param, 2, 1);      /* max count */
+	WSET(param, 4, 2 + 1);  /* close on end + close after this call */
+	WSET(param, 6, 1);      /* info level */
+	DSET(param, 8, 0);
+
+	result = smb_trans2_request(server, TRANSACT2_FINDFIRST,
+				    0, NULL, 12 + mask_len + 1, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+
+	if (result < 0)
+	{
+		if (smb_retry(server))
+		{
+			DPRINTK("smb_proc_getattr_ff: error=%d, retrying\n",
+				 result);
+			goto retry;
+		}
+		goto out;
+	}
+	if (server->rcls != 0)
+	{
+		result = -smb_errno(server->rcls, server->err);
+		if (result != -ENOENT)
+			DPRINTK("smb_proc_getattr_ff: rcls=%d, err=%d\n",
+				 server->rcls, server->err);
+		goto out;
+	}
+	/* Make sure we got enough data ... */
+	result = -EINVAL;      /* WVAL(resp_param, 2) is ff_searchcount */
+	if (resp_data_len < 22 || WVAL(resp_param, 2) != 1)
+	{
+		DPRINTK("smb_proc_getattr_ff: bad result, len=%d, count=%d\n",
+			 resp_data_len, WVAL(resp_param, 2));
+		goto out;
+	}
+	/* Decode the response (info level 1, as in smb_decode_long_dirent) */
+	p = resp_data;
+	entry->f_ctime = date_dos2unix(WVAL(p, 2), WVAL(p, 0));
+	entry->f_atime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
+	entry->f_mtime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
+	entry->f_size = DVAL(p, 12);
+	entry->attr = WVAL(p, 20);
+
+	DDPRINTK("smb_proc_getattr_ff: attr=%x\n", entry->attr);
+
+	result = 0;
+
+out:
+	smb_unlock_server(server);
+	return result;
+}
+
 int
 smb_proc_getattr(struct inode *dir, const char *name, int len,
 		 struct smb_dirent *entry)
@@ -1391,7 +1489,17 @@
         int result;
 
 	smb_init_dirent(server, entry);
-        result = smb_proc_getattr_core(dir, name, len, entry);
+ 
+ 	/* Use trans2 for NT, use core protocol for others (Win95/3.11/...).
+ 	 * We distinguish NT from Win95 by looking at the capabilities,
+ 	 * in the same way as in Samba 1.9.18p2's reply.c.
+ 	 */
+	if ((server->protocol >= PROTOCOL_LANMAN2)
+	    && (server->blkmode & (CAP_NT_SMBS | CAP_STATUS32)))
+		result = smb_proc_getattr_ff(dir, name, len, entry);
+	else
+		result = smb_proc_getattr_core(dir, name, len, entry);
+
 	smb_finish_dirent(server, entry);
 
 	entry->len = len;
@@ -1612,12 +1720,12 @@
 		word passlen = strlen(server->m.password);
 		word userlen = strlen(server->m.username);
 
+#ifdef DEBUG_SMB_PASSWORD
 		DPRINTK("smb_proc_connect: password = %s\n",
 			server->m.password);
+#endif			
 		DPRINTK("smb_proc_connect: usernam = %s\n",
 			server->m.username);
-		DPRINTK("smb_proc_connect: blkmode = %d\n",
-			WVAL(server->packet, smb_vwv5));
 
 		if (server->protocol >= PROTOCOL_NT1)
 		{
@@ -1634,6 +1742,8 @@
 			server->blkmode = WVAL(server->packet, smb_vwv5);
 			server->sesskey = DVAL(server->packet, smb_vwv6);
 		}
+		DPRINTK("smb_proc_connect: blkmode (capabilities) = %x\n",
+			server->blkmode);
 
 		if (server->max_xmit < given_max_xmit)
 		{
diff -u --recursive --new-file v2.0.33/linux/fs/super.c linux/fs/super.c
--- v2.0.33/linux/fs/super.c	Mon Aug 18 13:01:15 1997
+++ linux/fs/super.c	Wed Jun  3 15:17:49 1998
@@ -972,12 +972,21 @@
 
 #ifdef CONFIG_BLK_DEV_FD
 	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+		extern int rd_doload;
 		floppy_eject();
 #ifndef CONFIG_BLK_DEV_RAM
 		printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
 #endif
-		printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
-		wait_for_keypress();
+#ifdef CONFIG_BLK_DEV_INITRD
+		/* rd_doload is 2 for a dual initrd/ramload setup */
+		if(rd_doload==2)
+			rd_load_secondary();
+		else
+#endif		
+		{
+			printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
+			wait_for_keypress();
+		}
 	}
 #endif
 
diff -u --recursive --new-file v2.0.33/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- v2.0.33/linux/fs/sysv/ialloc.c	Sat Nov 30 02:21:21 1996
+++ linux/fs/sysv/ialloc.c	Wed Jun  3 15:17:49 1998
@@ -63,7 +63,7 @@
 		return;
 	}
 	if (inode->i_count != 1) {
-		printk("sysv_free_inode: inode has count=%d\n", inode->i_count);
+		printk("sysv_free_inode: inode has count=%ld\n", inode->i_count);
 		return;
 	}
 	if (inode->i_nlink) {
diff -u --recursive --new-file v2.0.33/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- v2.0.33/linux/fs/ufs/ufs_inode.c	Sat Nov 30 02:21:22 1996
+++ linux/fs/ufs/ufs_inode.c	Wed Jun  3 15:17:49 1998
@@ -23,7 +23,7 @@
 
 void ufs_print_inode(struct inode * inode)
 {
-	printk("ino %lu  mode 0%6.6o  lk %d  uid %d  gid %d  sz %lu  blks %lu  cnt %u\n",
+	printk("ino %lu  mode 0%6.6o  lk %d  uid %d  gid %d  sz %lu  blks %lu  cnt %lu\n",
 	       inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
 	printk("  db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x>\n",
 	       inode->u.ufs_i.ui_db[0], inode->u.ufs_i.ui_db[1],
diff -u --recursive --new-file v2.0.33/linux/fs/vfat/Makefile linux/fs/vfat/Makefile
--- v2.0.33/linux/fs/vfat/Makefile	Mon May  6 01:43:19 1996
+++ linux/fs/vfat/Makefile	Wed Jun  3 15:17:49 1998
@@ -8,8 +8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := vfat.o
-O_OBJS   := 
-OX_OBJS  := namei.o
+O_OBJS   := namei.o
+OX_OBJS  := vfatfs_syms.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.0.33/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.0.33/linux/fs/vfat/namei.c	Tue Dec  2 13:52:32 1997
+++ linux/fs/vfat/namei.c	Wed Jun  3 15:17:49 1998
@@ -10,20 +10,21 @@
  *    the problem, send a script that demonstrates it.
  */
 
+#include <linux/config.h>
+#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sched.h>
 #include <linux/msdos_fs.h>
+#include <linux/nls.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
-
-#include <asm/segment.h>
+#include <linux/malloc.h>
 
 #include "../fat/msbuffer.h"
-#include "../fat/tables.h"
 
 #if 0
 # define PRINTK(x) printk x
@@ -83,6 +84,7 @@
 
 	opts->unicode_xlate = opts->posixfs = 0;
 	opts->numtail = 1;
+	opts->utf8 = 0;
 
 	if (!options) return 1;
 	save = 0;
@@ -94,7 +96,13 @@
 			savep = value;
 			*value++ = 0;
 		}
-		if (!strcmp(this_char,"uni_xlate")) {
+		if (!strcmp(this_char,"utf8")) {
+			if (value) {
+				ret = 0;
+			} else {
+				opts->utf8 = 1;
+			}
+		} else if (!strcmp(this_char,"uni_xlate")) {
 			if (value) {
 				ret = 0;
 			} else {
@@ -124,6 +132,9 @@
 			return 0;
 		}
 	}
+	if (opts->unicode_xlate) {
+		opts->utf8 = 0;
+	}
 	return 1;
 }
 
@@ -134,6 +145,8 @@
   
 	MOD_INC_USE_COUNT;
 	
+	MSDOS_SB(sb)->options.isvfat = 1;
+
 	sb->s_op = &vfat_sops;
 	res = fat_read_super(sb, data, silent);
 	if (res == NULL) {
@@ -145,7 +158,6 @@
 	if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
 		MOD_DEC_USE_COUNT;
 	} else {
-		MSDOS_SB(sb)->options.isvfat = 1;
 		MSDOS_SB(sb)->options.dotsOK = 0;
 	}
 
@@ -220,7 +232,6 @@
 /* Characters that are undesirable in an MS-DOS file name */
 
 static char bad_chars[] = "*?<>|\":/\\";
-static char bad_if_strict[] = "+=,; []";
 static char replace_chars[] = "[];,+=";
 
 static int vfat_find(struct inode *dir,const char *name,int len,
@@ -260,8 +271,8 @@
 	return 0;
 }
 
-static int vfat_valid_shortname(char conv,const char *name,int len,
-				 int dot_dirs)
+static int vfat_valid_shortname(const char *name,int len,
+				int dot_dirs, int utf8)
 {
 	const char *walk, **reserved;
 	unsigned char c;
@@ -278,17 +289,17 @@
 	for (walk = name; len && walk-name < 8;) {
 	    	c = *walk++;
 		len--;
-		if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
-		if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
-		if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
-  		if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+		if (utf8 && (c & 0x80)) return -EINVAL;
+		if (strchr(bad_chars,c)) return -EINVAL;
+		if (strchr(replace_chars,c)) return -EINVAL;
+  		if (c >= 'A' && c <= 'Z') return -EINVAL;
 		if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
 		if ((walk == name) && (c == 0xE5)) c = 0x05;
 		if (c == '.') break;
 		space = c == ' ';
 	}
 	if (space) return -EINVAL;
-	if ((conv == 's' || conv == 'x') && len && c != '.') {
+	if (len && c != '.') {
 		c = *walk++;
 		len--;
 		if (c != '.') return -EINVAL;
@@ -299,18 +310,17 @@
 		while (len > 0 && walk-name < (MSDOS_NAME+1)) {
 			c = *walk++;
 			len--;
-			if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
-			if (conv == 's' && strchr(bad_if_strict,c))
-				return -EINVAL;
-			if (conv == 'x' && strchr(replace_chars,c))
+			if (utf8 && (c & 0x80)) return -EINVAL;
+			if (strchr(bad_chars,c)) return -EINVAL;
+			if (strchr(replace_chars,c))
 				return -EINVAL;
 			if (c < ' ' || c == ':' || c == '\\' || c == '.')
 				return -EINVAL;
-			if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+			if (c >= 'A' && c <= 'Z') return -EINVAL;
 			space = c == ' ';
 		}
 		if (space) return -EINVAL;
-		if ((conv == 's' || conv == 'x') && len) return -EINVAL;
+		if (len) return -EINVAL;
 	}
 	for (reserved = reserved_names; *reserved; reserved++)
 		if (!strncmp(name,*reserved,8)) return -EINVAL;
@@ -323,8 +333,8 @@
  * returned.  The formatted short filename is returned in 'res'.
  */
 
-static int vfat_format_name(char conv,const char *name,int len,char *res,
-  int dot_dirs)
+static int vfat_format_name(const char *name,int len,char *res,
+  int dot_dirs,int utf8)
 {
 	char *walk;
 	const char **reserved;
@@ -344,17 +354,17 @@
 	for (walk = res; len && walk-res < 8; walk++) {
 	    	c = *name++;
 		len--;
-		if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
-		if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
-		if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
-		if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+		if (utf8 && (c & 0x80)) return -EINVAL;
+		if (strchr(bad_chars,c)) return -EINVAL;
+		if (strchr(replace_chars,c)) return -EINVAL;
+		if (c >= 'A' && c <= 'Z') return -EINVAL;
 		if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
 		if (c == '.') break;
 		space = c == ' ';
 		*walk = c >= 'a' && c <= 'z' ? c-32 : c;
 	}
 	if (space) return -EINVAL;
-	if ((conv == 's' || conv == 'x') && len && c != '.') {
+	if (len && c != '.') {
 		c = *name++;
 		len--;
 		if (c != '.') return -EINVAL;
@@ -365,19 +375,18 @@
 		while (len > 0 && walk-res < MSDOS_NAME) {
 			c = *name++;
 			len--;
-			if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
-			if (conv == 's' && strchr(bad_if_strict,c))
-				return -EINVAL;
-			if (conv == 'x' && strchr(replace_chars,c))
+			if (utf8 && (c & 0x80)) return -EINVAL;
+			if (strchr(bad_chars,c)) return -EINVAL;
+			if (strchr(replace_chars,c))
 				return -EINVAL;
 			if (c < ' ' || c == ':' || c == '\\' || c == '.')
 				return -EINVAL;
-			if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+			if (c >= 'A' && c <= 'Z') return -EINVAL;
 			space = c == ' ';
 			*walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
 		}
 		if (space) return -EINVAL;
-		if ((conv == 's' || conv == 'x') && len) return -EINVAL;
+		if (len) return -EINVAL;
 	}
 	while (walk-res < MSDOS_NAME) *walk++ = ' ';
 	for (reserved = reserved_names; *reserved; reserved++)
@@ -392,7 +401,7 @@
  * shortname does not exist
  */
 static int vfat_create_shortname(struct inode *dir, const char *name,
-     int len, char *name_res)
+     int len, char *name_res, int utf8)
 {
 	const char *ip, *ext_start, *end;
 	char *p;
@@ -411,16 +420,25 @@
 	if (len && name[len-1]==' ') return -EINVAL;
 	if (len <= 12) {
 		/* Do a case insensitive search if the name would be a valid
-		 * shortname if is were all capitalized */
+		 * shortname if is were all capitalized.  However, do not
+		 * allow spaces in short names because Win95 scandisk does
+		 * not like that */
+		res = 0;
 		for (i = 0, p = msdos_name, ip = name; i < len; i++, p++, ip++)
 		{
+			if (*ip == ' ') {
+				res = -EINVAL;
+				break;
+			}
 			if (*ip >= 'A' && *ip <= 'Z') {
 				*p = *ip + 32;
 			} else {
 				*p = *ip;
 			}
 		}
-		res = vfat_format_name('x', msdos_name, len, name_res, 1);
+		if (res == 0) {
+			res = vfat_format_name(msdos_name, len, name_res, 1, utf8);
+		}
 		if (res > -1) {
 			PRINTK(("vfat_create_shortname 1\n"));
 			res = vfat_find(dir, msdos_name, len, 0, 0, 0, &sinfo);
@@ -468,7 +486,10 @@
 
 	for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++)
 	{
-		if (!strchr(skip_chars, *ip)) {
+		if (utf8 && (*ip & 0x80)) {
+			*p++ = '_';
+			baselen++;
+		} else if (!strchr(skip_chars, *ip)) {
 			if (*ip >= 'A' && *ip <= 'Z') {
 				*p = *ip + 32;
 			} else {
@@ -488,7 +509,10 @@
 	if (ext_start) {
 		extlen = 0;
 		for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
-			if (!strchr(skip_chars, *ip)) {
+			if (utf8 && (*ip & 0x80)) {
+				*p++ = '_';
+				extlen++;
+			} else if (!strchr(skip_chars, *ip)) {
 				if (*ip >= 'A' && *ip <= 'Z') {
 					*p = *ip + 32;
 				} else {
@@ -535,7 +559,7 @@
 		totlen = baselen + sz + 1 + extlen + (extlen > 0);
 		res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
 	}
-	res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
+	res = vfat_format_name(msdos_name, totlen, name_res, 1, utf8);
 	return res;
 }
 
@@ -584,7 +608,9 @@
 			ino = fat_get_entry(dir,&curr,&bh,&de);
 		}
 
-		if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+		if ((dir->i_ino == MSDOS_ROOT_INO) &&
+		    (MSDOS_SB(sb)->fat_bits != 32)) 
+			return -ENOSPC;
 		if ((res = fat_add_cluster(dir)) < 0) return res;
 		ino = fat_get_entry(dir,&curr,&bh,&de);
 	}
@@ -593,7 +619,8 @@
 
 /* Translate a string, including coded sequences into Unicode */
 static int
-xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
+xlate_to_uni(const char *name, int len, char *outname, int *outlen,
+	     int escape, int utf8, struct nls_table *nls)
 {
 	int i;
 	const unsigned char *ip;
@@ -601,22 +628,43 @@
 	int fill;
 	unsigned char c1, c2, c3;
 
-	op = outname;
-	for (i = 0, ip = name, op = outname, *outlen = 0;
-	     i < len && *outlen <= 260; i++, *outlen += 1)
-	{
-		if (escape && (i < len - 4) && 
-		    (*ip == ':') &&
-		    ((c1 = fat_code2uni[ip[1]]) != 255) &&
-		    ((c2 = fat_code2uni[ip[2]]) != 255) &&
-		    ((c3 = fat_code2uni[ip[3]]) != 255)) {
-			*op++ = (c1 << 4) + (c2 >> 2);
-			*op++ = ((c2 & 0x3) << 6) + c3;
-			ip += 4;
+	if (utf8) {
+		*outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE);
+		if (name[len-1] == '.')
+			*outlen-=2;
+		op = &outname[*outlen * sizeof(__u16)];
+	} else {
+		if (name[len-1] == '.') 
+			len--;
+		op = outname;
+		if (nls) {
+			/* XXX: i is incorrectly computed. */
+			for (i = 0, ip = name, op = outname, *outlen = 0;
+			     i < len && *outlen <= 260; i++, *outlen += 1)
+			{
+				if (escape && (*ip == ':')) {
+					if (i > len - 4) return -EINVAL;
+					c1 = fat_esc2uni[ip[1]];
+					c2 = fat_esc2uni[ip[2]];
+					c3 = fat_esc2uni[ip[3]];
+					if (c1 == 255 || c2 == 255 || c3 == 255)
+						return -EINVAL;
+					*op++ = (c1 << 4) + (c2 >> 2);
+					*op++ = ((c2 & 0x3) << 6) + c3;
+					ip += 4;
+				} else {
+					*op++ = nls->charset2uni[*ip].uni1;
+					*op++ = nls->charset2uni[*ip].uni2;
+					ip++;
+				}
+			}
 		} else {
-			*op++ = fat_a2uni[*ip].uni1;
-			*op++ = fat_a2uni[*ip].uni2;
-			ip++;
+			for (i = 0, ip = name, op = outname, *outlen = 0;
+			     i < len && *outlen <= 260; i++, *outlen += 1)
+			{
+				*op++ = *ip++;
+				*op++ = 0;
+			}
 		}
 	}
 	if (*outlen > 260)
@@ -641,7 +689,8 @@
 
 static int
 vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
-		     char *msdos_name, int *slots, int uni_xlate)
+		     char *msdos_name, int *slots,
+		     int uni_xlate, int utf8, struct nls_table *nls)
 {
 	struct msdos_dir_slot *ps;
 	struct msdos_dir_entry *de;
@@ -655,10 +704,11 @@
 	int i;
 	loff_t offset;
 
+	if (name[len-1] == '.') len--;
 	if(!(page = __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
 	uniname = (char *) page;
-	res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate);
+	res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate, utf8, nls);
 	if (res < 0) {
 		free_page(page);
 		return res;
@@ -678,8 +728,7 @@
 		ps->attr = ATTR_EXT;
 		ps->reserved = 0;
 		ps->alias_checksum = cksum;
-		ps->start[0] = 0;
-		ps->start[1] = 0;
+		ps->start = 0;
 		PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname));
 		offset = (slot - 1) * 26;
 		ip = &uniname[offset];
@@ -716,11 +765,14 @@
 {
 	struct msdos_dir_entry *de;
 	char msdos_name[MSDOS_NAME];
-	int res, xlate;
+	int res, xlate, utf8;
+	struct nls_table *nls;
 
 	PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
 	de = (struct msdos_dir_entry *) ds;
 	xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
+	utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
+	nls = MSDOS_SB(dir->i_sb)->nls_io;
 
 	*slots = 1;
 	*is_long = 0;
@@ -730,13 +782,13 @@
 		strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
 	} else {
 		PRINTK(("vfat_build_slots 4\n"));
-		res = vfat_valid_shortname('x', name, len, 1);
+		res = vfat_valid_shortname(name, len, 1, utf8);
 		if (res > -1) {
 			PRINTK(("vfat_build_slots 5a\n"));
-			res = vfat_format_name('x', name, len, de->name, 1);
+			res = vfat_format_name(name, len, de->name, 1, utf8);
 			PRINTK(("vfat_build_slots 5b\n"));
 		} else {
-			res = vfat_create_shortname(dir, name, len, msdos_name);
+			res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
 			if (res < 0) {
 				return res;
 			}
@@ -749,7 +801,7 @@
 			*is_long = 1;
 
 			return vfat_fill_long_slots(ds, name, len, msdos_name,
-						    slots, xlate);
+						    slots, xlate, utf8, nls);
 		}
 	}
 	return 0;
@@ -775,8 +827,11 @@
 			  vf->name, vf->len, name, name_len);
 #endif
 
+	/* Filenames cannot end in '.' or we treat like it has none */
 	if (vf->len != name_len) {
-		return 0;
+		if ((vf->len != name_len + 1) || (vf->name[name_len] != '.')) {
+			return 0;
+		}
 	}
 
 	s1 = name; s2 = vf->name;
@@ -809,12 +864,17 @@
 	struct msdos_dir_entry *de;
 	struct msdos_dir_slot *ps;
 	loff_t offset;
-	struct msdos_dir_slot ds[MSDOS_SLOTS];
+	struct msdos_dir_slot *ds;
 	int is_long;
 	int slots, slot;
 	int res;
 
 	PRINTK(("Entering vfat_find\n"));
+
+	ds = (struct msdos_dir_slot *)
+	    kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);
+	if (ds == NULL) return -ENOMEM;
+
 	fil.f_pos = 0;
 	vf.name = name;
 	vf.len = len;
@@ -823,10 +883,11 @@
 	vf.posix = MSDOS_SB(sb)->options.posixfs;
 	res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0);
 	PRINTK(("vfat_find: Debug 1\n"));
-	if (res < 0) return res;
+	if (res < 0) goto cleanup;
 	if (vf.found) {
 		if (new_filename) {
-			return -EEXIST;
+			res = -EEXIST;
+			goto cleanup;
 		}
 		sinfo_out->longname_offset = vf.offset;
 		sinfo_out->shortname_offset = vf.short_offset;
@@ -836,15 +897,18 @@
 		sinfo_out->ino = vf.ino;
 
 		PRINTK(("vfat_find: Debug 2\n"));
-		return 0;
+		res = 0;
+		goto cleanup;
 	}
 
 	PRINTK(("vfat_find: Debug 3\n"));
-	if (!vf.found && !new_filename)
-		return -ENOENT;
+	if (!vf.found && !new_filename) {
+		res = -ENOENT;
+		goto cleanup;
+	}
 	
 	res = vfat_build_slots(dir, name, len, ds, &slots, &is_long);
-	if (res < 0) return res;
+	if (res < 0) goto cleanup;
 
 	de = (struct msdos_dir_entry *) ds;
 
@@ -854,7 +918,8 @@
 		if (is_long) slots++;
 		offset = vfat_find_free_slots(dir, slots);
 		if (offset < 0) {
-			return offset;
+			res = offset;
+			goto cleanup;
 		}
 
 		PRINTK(("vfat_find: create file 2\n"));
@@ -865,7 +930,8 @@
 			sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
 			if (sinfo_out->ino < 0) {
 				PRINTK(("vfat_find: problem\n"));
-				return sinfo_out->ino;
+				res = sinfo_out->ino;
+				goto cleanup;
 			}
 			memcpy(de, ps, sizeof(struct msdos_dir_slot));
 			fat_mark_buffer_dirty(sb, bh, 1);
@@ -877,12 +943,12 @@
 
 		PRINTK(("vfat_find: create file 5\n"));
 
-		memset(de->unused, 0, sizeof(de->unused));
 		fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
 		de->ctime_ms = 0;
 		de->ctime = de->time;
 		de->adate = de->cdate = de->date;
 		de->start = 0;
+		de->starthi = 0;
 		de->size = 0;
 		de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 		de->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
@@ -900,10 +966,15 @@
 		sinfo_out->total_slots = slots;
 		sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
 		sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
+		res = 0;
 		return 0;
+	} else {
+		res = -ENOENT;
 	}
 
-	return -ENOENT;
+cleanup:
+	kfree(ds);
+	return res;
 }
 
 int vfat_lookup(struct inode *dir,const char *name,int len,
@@ -1051,10 +1122,10 @@
 	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->i_dirt = 1;
 	memcpy(de->name,name,MSDOS_NAME);
-	memset(de->unused, 0, sizeof(de->unused));
 	de->lcase = 0;
 	de->attr = ATTR_DIR;
 	de->start = 0;
+	de->starthi = 0;
 	fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
 	de->ctime_ms = 0;
 	de->ctime = de->time;
@@ -1069,10 +1140,12 @@
 	if (isdot) {
 		dot->i_size = dir->i_size;
 		MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
+		MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
 		dot->i_nlink = dir->i_nlink;
 	} else {
 		dot->i_size = parent->i_size;
 		MSDOS_I(dot)->i_start = MSDOS_I(parent)->i_start;
+		MSDOS_I(dot)->i_logstart = MSDOS_I(parent)->i_logstart;
 		dot->i_nlink = parent->i_nlink;
 	}
 
@@ -1261,10 +1334,8 @@
 		if (res > 0) {
 			res = 0;
 		}
-	} else {
-		printk("Problem in vfat_rmdirx\n");
+		dir->i_version = ++event;
 	}
-	dir->i_version = ++event;
 
 rmdir_done:
 	fat_brelse(sb, bh);
@@ -1294,19 +1365,15 @@
 	struct slot_info sinfo;
 
 	bh = NULL;
-	if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0)
-		goto unlink_done;
+	res = vfat_find(dir,name,len,1,0,0,&sinfo);
 
 	if (res >= 0 && sinfo.total_slots > 0) {
 		res = vfat_remove_entry(dir,&sinfo,&bh,&de,0,nospc);
 		if (res > 0) {
 			res = 0;
 		}
-	} else {
-		printk("Problem in vfat_unlinkx: res=%d, total_slots=%d\n",res, sinfo.total_slots);
 	}
 
-unlink_done:
 	fat_brelse(sb, bh);
 	return res;
 }
@@ -1350,7 +1417,16 @@
 	return res;
 }
 
+/***** Unlink, as called for uvfatfs */
+int vfat_unlink_uvfat(struct inode *dir,const char *name,int len)
+{
+	int res;
 
+	res = vfat_unlinkx (dir,name,len,0);
+	iput(dir);
+	return res;
+}
+ 
 int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
 	struct inode *new_dir,const char *new_name,int new_len,int must_be_dir)
 {
@@ -1469,6 +1545,7 @@
 	new_de->cdate = old_de->cdate;
 	new_de->adate = old_de->adate;
 	new_de->start = old_de->start;
+	new_de->starthi = old_de->starthi;
 	new_de->size = old_de->size;
 
 	if (!(new_inode = iget(new_dir->i_sb,new_ino))) goto rename_done;
@@ -1518,8 +1595,10 @@
 			res = -EIO;
 			goto rename_done;
 		}
-		dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
-		    MSDOS_I(new_dir)->i_start;
+		MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
+		MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
+		dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
+		dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
 		dotdot_inode->i_dirt = 1;
 		fat_mark_buffer_dirty(sb, dotdot_bh, 1);
 		old_dir->i_nlink--;
@@ -1573,36 +1652,6 @@
 void vfat_read_inode(struct inode *inode)
 {
 	fat_read_inode(inode, &vfat_dir_inode_operations);
-}
-
-
-
-
-static struct file_system_type vfat_fs_type = {
-	vfat_read_super, "vfat", 1, NULL
-};
-
-static struct symbol_table vfat_syms = {
-#include <linux/symtab_begin.h>
-	X(vfat_create),
-	X(vfat_unlink),
-	X(vfat_mkdir),
-	X(vfat_rmdir),
-	X(vfat_rename),
-	X(vfat_put_super),
-	X(vfat_read_super),
-	X(vfat_read_inode),
-	X(vfat_lookup),
-#include <linux/symtab_end.h>
-};                                           
-
-int init_vfat_fs(void)
-{
-	int status;
-
-	if ((status = register_filesystem(&vfat_fs_type)) == 0)
-		status = register_symtab(&vfat_syms);
-	return status;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.0.33/linux/fs/vfat/vfatfs_syms.c linux/fs/vfat/vfatfs_syms.c
--- v2.0.33/linux/fs/vfat/vfatfs_syms.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/vfat/vfatfs_syms.c	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,54 @@
+/*
+ * linux/fs/msdos/vfatfs_syms.c
+ *
+ * Exported kernel symbols for the VFAT filesystem.
+ * These symbols are used by dmsdos.
+ */
+
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/mm.h>
+#include <linux/msdos_fs.h>
+
+struct file_system_type vfat_fs_type = {
+	vfat_read_super, "vfat", 1, NULL
+};
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+#define X(sym) EXPORT_SYMBOL(sym);
+#define X_PUNCT ;
+#else
+#define X_PUNCT ,
+static struct symbol_table vfat_syms = {
+#include <linux/symtab_begin.h>
+#endif
+X(vfat_create) X_PUNCT
+X(vfat_unlink) X_PUNCT
+X(vfat_unlink_uvfat) X_PUNCT
+X(vfat_mkdir) X_PUNCT
+X(vfat_rmdir) X_PUNCT
+X(vfat_rename) X_PUNCT
+X(vfat_put_super) X_PUNCT
+X(vfat_read_super) X_PUNCT
+X(vfat_read_inode) X_PUNCT
+X(vfat_lookup) X_PUNCT
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#include <linux/symtab_end.h>
+};                                           
+#endif
+
+int init_vfat_fs(void)
+{
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+	return register_filesystem(&vfat_fs_type);
+#else
+	int status;
+
+	if ((status = register_filesystem(&vfat_fs_type)) == 0)
+		status = register_symtab(&vfat_syms);
+	return status;
+#endif
+}
+
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/a.out.h linux/include/asm-alpha/a.out.h
--- v2.0.33/linux/include/asm-alpha/a.out.h	Thu Nov  9 00:04:33 1995
+++ linux/include/asm-alpha/a.out.h	Wed Jun  3 15:17:49 1998
@@ -90,7 +90,8 @@
 
 #ifdef __KERNEL__
 
-#define STACK_TOP (0x00120000000UL)
+#define STACK_TOP ((current->personality & ADDR_MAX_32BIT) ? 0x100000000UL : \
+      ((current->personality&ADDR_MAX_31BIT) ? 0x80000000UL : 0x00120000000UL))
 
 #endif
 
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/apecs.h linux/include/asm-alpha/apecs.h
--- v2.0.33/linux/include/asm-alpha/apecs.h	Mon Jul  8 22:08:18 1996
+++ linux/include/asm-alpha/apecs.h	Wed Jun  3 15:17:49 1998
@@ -31,7 +31,7 @@
    BIOS ROMs. So we must put the windows high enough to avoid these areas.
 
    We put window 1 at BUS 64Mb for 64Mb, mapping physical 0 to 64Mb-1,
-   and window 2 at BUS 512Mb for 512Mb, mapping physical 0 to 512Mb-1.
+   and window 2 at BUS 1Gb for 1Gb, mapping physical 0 to 1Gb-1.
    Yes, this does map 0 to 64Mb-1 twice, but only window 1 will actually
    be used for that range (via virt_to_bus()).
 
@@ -53,12 +53,14 @@
    DMAable memory; they count on being able to DMA to any memory they
    get from kmalloc()/get_free_pages(). They will also use window 1 for
    any physical memory accesses below 64Mb; the rest will be handled by
-   window 2, maxing out at 512Mb of memory. I trust this is enough... :-)
+   window 2, maxing out at 1Gb of memory. I trust this is enough... :-)
 
-   Finally, the reason we make window 2 start at 512Mb for 512Mb, is so that
-   we can allocate PCI bus devices' memory starting at 1Gb and up, to ensure
-   that no conflicts occur and bookkeeping is simplified (ie we don't
-   try to fill the gap between the two windows, we just go above the top).
+   We hope that the area before the first window is large enough so that
+   there will be no overlap at the top end (64Mb). We *must* locate the
+   PCI cards' memory just below window 1, so that there's still the
+   possibility of being able to access it via SPARSE space. This is
+   important for cards such as the Matrox Millennium, whose Xserver
+   wants to access memory-mapped registers in byte and short lengths.
 
    Note that the XL is treated differently from the AVANTI, even though
    for most other things they are identical. It didn't seem reasonable to
@@ -69,14 +71,24 @@
 #define APECS_XL_DMA_WIN1_BASE		(64*1024*1024)
 #define APECS_XL_DMA_WIN1_SIZE		(64*1024*1024)
 #define APECS_XL_DMA_WIN1_SIZE_PARANOID	(48*1024*1024)
-#define APECS_XL_DMA_WIN2_BASE		(512*1024*1024)
-#define APECS_XL_DMA_WIN2_SIZE		(512*1024*1024)
+#define APECS_XL_DMA_WIN2_BASE		(1024*1024*1024)
+#define APECS_XL_DMA_WIN2_SIZE		(1024*1024*1024)
 
 #else /* CONFIG_ALPHA_XL */
 
 /* these are for normal APECS family machines, AVANTI/MUSTANG/EB64/PC64 */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define APECS_DMA_WIN_BASE_DEFAULT	(1024*1024*1024)
+#define APECS_DMA_WIN_SIZE_DEFAULT	(1024*1024*1024)
+
+extern unsigned int APECS_DMA_WIN_BASE;
+extern unsigned int APECS_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
 #define APECS_DMA_WIN_BASE	(1024*1024*1024)
 #define APECS_DMA_WIN_SIZE	(1024*1024*1024)
+#endif /* SRM_SETUP */
 
 #endif /* CONFIG_ALPHA_XL */
 
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/cia.h linux/include/asm-alpha/cia.h
--- v2.0.33/linux/include/asm-alpha/cia.h	Mon Jul 15 01:34:11 1996
+++ linux/include/asm-alpha/cia.h	Wed Jun  3 15:17:49 1998
@@ -74,11 +74,23 @@
 
 #define BYTE_ENABLE_SHIFT 5
 #define TRANSFER_LENGTH_SHIFT 3
-#define MEM_SP1_MASK 0x1fffffff  /* Mem sparse space 1 mask is 29 bits */
 
+#define MEM_R1_MASK 0x1fffffff  /* SPARSE Mem region 1 mask is 29 bits */
+#define MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
+#define MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define CIA_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define CIA_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
 
-#define CIA_DMA_WIN_BASE	(1024UL*1024UL*1024UL)
+extern unsigned int CIA_DMA_WIN_BASE;
+extern unsigned int CIA_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define CIA_DMA_WIN_BASE            (1024*1024*1024)
 #define CIA_DMA_WIN_SIZE	(1024*1024*1024)
+#endif /* SRM_SETUP */
 
 /*
  * 21171-CA Control and Status Registers (p4-1)
@@ -86,6 +98,7 @@
 #define CIA_IOC_CIA_REV               (IDENT_ADDR + 0x8740000080UL)
 #define CIA_IOC_PCI_LAT               (IDENT_ADDR + 0x87400000C0UL)
 #define CIA_IOC_CIA_CTRL              (IDENT_ADDR + 0x8740000100UL)
+#define CIA_IOC_CIA_CNFG              (IDENT_ADDR + 0x8740000140UL)
 #define CIA_IOC_HAE_MEM               (IDENT_ADDR + 0x8740000400UL)
 #define CIA_IOC_HAE_IO                (IDENT_ADDR + 0x8740000440UL)
 #define CIA_IOC_CFG                   (IDENT_ADDR + 0x8740000480UL)
@@ -119,18 +132,25 @@
 #define CIA_IOC_PCI_ERR3              (IDENT_ADDR + 0x8740008880UL)
 
 /*
- * 2117A-CA PCI Address Translation Registers.   I've only defined
- * the first window fully as that's the only one that we're currently using.
- * The other window bases are needed to disable the windows.
+ * 2117A-CA PCI Address Translation Registers.
  */
 #define CIA_IOC_PCI_TBIA              (IDENT_ADDR + 0x8760000100UL)
+
 #define CIA_IOC_PCI_W0_BASE           (IDENT_ADDR + 0x8760000400UL)
 #define CIA_IOC_PCI_W0_MASK           (IDENT_ADDR + 0x8760000440UL)
 #define CIA_IOC_PCI_T0_BASE           (IDENT_ADDR + 0x8760000480UL)
 
 #define CIA_IOC_PCI_W1_BASE           (IDENT_ADDR + 0x8760000500UL)
+#define CIA_IOC_PCI_W1_MASK           (IDENT_ADDR + 0x8760000540UL)
+#define CIA_IOC_PCI_T1_BASE           (IDENT_ADDR + 0x8760000580UL)
+
 #define CIA_IOC_PCI_W2_BASE           (IDENT_ADDR + 0x8760000600UL)
+#define CIA_IOC_PCI_W2_MASK           (IDENT_ADDR + 0x8760000640UL)
+#define CIA_IOC_PCI_T2_BASE           (IDENT_ADDR + 0x8760000680UL)
+
 #define CIA_IOC_PCI_W3_BASE           (IDENT_ADDR + 0x8760000700UL)
+#define CIA_IOC_PCI_W3_MASK           (IDENT_ADDR + 0x8760000740UL)
+#define CIA_IOC_PCI_T3_BASE           (IDENT_ADDR + 0x8760000780UL)
 
 /*
  * 21171-CA System configuration registers (p4-3)
@@ -155,6 +175,8 @@
 #define CIA_CONF		        (IDENT_ADDR + 0x8700000000UL)
 #define CIA_IO				(IDENT_ADDR + 0x8580000000UL)
 #define CIA_SPARSE_MEM			(IDENT_ADDR + 0x8000000000UL)
+#define CIA_SPARSE_MEM_R2		(IDENT_ADDR + 0x8400000000UL)
+#define CIA_SPARSE_MEM_R3		(IDENT_ADDR + 0x8500000000UL)
 #define CIA_DENSE_MEM		        (IDENT_ADDR + 0x8600000000UL)
 
 /*
@@ -296,13 +318,125 @@
  * 
  */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+	unsigned long result, shift, work;
+
+	if ((addr >= cia_sm_base_r1) &&
+	    (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= cia_sm_base_r2) &&
+	    (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+	else
+	if ((addr >= cia_sm_base_r3) &&
+	    (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+	else
+	{
+#if 0
+	  printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return 0x0ffUL;
+	}
+	shift = (addr & 0x3) << 3;
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+	unsigned long result, shift, work;
+
+	if ((addr >= cia_sm_base_r1) &&
+	    (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x08);
+	else
+	if ((addr >= cia_sm_base_r2) &&
+	    (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x08);
+	else
+	if ((addr >= cia_sm_base_r3) &&
+	    (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x08);
+	else
+	{
+#if 0
+	  printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return 0x0ffUL;
+	}
+	shift = (addr & 0x3) << 3;
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+	unsigned long work;
+
+	if ((addr >= cia_sm_base_r1) &&
+	    (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= cia_sm_base_r2) &&
+	    (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+	else
+	if ((addr >= cia_sm_base_r3) &&
+	    (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+	else
+	{
+#if 0
+	  printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return;
+	}
+	*(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+	unsigned long work;
+
+	if ((addr >= cia_sm_base_r1) &&
+	    (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= cia_sm_base_r2) &&
+	    (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+	else
+	if ((addr >= cia_sm_base_r3) &&
+	    (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+	else
+	{
+#if 0
+	  printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return;
+	}
+	*(vuip) work = b * 0x00010001;
+}
+
+#else /* SRM_SETUP */
+
 extern inline unsigned long __readb(unsigned long addr)
 {
 	unsigned long result, shift, msb;
 
 	shift = (addr & 0x3) * 8 ;
 	msb = addr & 0xE0000000 ;
-	addr &= MEM_SP1_MASK ;
+	addr &= MEM_R1_MASK ;
 	if (msb != hae.cache) {
 	  set_hae(msb);
 	}
@@ -317,7 +451,7 @@
 
 	shift = (addr & 0x3) * 8;
 	msb = addr & 0xE0000000 ;
-	addr &= MEM_SP1_MASK ;
+	addr &= MEM_R1_MASK ;
 	if (msb != hae.cache) {
 	  set_hae(msb);
 	}
@@ -326,17 +460,12 @@
 	return 0xffffUL & result;
 }
 
-extern inline unsigned long __readl(unsigned long addr)
-{
-	return *(vuip) (addr + CIA_DENSE_MEM);
-}
-
 extern inline void __writeb(unsigned char b, unsigned long addr)
 {
         unsigned long msb ; 
 
 	msb = addr & 0xE0000000 ;
-	addr &= MEM_SP1_MASK ;
+	addr &= MEM_R1_MASK ;
 	if (msb != hae.cache) {
 	  set_hae(msb);
 	}
@@ -348,13 +477,20 @@
         unsigned long msb ; 
 
 	msb = addr & 0xE0000000 ;
-	addr &= MEM_SP1_MASK ;
+	addr &= MEM_R1_MASK ;
 	if (msb != hae.cache) {
 	  set_hae(msb);
 	}
 	*(vuip) ((addr << 5) + CIA_SPARSE_MEM + 0x08) = b * 0x00010001;
 }
 
+#endif /* SRM_SETUP */
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+	return *(vuip) (addr + CIA_DENSE_MEM);
+}
+
 extern inline void __writel(unsigned int b, unsigned long addr)
 {
 	*(vuip) (addr + CIA_DENSE_MEM) = b;
@@ -379,48 +515,73 @@
 /*
  * Data structure for handling CIA machine checks:
  */
+/* ev5-specific info: */
+struct el_procdata {
+	unsigned long shadow[8];	/* PALmode shadow registers */
+	unsigned long paltemp[24];	/* PAL temporary registers */
+	/* EV5-specific fields */
+	unsigned long exc_addr;		/* Address of excepting instruction. */
+	unsigned long exc_sum;		/* Summary of arithmetic traps. */
+	unsigned long exc_mask;		/* Exception mask (from exc_sum). */
+	unsigned long exc_base;		/* PALbase at time of exception. */
+	unsigned long isr;		/* Interrupt summary register. */
+	unsigned long icsr;		/* Ibox control register. */
+	unsigned long ic_perr_stat;
+	unsigned long dc_perr_stat;
+	unsigned long va;		/* Effective VA of fault or miss. */
+	unsigned long mm_stat;
+	unsigned long sc_addr;
+	unsigned long sc_stat;
+	unsigned long bc_tag_addr;
+	unsigned long ei_addr;
+	unsigned long fill_syn;
+	unsigned long ei_stat;
+	unsigned long ld_lock;
+};
+
+/* system-specific info: */
 struct el_CIA_sysdata_mcheck {
-    u_long      coma_gcr;                       
-    u_long      coma_edsr;                      
-    u_long      coma_ter;                       
-    u_long      coma_elar;                      
-    u_long      coma_ehar;                      
-    u_long      coma_ldlr;                      
-    u_long      coma_ldhr;                      
-    u_long      coma_base0;                     
-    u_long      coma_base1;                     
-    u_long      coma_base2;                     
-    u_long      coma_cnfg0;                     
-    u_long      coma_cnfg1;                     
-    u_long      coma_cnfg2;                     
-    u_long      epic_dcsr;                      
-    u_long      epic_pear;                      
-    u_long      epic_sear;                      
-    u_long      epic_tbr1;                      
-    u_long      epic_tbr2;                      
-    u_long      epic_pbr1;                      
-    u_long      epic_pbr2;                      
-    u_long      epic_pmr1;                      
-    u_long      epic_pmr2;                      
-    u_long      epic_harx1;                     
-    u_long      epic_harx2;                     
-    u_long      epic_pmlt;                      
-    u_long      epic_tag0;                      
-    u_long      epic_tag1;                      
-    u_long      epic_tag2;                      
-    u_long      epic_tag3;                      
-    u_long      epic_tag4;                      
-    u_long      epic_tag5;                      
-    u_long      epic_tag6;                      
-    u_long      epic_tag7;                      
-    u_long      epic_data0;                     
-    u_long      epic_data1;                     
-    u_long      epic_data2;                     
-    u_long      epic_data3;                     
-    u_long      epic_data4;                     
-    u_long      epic_data5;                     
-    u_long      epic_data6;                     
-    u_long      epic_data7;                     
+    unsigned long      coma_gcr;                       
+    unsigned long      coma_edsr;                      
+    unsigned long      coma_ter;                       
+    unsigned long      coma_elar;                      
+    unsigned long      coma_ehar;                      
+    unsigned long      coma_ldlr;                      
+    unsigned long      coma_ldhr;                      
+    unsigned long      coma_base0;                     
+    unsigned long      coma_base1;                     
+    unsigned long      coma_base2;                     
+    unsigned long      coma_cnfg0;                     
+    unsigned long      coma_cnfg1;                     
+    unsigned long      coma_cnfg2;                     
+    unsigned long      epic_dcsr;                      
+    unsigned long      epic_pear;                      
+    unsigned long      epic_sear;                      
+    unsigned long      epic_tbr1;                      
+    unsigned long      epic_tbr2;                      
+    unsigned long      epic_pbr1;                      
+    unsigned long      epic_pbr2;                      
+    unsigned long      epic_pmr1;                      
+    unsigned long      epic_pmr2;                      
+    unsigned long      epic_harx1;                     
+    unsigned long      epic_harx2;                     
+    unsigned long      epic_pmlt;                      
+    unsigned long      epic_tag0;                      
+    unsigned long      epic_tag1;                      
+    unsigned long      epic_tag2;                      
+    unsigned long      epic_tag3;                      
+    unsigned long      epic_tag4;                      
+    unsigned long      epic_tag5;                      
+    unsigned long      epic_tag6;                      
+    unsigned long      epic_tag7;                      
+    unsigned long      epic_data0;                     
+    unsigned long      epic_data1;                     
+    unsigned long      epic_data2;                     
+    unsigned long      epic_data3;                     
+    unsigned long      epic_data4;                     
+    unsigned long      epic_data5;                     
+    unsigned long      epic_data6;                     
+    unsigned long      epic_data7;                     
 };
 
 #define RTC_PORT(x)	(0x70 + (x))
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h
--- v2.0.33/linux/include/asm-alpha/dma.h	Mon Jun  3 20:06:38 1996
+++ linux/include/asm-alpha/dma.h	Wed Jun  3 15:17:49 1998
@@ -75,7 +75,9 @@
 
 #define MAX_DMA_CHANNELS	8
 
-#ifdef CONFIG_ALPHA_XL
+#if defined(CONFIG_ALPHA_RUFFIAN)
+#define MAX_DMA_ADDRESS         (0xfffffc0001000000UL) /* yup, 16Mb :-( */
+#elif defined(CONFIG_ALPHA_XL)
 /* The maximum address that we can perform a DMA transfer to on Alpha XL,
    due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB.
    See <asm/apecs.h> for more info.
@@ -87,11 +89,13 @@
    For now, this limit is set to 48Mb...
 */
 #define MAX_DMA_ADDRESS		(0xfffffc0003000000UL)
-#else /* CONFIG_ALPHA_XL */
-/* The maximum address that we can perform a DMA transfer to on normal
-   Alpha platforms */
+#else
+/*
+ * The maximum address that we can perform a DMA transfer to on
+ * normal Alpha platforms
+ */
 #define MAX_DMA_ADDRESS		(~0UL)
-#endif /* CONFIG_ALPHA_XL */
+#endif
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/floppy.h linux/include/asm-alpha/floppy.h
--- v2.0.33/linux/include/asm-alpha/floppy.h	Sat Mar 30 01:48:51 1996
+++ linux/include/asm-alpha/floppy.h	Wed Jun  3 15:17:49 1998
@@ -51,11 +51,11 @@
 /*
  * Most Alphas have no problems with floppy DMA crossing 64k borders. Sigh...
  */
-#ifdef CONFIG_ALPHA_XL
+#if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN)
 #define CROSS_64KB(a,s) \
     ((unsigned long)(a)/0x10000 != ((unsigned long)(a) + (s) - 1) / 0x10000)
-#else /* CONFIG_ALPHA_XL */
+#else /* XL || RUFFIAN */
 #define CROSS_64KB(a,s) (0)
-#endif /* CONFIG_ALPHA_XL */
+#endif /* XL || RUFFIAN */
 
 #endif /* __ASM_ALPHA_FLOPPY_H */
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h
--- v2.0.33/linux/include/asm-alpha/hwrpb.h	Thu Apr  4 04:56:47 1996
+++ linux/include/asm-alpha/hwrpb.h	Wed Jun  3 15:17:49 1998
@@ -15,6 +15,8 @@
 #define EV45_CPU                6       /* EV4.5 (21064/xxx)    */
 #define EV56_CPU		7	/* EV5.6 (21164)	*/
 #define EV6_CPU			8	/* EV6 (21164)		*/
+#define PCA56_CPU		9	/* PCA56 (21164PC)	*/
+#define PCA57_CPU		10	/* PCA57 (21164??)	*/
 
 /*
  * DEC system types for Alpha systems.  Found in HWRPB.
@@ -32,14 +34,30 @@
 #define ST_DEC_AXPPCI_33	 11	/* NoName system type	*/
 #define ST_DEC_TLASER		 12	/* Turbolaser systype	*/
 #define ST_DEC_2100_A50		 13	/* Avanti systype	*/
-#define ST_DEC_MUSTANG		 14	/* Mustang systype	*/
 #define ST_DEC_ALCOR		 15	/* Alcor (EV5) systype	*/
 #define ST_DEC_1000		 17	/* Mikasa systype	*/
+#define ST_DEC_EB64		 18	/* EB64 systype		*/
 #define ST_DEC_EB66		 19	/* EB66 systype		*/
 #define ST_DEC_EB64P		 20	/* EB64+ systype	*/
-#define ST_DEC_EB66P		-19	/* EB66 systype		*/
-#define ST_DEC_EBPC64		-20	/* Cabriolet (AlphaPC64) systype */
+#define ST_DEC_BURNS		 21	/* laptop systype	*/
+#define ST_DEC_RAWHIDE		 22	/* Rawhide systype	*/
+#define ST_DEC_K2		 23	/* K2 systype		*/
+#define ST_DEC_LYNX		 24	/* Lynx systype		*/
+#define ST_DEC_XL		 25	/* Alpha XL systype	*/
 #define ST_DEC_EB164		 26	/* EB164 systype	*/
+#define ST_DEC_NORITAKE		 27	/* Noritake systype	*/
+#define ST_DEC_CORTEX		 28	/* Cortex systype	*/
+#define ST_DEC_MIATA		 30	/* Miata systype        */
+#define ST_DEC_XXM		 31	/* XXM systype		*/
+#define ST_DEC_TAKARA		 32	/* Takara systype	*/
+#define ST_DEC_YUKON		 33	/* Yukon systype	*/
+#define ST_DEC_TSUNAMI		 34	/* Tsunami systype	*/
+#define ST_DEC_WILDFIRE		 35	/* Wildfire systype	*/
+#define ST_DEC_CUSCO		 36	/* CUSCO systype	*/
+
+/* UNOFFICIAL!!! */
+#define ST_UNOFFICIAL_BIAS	100
+#define ST_DTI_RUFFIAN		101	/* RUFFIAN systype	*/
 
 struct pcb_struct {
 	unsigned long ksp;
@@ -118,6 +136,12 @@
 	struct memclust_struct cluster[0];
 };
 
+struct dsr_struct {
+	long smm;                       /* SMM nubber used by LMF       */
+	unsigned long  lurt_off;        /* offset to LURT table         */
+	unsigned long  sysname_off;     /* offset to sysname char count */
+};
+
 struct hwrpb_struct {
 	unsigned long phys_addr;	/* check: physical address of the hwrpb */
 	unsigned long id;		/* check: "HWRPB\0\0\0" */
@@ -157,7 +181,7 @@
 	unsigned long chksum;
 	unsigned long rxrdy;
 	unsigned long txrdy;
-	unsigned long dsrdbt_offset;	/* "Dynamic System Recognition Data Block Table" Whee */
+	unsigned long dsr_offset;	/* "Dynamic System Recognition Data Block Table" */
 };
 
 #endif
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.0.33/linux/include/asm-alpha/io.h	Mon Jun  3 20:06:38 1996
+++ linux/include/asm-alpha/io.h	Wed Jun  3 15:17:49 1998
@@ -25,7 +25,11 @@
 /*
  * Virtual -> physical identity mapping starts at this offset
  */
+#ifdef USE_48_BIT_KSEG
+#define IDENT_ADDR	(0xffff800000000000UL)
+#else
 #define IDENT_ADDR	(0xfffffc0000000000UL)
+#endif
 
 #ifdef __KERNEL__
 
@@ -42,6 +46,7 @@
 	hae.cache = new_hae;
 	*hae.reg = new_hae;
 	mb();
+	new_hae = *hae.reg; /* read to make sure it was written */
 	setipl(ipl);
 }
 
@@ -79,6 +84,10 @@
 # include <asm/apecs.h>		/* get chip-specific definitions */
 #elif defined(CONFIG_ALPHA_CIA)
 # include <asm/cia.h>		/* get chip-specific definitions */
+#elif defined(CONFIG_ALPHA_T2)
+# include <asm/t2.h>		/* get chip-specific definitions */
+#elif defined(CONFIG_ALPHA_PYXIS)
+# include <asm/pyxis.h>		/* get chip-specific definitions */
 #else
 # include <asm/jensen.h>
 #endif
@@ -150,9 +159,21 @@
 #endif
 
 /*
- * The "address" in IO memory space is not clearly either a integer or a
+ * The "address" in IO memory space is not clearly either an integer or a
  * pointer. We will accept both, thus the casts.
+ *
+ * On the alpha, we have the whole physical address space mapped at all
+ * times, so "ioremap()" and "iounmap()" do not need to do anything.
  */
+extern inline void * ioremap(unsigned long offset, unsigned long size)
+{
+	return (void *) offset;
+} 
+
+extern inline void iounmap(void *addr)
+{
+}
+
 #ifndef readb
 # define readb(a)	_readb((unsigned long)(a))
 #endif
@@ -202,6 +223,22 @@
  */
 
 #define eth_io_copy_and_sum(skb,src,len,unused)	memcpy_fromio((skb)->data,(src),(len))
+
+static inline int check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/irq.h linux/include/asm-alpha/irq.h
--- v2.0.33/linux/include/asm-alpha/irq.h	Sun Jul 14 23:47:42 1996
+++ linux/include/asm-alpha/irq.h	Wed Jun  3 15:17:49 1998
@@ -10,14 +10,41 @@
 #include <linux/linkage.h>
 #include <linux/config.h>
 
-#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164)
-# define NR_IRQS	33
-#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || defined(CONFIG_ALPHA_MIKASA)
+#if   defined(CONFIG_ALPHA_CABRIOLET) || \
+      defined(CONFIG_ALPHA_EB66P)     || \
+      defined(CONFIG_ALPHA_EB164)     || \
+      defined(CONFIG_ALPHA_PC164)     || \
+      defined(CONFIG_ALPHA_LX164)
+
+# define NR_IRQS	35
+
+#elif defined(CONFIG_ALPHA_EB66)      || \
+      defined(CONFIG_ALPHA_EB64P)     || \
+      defined(CONFIG_ALPHA_MIKASA)
+
 # define NR_IRQS	32
-#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+
+#elif defined(CONFIG_ALPHA_ALCOR)     || \
+      defined(CONFIG_ALPHA_XLT)       || \
+      defined(CONFIG_ALPHA_MIATA)     || \
+      defined(CONFIG_ALPHA_RUFFIAN)   || \
+      defined(CONFIG_ALPHA_NORITAKE)
+
 # define NR_IRQS	48
-#else
+
+#elif defined(CONFIG_ALPHA_SABLE)     || \
+      defined(CONFIG_ALPHA_SX164)
+
+# define NR_IRQS	40
+
+#elif defined(CONFIG_ALPHA_TAKARA)
+
+# define NR_IRQS	20
+
+#else /* everyone else */
+
 # define NR_IRQS	16
+
 #endif
 
 
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/lca.h linux/include/asm-alpha/lca.h
--- v2.0.33/linux/include/asm-alpha/lca.h	Thu Apr 11 23:49:44 1996
+++ linux/include/asm-alpha/lca.h	Wed Jun  3 15:17:49 1998
@@ -54,8 +54,18 @@
 
 #include <asm/system.h>
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define LCA_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define LCA_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int LCA_DMA_WIN_BASE;
+extern unsigned int LCA_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
 #define LCA_DMA_WIN_BASE	(1024*1024*1024)
 #define LCA_DMA_WIN_SIZE	(1024*1024*1024)
+#endif /* SRM_SETUP */
 
 /*
  * Memory Controller registers:
@@ -130,6 +140,37 @@
 
 #define HAE_ADDRESS	LCA_IOC_HAE
 
+/* LCA PMR Power Management register defines */
+#define LCA_PMR_ADDR	(IDENT_ADDR + 0x120000098UL)
+#define LCA_PMR_PDIV    0x7                     /* Primary clock divisor */
+#define LCA_PMR_ODIV    0x38                    /* Override clock divisor */
+#define LCA_PMR_INTO    0x40                    /* Interrupt override */
+#define LCA_PMR_DMAO    0x80                    /* DMA override */
+#define LCA_PMR_OCCEB   0xffff0000L             /* Override cycle counter - even
+ bits */
+#define LCA_PMR_OCCOB   0xffff000000000000L     /* Override cycle counter - even
+ bits */
+#define LCA_PMR_PRIMARY_MASK    0xfffffffffffffff8
+/* LCA PMR Macros */
+
+#define READ_PMR        (*(volatile unsigned long *)LCA_PMR_ADDR)
+#define WRITE_PMR(d)    (*((volatile unsigned long *)LCA_PMR_ADDR) = (d))
+
+#define GET_PRIMARY(r)  ((r) & LCA_PMR_PDIV)
+#define GET_OVERRIDE(r) (((r) >> 3) & LCA_PMR_PDIV)
+#define SET_PRIMARY_CLOCK(r, c) ((r) = (((r) & LCA_PMR_PRIMARY_MASK) | (c)))
+
+/* LCA PMR Divisor values */
+#define DIV_1   0x0
+#define DIV_1_5 0x1
+#define DIV_2   0x2
+#define DIV_4   0x3
+#define DIV_8   0x4
+#define DIV_16  0x5
+#define DIV_MIN DIV_1
+#define DIV_MAX DIV_16
+
+
 #ifdef __KERNEL__
 
 /*
@@ -317,7 +358,6 @@
  */
 struct el_lca_mcheck_short {
 	struct el_common	h;		/* common logout header */
-	unsigned long		reason;		/* reason for machine check */
 	unsigned long		esr;		/* error-status register */
 	unsigned long		ear;		/* error-address register */
 	unsigned long		dc_stat;	/* dcache status register */
@@ -327,7 +367,7 @@
 
 struct el_lca_mcheck_long {
 	struct el_common	h;		/* common logout header */
-	unsigned long		pt[32];		/* PAL temps (pt[0] is reason) */
+	unsigned long		pt[31];		/* PAL temps */
 	unsigned long		exc_addr;	/* exception address */
 	unsigned long		pad1[3];
 	unsigned long		pal_base;	/* PALcode base address */
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/pal.h linux/include/asm-alpha/pal.h
--- v2.0.33/linux/include/asm-alpha/pal.h	Mon Jun 26 01:06:53 1995
+++ linux/include/asm-alpha/pal.h	Wed Jun  3 15:17:49 1998
@@ -7,7 +7,6 @@
 #define PAL_halt	  0
 #define PAL_cflush	  1
 #define PAL_draina	  2
-#define PAL_cobratt	  9
 #define PAL_bpt		128
 #define PAL_bugchk	129
 #define PAL_chmk	131
@@ -27,6 +26,8 @@
 /*
  * OSF specific PAL-code
  */
+#define PAL_cserve	 9
+#define PAL_wripir	13
 #define PAL_rdmces	16
 #define PAL_wrmces	17
 #define PAL_wrfen	43
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.0.33/linux/include/asm-alpha/processor.h	Sun Aug  3 10:58:38 1997
+++ linux/include/asm-alpha/processor.h	Wed Jun  3 15:17:49 1998
@@ -8,9 +8,17 @@
 #define __ASM_ALPHA_PROCESSOR_H
 
 /*
- * We have a 41-bit user address space: 2TB user VM...
+ * We have a 41-bit user address space: 2TB user VM.
+ * Under certain circumstances (e.g. when emulating 32-bit code)
+ * we may want to voluntarily limit this...
  */
 #define TASK_SIZE (0x40000000000UL)
+#define MAX_USER_ADDR ((current->personality&ADDR_MAX_32BIT) ? 0x100000000UL : \
+	((current->personality & ADDR_MAX_31BIT) ? 0x80000000UL : \
+							0x40000000000UL))
+#define MMAP_SEARCH_START ((current->personality & ADDR_MAX_31BIT) ? \
+			(MAX_USER_ADDR/2) : (MAX_USER_ADDR/3))
+
 
 /*
  * Bus types
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/ptrace.h linux/include/asm-alpha/ptrace.h
--- v2.0.33/linux/include/asm-alpha/ptrace.h	Thu Dec 21 22:22:06 1995
+++ linux/include/asm-alpha/ptrace.h	Wed Jun  3 15:17:49 1998
@@ -37,6 +37,10 @@
 	unsigned long r27;
 	unsigned long r28;
 	unsigned long hae;
+/* JRP - These are the values provided to a0-a2 by PALcode */
+	unsigned long trap_a0;
+	unsigned long trap_a1;
+	unsigned long trap_a2;
 /* These are saved by PAL-code: */
 	unsigned long ps;
 	unsigned long pc;
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/pyxis.h linux/include/asm-alpha/pyxis.h
--- v2.0.33/linux/include/asm-alpha/pyxis.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/pyxis.h	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,742 @@
+#ifndef __ALPHA_PYXIS__H__
+#define __ALPHA_PYXIS__H__
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/*
+ * PYXIS is the internal name for a core logic chipset which provides
+ * memory controller and PCI access for the 21164A chip based systems.
+ *
+ * This file is based on:
+ *
+ * Pyxis Chipset Spec
+ * 14-Jun-96
+ * Rev. X2.0
+ *
+ */
+
+/*------------------------------------------------------------------------**
+**                                                                        **
+**  I/O procedures                                                   **
+**                                                                        **
+**      inport[b|w|t|l], outport[b|w|t|l] 8:16:24:32 IO xfers             **
+**	inportbxt: 8 bits only                                            **
+**      inport:    alias of inportw                                       **
+**      outport:   alias of outportw                                      **
+**                                                                        **
+**      inmem[b|w|t|l], outmem[b|w|t|l] 8:16:24:32 ISA memory xfers       **
+**	inmembxt: 8 bits only                                             **
+**      inmem:    alias of inmemw                                         **
+**      outmem:   alias of outmemw                                        **
+**                                                                        **
+**------------------------------------------------------------------------*/
+
+
+/* CIA ADDRESS BIT DEFINITIONS
+ *
+ *  3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |1| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
+ *  |                                                                        \_/ \_/
+ *  |                                                                         |   |
+ *  +-- IO space, not cached.                                   Byte Enable --+   |
+ *                                                              Transfer Length --+
+ *
+ *
+ *
+ *   Byte      Transfer
+ *   Enable    Length    Transfer  Byte    Address
+ *   adr<6:5>  adr<4:3>  Length    Enable  Adder
+ *   ---------------------------------------------
+ *      00        00      Byte      1110   0x000
+ *      01        00      Byte      1101   0x020
+ *      10        00      Byte      1011   0x040
+ *      11        00      Byte      0111   0x060
+ *
+ *      00        01      Word      1100   0x008
+ *      01        01      Word      1001   0x028 <= Not supported in this code.
+ *      10        01      Word      0011   0x048
+ *
+ *      00        10      Tribyte   1000   0x010
+ *      01        10      Tribyte   0001   0x030
+ *
+ *      10        11      Longword  0000   0x058
+ *
+ *      Note that byte enables are asserted low.
+ *
+ */
+
+#define BYTE_ENABLE_SHIFT 5
+#define TRANSFER_LENGTH_SHIFT 3
+
+#define MEM_R1_MASK 0x1fffffff  /* SPARSE Mem region 1 mask is 29 bits */
+#define MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
+#define MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define PYXIS_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define PYXIS_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int PYXIS_DMA_WIN_BASE;
+extern unsigned int PYXIS_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define PYXIS_DMA_WIN_BASE	(1024*1024*1024)
+#define PYXIS_DMA_WIN_SIZE	(1024*1024*1024)
+#endif /* SRM_SETUP */
+
+/*
+ *  General Registers
+ */
+#define PYXIS_REV			(IDENT_ADDR + 0x8740000080UL)
+#define PYXIS_PCI_LAT			(IDENT_ADDR + 0x87400000C0UL)
+#define PYXIS_CTRL			(IDENT_ADDR + 0x8740000100UL)
+#define PYXIS_CTRL1			(IDENT_ADDR + 0x8740000140UL)
+#define PYXIS_FLASH_CTRL		(IDENT_ADDR + 0x8740000200UL)
+
+#define PYXIS_HAE_MEM			(IDENT_ADDR + 0x8740000400UL)
+#define PYXIS_HAE_IO			(IDENT_ADDR + 0x8740000440UL)
+#define PYXIS_CFG			(IDENT_ADDR + 0x8740000480UL)
+
+/*
+ * Diagnostic Registers
+ */
+#define PYXIS_DIAG			(IDENT_ADDR + 0x8740002000UL)
+#define PYXIS_DIAG_CHECK		(IDENT_ADDR + 0x8740003000UL)
+
+/*
+ * Performance Monitor registers
+ */
+#define PYXIS_PERF_MONITOR		(IDENT_ADDR + 0x8740004000UL)
+#define PYXIS_PERF_CONTROL		(IDENT_ADDR + 0x8740004040UL)
+
+/*
+ * Error registers
+ */
+#define PYXIS_ERR			(IDENT_ADDR + 0x8740008200UL)
+#define PYXIS_STAT			(IDENT_ADDR + 0x8740008240UL)
+#define PYXIS_ERR_MASK			(IDENT_ADDR + 0x8740008280UL)
+#define PYXIS_SYN			(IDENT_ADDR + 0x8740008300UL)
+#define PYXIS_ERR_DATA			(IDENT_ADDR + 0x8740008308UL)
+
+#define PYXIS_MEAR			(IDENT_ADDR + 0x8740008400UL)
+#define PYXIS_MESR			(IDENT_ADDR + 0x8740008440UL)
+#define PYXIS_PCI_ERR0			(IDENT_ADDR + 0x8740008800UL)
+#define PYXIS_PCI_ERR1			(IDENT_ADDR + 0x8740008840UL)
+#define PYXIS_PCI_ERR2			(IDENT_ADDR + 0x8740008880UL)
+
+/*
+ * PCI Address Translation Registers.
+ */
+#define PYXIS_TBIA			(IDENT_ADDR + 0x8760000100UL)
+
+#define PYXIS_W0_BASE			(IDENT_ADDR + 0x8760000400UL)
+#define PYXIS_W0_MASK			(IDENT_ADDR + 0x8760000440UL)
+#define PYXIS_T0_BASE			(IDENT_ADDR + 0x8760000480UL)
+
+#define PYXIS_W1_BASE			(IDENT_ADDR + 0x8760000500UL)
+#define PYXIS_W1_MASK			(IDENT_ADDR + 0x8760000540UL)
+#define PYXIS_T1_BASE			(IDENT_ADDR + 0x8760000580UL)
+
+#define PYXIS_W2_BASE			(IDENT_ADDR + 0x8760000600UL)
+#define PYXIS_W2_MASK			(IDENT_ADDR + 0x8760000640UL)
+#define PYXIS_T2_BASE			(IDENT_ADDR + 0x8760000680UL)
+
+#define PYXIS_W3_BASE			(IDENT_ADDR + 0x8760000700UL)
+#define PYXIS_W3_MASK			(IDENT_ADDR + 0x8760000740UL)
+#define PYXIS_T3_BASE			(IDENT_ADDR + 0x8760000780UL)
+
+/*
+ * Memory Control registers
+ */
+#define PYXIS_MCR			(IDENT_ADDR + 0x8750000000UL)
+
+/*
+ * Memory spaces:
+ */
+#define PYXIS_IACK_SC		        (IDENT_ADDR + 0x8720000000UL)
+#define PYXIS_CONF		        (IDENT_ADDR + 0x8700000000UL)
+#define PYXIS_IO			(IDENT_ADDR + 0x8580000000UL)
+#define PYXIS_SPARSE_MEM		(IDENT_ADDR + 0x8000000000UL)
+#define PYXIS_SPARSE_MEM_R2		(IDENT_ADDR + 0x8400000000UL)
+#define PYXIS_SPARSE_MEM_R3		(IDENT_ADDR + 0x8500000000UL)
+#define PYXIS_DENSE_MEM		        (IDENT_ADDR + 0x8600000000UL)
+
+/*
+ * Byte/Word PCI Memory Spaces:
+ */
+#define PYXIS_BW_MEM			(IDENT_ADDR + 0x8800000000UL)
+#define PYXIS_BW_IO			(IDENT_ADDR + 0x8900000000UL)
+#define PYXIS_BW_CFG_0			(IDENT_ADDR + 0x8a00000000UL)
+#define PYXIS_BW_CFG_1			(IDENT_ADDR + 0x8b00000000UL)
+
+/*
+ * Interrupt Control registers
+ */
+#define PYXIS_INT_REQ			(IDENT_ADDR + 0x87A0000000UL)
+#define PYXIS_INT_MASK			(IDENT_ADDR + 0x87A0000040UL)
+#define PYXIS_INT_HILO			(IDENT_ADDR + 0x87A00000C0UL)
+#define PYXIS_INT_ROUTE			(IDENT_ADDR + 0x87A0000140UL)
+#define PYXIS_GPO			(IDENT_ADDR + 0x87A0000180UL)
+#define PYXIS_INT_CNFG			(IDENT_ADDR + 0x87A00001C0UL)
+#define PYXIS_RT_COUNT			(IDENT_ADDR + 0x87A0000200UL)
+#define PYXIS_INT_TIME			(IDENT_ADDR + 0x87A0000240UL)
+#define PYXIS_IIC_CTRL			(IDENT_ADDR + 0x87A00002C0UL)
+
+/*
+ * Bit definitions for I/O Controller status register 0:
+ */
+#define PYXIS_STAT0_CMD			0xf
+#define PYXIS_STAT0_ERR			(1<<4)
+#define PYXIS_STAT0_LOST		(1<<5)
+#define PYXIS_STAT0_THIT		(1<<6)
+#define PYXIS_STAT0_TREF		(1<<7)
+#define PYXIS_STAT0_CODE_SHIFT		8
+#define PYXIS_STAT0_CODE_MASK		0x7
+#define PYXIS_STAT0_P_NBR_SHIFT		13
+#define PYXIS_STAT0_P_NBR_MASK		0x7ffff
+
+#define HAE_ADDRESS	                PYXIS_HAE_MEM
+
+#ifdef __KERNEL__
+
+/*
+ * Translate physical memory address as seen on (PCI) bus into
+ * a kernel virtual address and vv.
+ */
+#if defined(CONFIG_ALPHA_RUFFIAN)
+#if 0
+/* Ruffian doesn't do 1G PCI window */
+extern inline unsigned long virt_to_bus(void * address)
+{
+	return virt_to_phys(address);
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+	return phys_to_virt(address);
+}
+#else
+/* Oh, yes, it does (at least with the latest FW) */
+extern inline unsigned long virt_to_bus(void * address)
+{
+	return virt_to_phys(address) + PYXIS_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+	return phys_to_virt(address - PYXIS_DMA_WIN_BASE);
+}
+#endif
+#else /* RUFFIAN */
+extern inline unsigned long virt_to_bus(void * address)
+{
+	return virt_to_phys(address) + PYXIS_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+	return phys_to_virt(address - PYXIS_DMA_WIN_BASE);
+}
+#endif /* RUFFIAN */
+
+/*
+ * I/O functions:
+ *
+ * PYXIS, the 21174 PCI/memory support chipset for the EV56 (21164)
+ * and PCA56 (21164PC) processors, can use either a sparse address
+ * mapping scheme, or the so-called byte-word PCI address space, to
+ * get at PCI memory and I/O.
+ */
+
+#define vuip	volatile unsigned int *
+
+#if defined(BWIO_ENABLED)
+# if defined(CONFIG_ALPHA_LX164) || \
+     defined(CONFIG_ALPHA_SX164)
+/* only for the above platforms can we be sure this will work */
+#  define BWIO_REALLY_ENABLED
+# else
+#  undef BWIO_REALLY_ENABLED
+# endif
+#else
+# undef BWIO_REALLY_ENABLED
+#endif
+
+#ifdef BWIO_REALLY_ENABLED
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+	register unsigned long result;
+
+	__asm__ __volatile__ (
+		 "ldbu %0,%1"
+		 : "=r" (result)
+		 : "m"  (*(unsigned char *)(addr+PYXIS_BW_IO)));
+
+	return result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+	__asm__ __volatile__ (
+		 "stb %1,%0\n\t"
+		 "mb"
+		 : : "m" (*(unsigned char *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+	register unsigned long result;
+
+	__asm__ __volatile__ (
+		 "ldwu %0,%1"
+		 : "=r" (result)
+		 : "m"  (*(unsigned short *)(addr+PYXIS_BW_IO)));
+
+	return result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+	__asm__ __volatile__ (
+		 "stw %1,%0\n\t"
+		 "mb"
+		 : : "m" (*(unsigned short *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+	register unsigned long result;
+
+	__asm__ __volatile__ (
+		 "ldl %0,%1"
+		 : "=r" (result)
+		 : "m"  (*(unsigned int *)(addr+PYXIS_BW_IO)));
+
+	return result;
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+	__asm__ __volatile__ (
+		 "stl %1,%0\n\t"
+		 "mb"
+		 : : "m" (*(unsigned int *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+#define inb(port) __inb((port))
+#define inw(port) __inw((port))
+#define inl(port) __inl((port))
+
+#define outb(x, port) __outb((x),(port))
+#define outw(x, port) __outw((x),(port))
+#define outl(x, port) __outl((x),(port))
+
+#else /* BWIO_REALLY_ENABLED */
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+	long result = *(vuip) ((addr << 5) + PYXIS_IO + 0x00);
+	result >>= (addr & 3) * 8;
+	return 0xffUL & result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+	unsigned int w;
+
+	asm ("insbl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+	*(vuip) ((addr << 5) + PYXIS_IO + 0x00) = w;
+	mb();
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+	long result = *(vuip) ((addr << 5) + PYXIS_IO + 0x08);
+	result >>= (addr & 3) * 8;
+	return 0xffffUL & result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+	unsigned int w;
+
+	asm ("inswl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+	*(vuip) ((addr << 5) + PYXIS_IO + 0x08) = w;
+	mb();
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+	return *(vuip) ((addr << 5) + PYXIS_IO + 0x18);
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+	*(vuip) ((addr << 5) + PYXIS_IO + 0x18) = b;
+	mb();
+}
+
+#define inb(port) \
+(__builtin_constant_p((port))?__inb(port):_inb(port))
+
+#define outb(x, port) \
+(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
+
+#endif /* BWIO_REALLY_ENABLED */
+
+
+/*
+ * Memory functions.  64-bit and 32-bit accesses are done through
+ * dense memory space, everything else through sparse space.
+ * 
+ * For reading and writing 8 and 16 bit quantities we need to 
+ * go through one of the three sparse address mapping regions
+ * and use the HAE_MEM CSR to provide some bits of the address.
+ * The following few routines use only sparse address region 1
+ * which gives 1Gbyte of accessible space which relates exactly
+ * to the amount of PCI memory mapping *into* system address space.
+ * See p 6-17 of the specification but it looks something like this:
+ *
+ * 21164 Address:
+ * 
+ *          3         2         1
+ * 9876543210987654321098765432109876543210
+ * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ *
+ * ZZ = SBZ
+ * BB = Byte offset
+ * LL = Transfer length
+ *
+ * PCI Address:
+ *
+ * 3         2         1
+ * 10987654321098765432109876543210
+ * HHH....PCI.QW.Address........ 00
+ *
+ * HHH = 31:29 HAE_MEM CSR
+ * 
+ */
+
+#ifdef BWIO_REALLY_ENABLED
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+	register unsigned long result;
+
+	__asm__ __volatile__ (
+		 "ldbu %0,%1"
+		 : "=r" (result)
+		 : "m"  (*(unsigned char *)(addr+PYXIS_BW_MEM)));
+
+	return result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+	register unsigned long result;
+
+	__asm__ __volatile__ (
+		 "ldwu %0,%1"
+		 : "=r" (result)
+		 : "m"  (*(unsigned short *)(addr+PYXIS_BW_MEM)));
+
+	return result;
+}
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+	register unsigned long result;
+
+	__asm__ __volatile__ (
+		 "ldl %0,%1"
+		 : "=r" (result)
+		 : "m"  (*(unsigned int *)(addr+PYXIS_BW_MEM)));
+
+	return result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+	__asm__ __volatile__ (
+		 "stb %1,%0\n\t"
+		 "mb"
+		 : : "m" (*(unsigned char *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+	__asm__ __volatile__ (
+		 "stw %1,%0\n\t"
+		 "mb"
+		 : : "m" (*(unsigned short *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+	__asm__ __volatile__ (
+		 "stl %1,%0\n\t"
+		 "mb"
+		 : : "m" (*(unsigned int *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+#define readb(addr) __readb((addr))
+#define readw(addr) __readw((addr))
+
+#define writeb(b, addr) __writeb((b),(addr))
+#define writew(b, addr) __writew((b),(addr))
+
+#else /* BWIO_REALLY_ENABLED */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+	unsigned long result, shift, work;
+
+	if ((addr >= pyxis_sm_base_r1) &&
+	    (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= pyxis_sm_base_r2) &&
+	    (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+	else
+	if ((addr >= pyxis_sm_base_r3) &&
+	    (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+	else
+	{
+#if 0
+	  printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return 0x0ffUL;
+	}
+	shift = (addr & 0x3) << 3;
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+	unsigned long result, shift, work;
+
+	if ((addr >= pyxis_sm_base_r1) &&
+	    (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x08);
+	else
+	if ((addr >= pyxis_sm_base_r2) &&
+	    (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x08);
+	else
+	if ((addr >= pyxis_sm_base_r3) &&
+	    (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x08);
+	else
+	{
+#if 0
+	  printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return 0x0ffUL;
+	}
+	shift = (addr & 0x3) << 3;
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+	unsigned long work;
+
+	if ((addr >= pyxis_sm_base_r1) &&
+	    (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= pyxis_sm_base_r2) &&
+	    (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+	else
+	if ((addr >= pyxis_sm_base_r3) &&
+	    (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+	else
+	{
+#if 0
+	  printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return;
+	}
+	*(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+	unsigned long work;
+
+	if ((addr >= pyxis_sm_base_r1) &&
+	    (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= pyxis_sm_base_r2) &&
+	    (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+	  work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+	else
+	if ((addr >= pyxis_sm_base_r3) &&
+	    (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+	  work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+	else
+	{
+#if 0
+	  printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return;
+	}
+	*(vuip) work = b * 0x00010001;
+}
+
+#else /* SRM_SETUP */
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+	unsigned long result, shift, msb, work, temp;
+
+	shift = (addr & 0x3) << 3;
+	msb = addr & 0xE0000000UL;
+	temp = addr & MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x00);
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+	unsigned long result, shift, msb, work, temp;
+
+	shift = (addr & 0x3) << 3;
+	msb = addr & 0xE0000000UL;
+	temp = addr & MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x08);
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	*(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x00) = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	*(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x08) = b * 0x00010001;
+}
+#endif /* SRM_SETUP */
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+	return *(vuip) (addr + PYXIS_DENSE_MEM);
+}
+
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+	*(vuip) (addr + PYXIS_DENSE_MEM) = b;
+}
+
+#endif /* BWIO_REALLY_ENABLED */
+
+#define readl(a)	__readl((unsigned long)(a))
+#define writel(v,a)	__writel((v),(unsigned long)(a))
+
+#undef vuip
+
+extern unsigned long pyxis_init (unsigned long mem_start,
+				 unsigned long mem_end);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Data structure for handling PYXIS machine checks:
+ */
+struct el_PYXIS_sysdata_mcheck {
+    u_long      coma_gcr;                       
+    u_long      coma_edsr;                      
+    u_long      coma_ter;                       
+    u_long      coma_elar;                      
+    u_long      coma_ehar;                      
+    u_long      coma_ldlr;                      
+    u_long      coma_ldhr;                      
+    u_long      coma_base0;                     
+    u_long      coma_base1;                     
+    u_long      coma_base2;                     
+    u_long      coma_cnfg0;                     
+    u_long      coma_cnfg1;                     
+    u_long      coma_cnfg2;                     
+    u_long      epic_dcsr;                      
+    u_long      epic_pear;                      
+    u_long      epic_sear;                      
+    u_long      epic_tbr1;                      
+    u_long      epic_tbr2;                      
+    u_long      epic_pbr1;                      
+    u_long      epic_pbr2;                      
+    u_long      epic_pmr1;                      
+    u_long      epic_pmr2;                      
+    u_long      epic_harx1;                     
+    u_long      epic_harx2;                     
+    u_long      epic_pmlt;                      
+    u_long      epic_tag0;                      
+    u_long      epic_tag1;                      
+    u_long      epic_tag2;                      
+    u_long      epic_tag3;                      
+    u_long      epic_tag4;                      
+    u_long      epic_tag5;                      
+    u_long      epic_tag6;                      
+    u_long      epic_tag7;                      
+    u_long      epic_data0;                     
+    u_long      epic_data1;                     
+    u_long      epic_data2;                     
+    u_long      epic_data3;                     
+    u_long      epic_data4;                     
+    u_long      epic_data5;                     
+    u_long      epic_data6;                     
+    u_long      epic_data7;                     
+};
+
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_ADDR(x)	(0x80 | (x))
+#ifdef CONFIG_ALPHA_RUFFIAN
+#define RTC_ALWAYS_BCD 1
+#else /* RUFFIAN */
+#define RTC_ALWAYS_BCD 0
+#endif /* RUFFIAN */
+ 
+#endif /* __ALPHA_PYXIS__H__ */
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/shmparam.h linux/include/asm-alpha/shmparam.h
--- v2.0.33/linux/include/asm-alpha/shmparam.h	Thu Apr 11 23:49:44 1996
+++ linux/include/asm-alpha/shmparam.h	Wed Jun  3 15:17:49 1998
@@ -2,14 +2,10 @@
 #define _ASMAXP_SHMPARAM_H
 
 /*
- * Address range for shared memory attaches if no address passed to
- * shmat().  These ought to be changed to something >4GB so 32-bit
- * errors are caught more easily.  However, they don't seem to be used
- * except for ELF stuff, so it's not really critical until we get ELF
- * support for the Alpha.
+ * Address range for shared memory attaches if no address passed to shmat().
  */
-#define SHM_RANGE_START	0x50000000
-#define SHM_RANGE_END	0x60000000
+#define SHM_RANGE_START	0x14000000000
+#define SHM_RANGE_END	0x15000000000
 
 /*
  * Format of a swap-entry for shared memory pages currently out in
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.0.33/linux/include/asm-alpha/system.h	Mon Mar 17 15:00:38 1997
+++ linux/include/asm-alpha/system.h	Wed Jun  3 15:17:49 1998
@@ -52,6 +52,8 @@
 extern unsigned long rdusp(void);
 extern unsigned long rdmces (void);
 extern void wrmces (unsigned long);
+extern unsigned long whami(void);
+extern void wripir(unsigned long);
 
 #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
 
diff -u --recursive --new-file v2.0.33/linux/include/asm-alpha/t2.h linux/include/asm-alpha/t2.h
--- v2.0.33/linux/include/asm-alpha/t2.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/t2.h	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,654 @@
+#ifndef __ALPHA_T2__H__
+#define __ALPHA_T2__H__
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/*
+ * T2 is the internal name for the core logic chipset which provides
+ * memory controller and PCI access for the SABLE-based systems.
+ *
+ * This file is based on:
+ *
+ * SABLE I/O Specification
+ * Revision/Update Information: 1.3
+ *
+ * jestabro@amt.tay1.dec.com Initial Version.
+ *
+ */
+
+#define BYTE_ENABLE_SHIFT 5
+#define TRANSFER_LENGTH_SHIFT 3
+#define MEM_R1_MASK 0x03ffffff  /* Mem sparse space region 1 mask is 26 bits */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define T2_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define T2_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int T2_DMA_WIN_BASE;
+extern unsigned int T2_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define T2_DMA_WIN_BASE	(1024*1024*1024)
+#define T2_DMA_WIN_SIZE	(1024*1024*1024)
+#endif /* SRM_SETUP */
+
+/* GAMMA-SABLE is a SABLE with EV5-based CPUs */
+#ifdef CONFIG_ALPHA_GAMMA
+#  define GAMMA_BIAS		0x8000000000UL
+#else /* GAMMA */
+#  define GAMMA_BIAS		0x0000000000UL
+#endif /* GAMMA */
+
+/*
+ * Memory spaces:
+ */
+#define T2_CONF		        (IDENT_ADDR + GAMMA_BIAS + 0x390000000UL)
+#define T2_IO			(IDENT_ADDR + GAMMA_BIAS + 0x3a0000000UL)
+#define T2_SPARSE_MEM		(IDENT_ADDR + GAMMA_BIAS + 0x200000000UL)
+#define T2_DENSE_MEM	        (IDENT_ADDR + GAMMA_BIAS + 0x3c0000000UL)
+
+#define T2_IOCSR		(IDENT_ADDR + GAMMA_BIAS + 0x38e000000UL)
+#define T2_CERR1		(IDENT_ADDR + GAMMA_BIAS + 0x38e000020UL)
+#define T2_CERR2		(IDENT_ADDR + GAMMA_BIAS + 0x38e000040UL)
+#define T2_CERR3		(IDENT_ADDR + GAMMA_BIAS + 0x38e000060UL)
+#define T2_PERR1		(IDENT_ADDR + GAMMA_BIAS + 0x38e000080UL)
+#define T2_PERR2		(IDENT_ADDR + GAMMA_BIAS + 0x38e0000a0UL)
+#define T2_PSCR			(IDENT_ADDR + GAMMA_BIAS + 0x38e0000c0UL)
+#define T2_HAE_1		(IDENT_ADDR + GAMMA_BIAS + 0x38e0000e0UL)
+#define T2_HAE_2		(IDENT_ADDR + GAMMA_BIAS + 0x38e000100UL)
+#define T2_HBASE		(IDENT_ADDR + GAMMA_BIAS + 0x38e000120UL)
+#define T2_WBASE1		(IDENT_ADDR + GAMMA_BIAS + 0x38e000140UL)
+#define T2_WMASK1		(IDENT_ADDR + GAMMA_BIAS + 0x38e000160UL)
+#define T2_TBASE1		(IDENT_ADDR + GAMMA_BIAS + 0x38e000180UL)
+#define T2_WBASE2		(IDENT_ADDR + GAMMA_BIAS + 0x38e0001a0UL)
+#define T2_WMASK2		(IDENT_ADDR + GAMMA_BIAS + 0x38e0001c0UL)
+#define T2_TBASE2		(IDENT_ADDR + GAMMA_BIAS + 0x38e0001e0UL)
+#define T2_TLBBR		(IDENT_ADDR + GAMMA_BIAS + 0x38e000200UL)
+
+#define T2_HAE_3		(IDENT_ADDR + GAMMA_BIAS + 0x38e000240UL)
+#define T2_HAE_4		(IDENT_ADDR + GAMMA_BIAS + 0x38e000260UL)
+
+#define HAE_ADDRESS		T2_HAE_1
+
+/*  T2 CSRs are in the non-cachable primary IO space from 3.8000.0000 to
+ 3.8fff.ffff
+ *
+ *  +--------------+ 3 8000 0000
+ *  | CPU 0 CSRs   |            
+ *  +--------------+ 3 8100 0000
+ *  | CPU 1 CSRs   |            
+ *  +--------------+ 3 8200 0000
+ *  | CPU 2 CSRs   |            
+ *  +--------------+ 3 8300 0000
+ *  | CPU 3 CSRs   |            
+ *  +--------------+ 3 8400 0000
+ *  | CPU Reserved |            
+ *  +--------------+ 3 8700 0000
+ *  | Mem Reserved |            
+ *  +--------------+ 3 8800 0000
+ *  | Mem 0 CSRs   |            
+ *  +--------------+ 3 8900 0000
+ *  | Mem 1 CSRs   |            
+ *  +--------------+ 3 8a00 0000
+ *  | Mem 2 CSRs   |            
+ *  +--------------+ 3 8b00 0000
+ *  | Mem 3 CSRs   |            
+ *  +--------------+ 3 8c00 0000           
+ *  | Mem Reserved |            
+ *  +--------------+ 3 8e00 0000           
+ *  | PCI Bridge   |            
+ *  +--------------+ 3 8f00 0000           
+ *  | Expansion IO |            
+ *  +--------------+ 3 9000 0000           
+ *                                              
+ *
+ */
+#define CPU0_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x380000000L)
+#define CPU1_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x381000000L)
+#define CPU2_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x382000000L)
+#define CPU3_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x383000000L)
+#define MEM0_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x388000000L)
+#define MEM1_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x389000000L)
+#define MEM2_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x38a000000L)
+#define MEM3_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x38b000000L)
+
+#ifdef __KERNEL__
+
+/*
+ * Translate physical memory address as seen on (PCI) bus into
+ * a kernel virtual address and vv.
+ */
+extern inline unsigned long virt_to_bus(void * address)
+{
+	return virt_to_phys(address) + T2_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+	return phys_to_virt(address - T2_DMA_WIN_BASE);
+}
+
+/*
+ * I/O functions:
+ *
+ * T2 (the core logic PCI/memory support chipset for the SABLE
+ * series of processors uses a sparse address mapping scheme to
+ * get at PCI memory and I/O.
+ */
+
+#define vuip	volatile unsigned int *
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+	long result = *(vuip) ((addr << 5) + T2_IO + 0x00);
+	result >>= (addr & 3) * 8;
+	return 0xffUL & result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+	unsigned int w;
+
+	asm ("insbl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+	*(vuip) ((addr << 5) + T2_IO + 0x00) = w;
+	mb();
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+	long result = *(vuip) ((addr << 5) + T2_IO + 0x08);
+	result >>= (addr & 3) * 8;
+	return 0xffffUL & result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+	unsigned int w;
+
+	asm ("inswl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+	*(vuip) ((addr << 5) + T2_IO + 0x08) = w;
+	mb();
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+	return *(vuip) ((addr << 5) + T2_IO + 0x18);
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+	*(vuip) ((addr << 5) + T2_IO + 0x18) = b;
+	mb();
+}
+
+
+/*
+ * Memory functions.  64-bit and 32-bit accesses are done through
+ * dense memory space, everything else through sparse space.
+ * 
+ * For reading and writing 8 and 16 bit quantities we need to 
+ * go through one of the three sparse address mapping regions
+ * and use the HAE_MEM CSR to provide some bits of the address.
+ * The following few routines use only sparse address region 1
+ * which gives 1Gbyte of accessible space which relates exactly
+ * to the amount of PCI memory mapping *into* system address space.
+ * See p 6-17 of the specification but it looks something like this:
+ *
+ * 21164 Address:
+ * 
+ *          3         2         1                                                               
+ * 9876543210987654321098765432109876543210
+ * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ *
+ * ZZ = SBZ
+ * BB = Byte offset
+ * LL = Transfer length
+ *
+ * PCI Address:
+ *
+ * 3         2         1                                                               
+ * 10987654321098765432109876543210
+ * HHH....PCI.QW.Address........ 00
+ *
+ * HHH = 31:29 HAE_MEM CSR
+ * 
+ */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long t2_sm_base;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+	unsigned long result, shift, work;
+
+	if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+	else
+	{
+#if 0
+	  printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return 0x0ffUL;
+	}
+	shift = (addr & 0x3) << 3;
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+	unsigned long result, shift, work;
+
+	if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+	else
+	if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+	else
+	{
+#if 0
+	  printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return 0x0ffffUL;
+	}
+	shift = (addr & 0x3) << 3;
+	result = *(vuip) work;
+	result >>= shift;
+	return 0x0ffffUL & result;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline unsigned long __readl(unsigned long addr)
+{
+	unsigned long result, work;
+
+	if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+	else
+	if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+	else
+	{
+#if 0
+	  printk("__readl: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return 0x0ffffffffUL;
+	}
+	result = *(vuip) work;
+	return 0xffffffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+	unsigned long work;
+
+	if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+	else
+	if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+	else
+	{
+#if 0
+	  printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return;
+	}
+	*(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+	unsigned long work;
+
+	if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+	else
+	if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+	else
+	{
+#if 0
+	  printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return;
+	}
+	*(vuip) work = b * 0x00010001;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+	unsigned long work;
+
+	if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+	else
+	if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+	  work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+	{
+#if 0
+	  printk("__writel: address 0x%lx not covered by HAE\n", addr);
+#endif
+	  return;
+	}
+	*(vuip) work = b;
+}
+
+#else /* SRM_SETUP */
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+	unsigned long result, shift, msb;
+
+	shift = (addr & 0x3) * 8 ;
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) ;
+	result >>= shift;
+	return 0xffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+	unsigned long result, shift, msb;
+
+	shift = (addr & 0x3) * 8;
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
+	result >>= shift;
+	return 0xffffUL & result;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline unsigned long __readl(unsigned long addr)
+{
+	unsigned long result, msb;
+
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
+	return 0xffffffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = b * 0x00010001;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+	msb = addr & 0xE0000000 ;
+	addr &= MEM_R1_MASK ;
+	if (msb != hae.cache) {
+	  set_hae(msb);
+	}
+	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
+}
+
+#endif /* SRM_SETUP */
+
+#define inb(port) \
+(__builtin_constant_p((port))?__inb(port):_inb(port))
+
+#define outb(x, port) \
+(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
+
+#define readl(a)	__readl((unsigned long)(a))
+#define writel(v,a)	__writel((v),(unsigned long)(a))
+
+#undef vuip
+
+extern unsigned long t2_init (unsigned long mem_start,
+				 unsigned long mem_end);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Sable CPU Module CSRS
+ *
+ * These are CSRs for hardware other than the CPU chip on the CPU module.
+ * The CPU module has Backup Cache control logic, Cbus control logic, and
+ * interrupt control logic on it.  There is a duplicate tag store to speed
+ * up maintaining cache coherency.
+ */
+
+struct sable_cpu_csr {
+unsigned long bcc;     long fill_00[3]; /* Backup Cache Control */
+unsigned long bcce;    long fill_01[3]; /* Backup Cache Correctable Error */
+unsigned long bccea;   long fill_02[3]; /* B-Cache Corr Err Address Latch */
+unsigned long bcue;    long fill_03[3]; /* B-Cache Uncorrectable Error */
+unsigned long bcuea;   long fill_04[3]; /* B-Cache Uncorr Err Addr Latch */
+unsigned long dter;    long fill_05[3]; /* Duplicate Tag Error */
+unsigned long cbctl;   long fill_06[3]; /* CBus Control */
+unsigned long cbe;     long fill_07[3]; /* CBus Error */
+unsigned long cbeal;   long fill_08[3]; /* CBus Error Addr Latch low */
+unsigned long cbeah;   long fill_09[3]; /* CBus Error Addr Latch high */
+unsigned long pmbx;    long fill_10[3]; /* Processor Mailbox */
+unsigned long ipir;    long fill_11[3]; /* Inter-Processor Int Request */
+unsigned long sic;     long fill_12[3]; /* System Interrupt Clear */
+unsigned long adlk;    long fill_13[3]; /* Address Lock (LDxL/STxC) */
+unsigned long madrl;   long fill_14[3]; /* CBus Miss Address */
+unsigned long rev;     long fill_15[3]; /* CMIC Revision */
+};
+
+/*
+ * Data structure for handling T2 machine checks:
+ */
+struct el_t2_frame_header {
+	unsigned int	elcf_fid;	/* Frame ID (from above) */
+	unsigned int	elcf_size;	/* Size of frame in bytes */
+};
+
+struct el_t2_procdata_mcheck {
+	unsigned long	elfmc_paltemp[32];	/* PAL TEMP REGS. */
+	/* EV4-specific fields */
+	unsigned long	elfmc_exc_addr;	/* Addr of excepting insn. */
+	unsigned long	elfmc_exc_sum;	/* Summary of arith traps. */
+	unsigned long	elfmc_exc_mask;	/* Exception mask (from exc_sum). */
+	unsigned long	elfmc_iccsr;	/* IBox hardware enables. */
+	unsigned long	elfmc_pal_base;	/* Base address for PALcode. */
+	unsigned long	elfmc_hier;	/* Hardware Interrupt Enable. */
+	unsigned long	elfmc_hirr;	/* Hardware Interrupt Request. */
+	unsigned long	elfmc_mm_csr;	/* D-stream fault info. */
+	unsigned long	elfmc_dc_stat;	/* D-cache status (ECC/Parity Err). */
+	unsigned long	elfmc_dc_addr;	/* EV3 Phys Addr for ECC/DPERR. */
+	unsigned long	elfmc_abox_ctl;	/* ABox Control Register. */
+	unsigned long	elfmc_biu_stat;	/* BIU Status. */
+	unsigned long	elfmc_biu_addr;	/* BUI Address. */
+	unsigned long	elfmc_biu_ctl;	/* BIU Control. */
+	unsigned long	elfmc_fill_syndrome;	/* For correcting ECC errors. */
+	unsigned long	elfmc_fill_addr;/* Cache block which was being read. */
+	unsigned long	elfmc_va;	/* Effective VA of fault or miss. */
+	unsigned long	elfmc_bc_tag;	/* Backup Cache Tag Probe Results. */
+};
+
+/* 
+ * Sable processor specific Machine Check Data segment.
+ */
+
+struct el_t2_logout_header {
+	unsigned int	elfl_size;	/* size in bytes of logout area. */
+	int	elfl_sbz1:31;		/* Should be zero. */
+	char	elfl_retry:1;		/* Retry flag. */
+        unsigned int	elfl_procoffset;	/* Processor-specific offset. */
+	unsigned int	elfl_sysoffset;		/* Offset of system-specific. */
+	unsigned int	elfl_error_type;	/* PAL error type code. */
+	unsigned int	elfl_frame_rev;		/* PAL Frame revision. */
+};
+struct el_t2_sysdata_mcheck {
+	unsigned long    elcmc_bcc;	      /* CSR 0 */
+	unsigned long    elcmc_bcce;	      /* CSR 1 */
+	unsigned long    elcmc_bccea;      /* CSR 2 */
+	unsigned long    elcmc_bcue;	      /* CSR 3 */
+	unsigned long    elcmc_bcuea;      /* CSR 4 */
+	unsigned long    elcmc_dter;	      /* CSR 5 */
+	unsigned long    elcmc_cbctl;      /* CSR 6 */
+	unsigned long    elcmc_cbe;	      /* CSR 7 */
+	unsigned long    elcmc_cbeal;      /* CSR 8 */
+	unsigned long    elcmc_cbeah;      /* CSR 9 */
+	unsigned long    elcmc_pmbx;	      /* CSR 10 */
+	unsigned long    elcmc_ipir;	      /* CSR 11 */
+	unsigned long    elcmc_sic;	      /* CSR 12 */
+	unsigned long    elcmc_adlk;	      /* CSR 13 */
+	unsigned long    elcmc_madrl;      /* CSR 14 */
+	unsigned long    elcmc_crrev4;     /* CSR 15 */
+};
+
+/*
+ * Sable memory error frame - sable pfms section 3.42
+ */
+struct el_t2_data_memory {
+	struct	el_t2_frame_header elcm_hdr;	/* ID$MEM-FERR = 0x08 */
+	unsigned int  elcm_module;	/* Module id. */
+	unsigned int  elcm_res04;	/* Reserved. */
+	unsigned long elcm_merr;	/* CSR0: Error Reg 1. */
+	unsigned long elcm_mcmd1;	/* CSR1: Command Trap 1. */
+	unsigned long elcm_mcmd2;	/* CSR2: Command Trap 2. */
+	unsigned long elcm_mconf;	/* CSR3: Configuration. */
+	unsigned long elcm_medc1;	/* CSR4: EDC Status 1. */
+	unsigned long elcm_medc2;	/* CSR5: EDC Status 2. */
+	unsigned long elcm_medcc;	/* CSR6: EDC Control. */
+	unsigned long elcm_msctl;	/* CSR7: Stream Buffer Control. */
+	unsigned long elcm_mref;	/* CSR8: Refresh Control. */
+	unsigned long elcm_filter;	/* CSR9: CRD Filter Control. */
+};
+
+
+/*
+ * Sable other cpu error frame - sable pfms section 3.43
+ */
+struct el_t2_data_other_cpu {
+	short	      elco_cpuid;	/* CPU ID */
+	short	      elco_res02[3];	
+	unsigned long elco_bcc;	/* CSR 0 */
+	unsigned long elco_bcce;	/* CSR 1 */
+	unsigned long elco_bccea;	/* CSR 2 */
+	unsigned long elco_bcue;	/* CSR 3 */
+	unsigned long elco_bcuea;	/* CSR 4 */
+	unsigned long elco_dter;	/* CSR 5 */
+	unsigned long elco_cbctl;	/* CSR 6 */
+	unsigned long elco_cbe;	/* CSR 7 */
+	unsigned long elco_cbeal;	/* CSR 8 */
+	unsigned long elco_cbeah;	/* CSR 9 */
+	unsigned long elco_pmbx;	/* CSR 10 */
+	unsigned long elco_ipir;	/* CSR 11 */
+	unsigned long elco_sic;	/* CSR 12 */
+	unsigned long elco_adlk;	/* CSR 13 */
+	unsigned long elco_madrl;	/* CSR 14 */
+	unsigned long elco_crrev4;	/* CSR 15 */
+};
+
+/*
+ * Sable other cpu error frame - sable pfms section 3.44
+ */
+struct el_t2_data_t2{
+        struct el_t2_frame_header elct_hdr;	/* ID$T2-FRAME */
+	unsigned long elct_iocsr;	/* IO Control and Status Register */
+	unsigned long elct_cerr1;	/* Cbus Error Register 1 */
+	unsigned long elct_cerr2;	/* Cbus Error Register 2 */
+	unsigned long elct_cerr3;	/* Cbus Error Register 3 */
+	unsigned long elct_perr1;	/* PCI Error Register 1 */
+	unsigned long elct_perr2;	/* PCI Error Register 2 */
+	unsigned long elct_hae0_1;	/* High Address Extension Register 1 */
+	unsigned long elct_hae0_2;	/* High Address Extension Register 2 */
+	unsigned long elct_hbase;	/* High Base Register */
+	unsigned long elct_wbase1;	/* Window Base Register 1 */
+	unsigned long elct_wmask1;	/* Window Mask Register 1 */
+	unsigned long elct_tbase1;	/* Translated Base Register 1 */
+	unsigned long elct_wbase2;	/* Window Base Register 2 */
+	unsigned long elct_wmask2;	/* Window Mask Register 2 */
+	unsigned long elct_tbase2;	/* Translated Base Register 2 */
+	unsigned long elct_tdr0;	/* TLB Data Register 0 */
+	unsigned long elct_tdr1;	/* TLB Data Register 1 */
+	unsigned long elct_tdr2;	/* TLB Data Register 2 */
+	unsigned long elct_tdr3;	/* TLB Data Register 3 */
+	unsigned long elct_tdr4;	/* TLB Data Register 4 */
+	unsigned long elct_tdr5;	/* TLB Data Register 5 */
+	unsigned long elct_tdr6;	/* TLB Data Register 6 */
+	unsigned long elct_tdr7;	/* TLB Data Register 7 */
+};
+
+/*
+ * Sable error log data structure - sable pfms section 3.40
+ */
+struct el_t2_data_corrected {
+	unsigned long elcpb_biu_stat;
+	unsigned long elcpb_biu_addr;
+	unsigned long elcpb_biu_ctl;
+	unsigned long elcpb_fill_syndrome;
+	unsigned long elcpb_fill_addr;
+	unsigned long elcpb_bc_tag;
+};
+
+/* 
+ * Sable error log data structure
+ * Note there are 4 memory slots on sable (see t2.h)
+ */
+struct el_t2_frame_mcheck {
+        struct el_t2_frame_header elfmc_header;	/* ID$P-FRAME_MCHECK */
+	struct el_t2_logout_header elfmc_hdr;
+	struct el_t2_procdata_mcheck elfmc_procdata;
+	struct el_t2_sysdata_mcheck elfmc_sysdata;
+	struct el_t2_data_t2 elfmc_t2data;
+	struct el_t2_data_memory elfmc_memdata[4]; 
+        struct el_t2_frame_header elfmc_footer;	/* empty */
+};
+
+
+/* 
+ * Sable error log data structures on memory errors
+ */
+struct el_t2_frame_corrected {
+        struct el_t2_frame_header elfcc_header;	/* ID$P-BC-COR */
+	struct el_t2_logout_header elfcc_hdr;
+	struct el_t2_data_corrected elfcc_procdata; 
+/*	struct el_t2_data_t2 elfcc_t2data;		*/
+/*	struct el_t2_data_memory elfcc_memdata[4];	*/
+        struct el_t2_frame_header elfcc_footer;	/* empty */
+};
+
+
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_ADDR(x)	(0x80 | (x))
+#define RTC_ALWAYS_BCD	0
+
+#endif /* __ALPHA_T2__H__ */
diff -u --recursive --new-file v2.0.33/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v2.0.33/linux/include/asm-i386/irq.h	Mon Aug 11 13:42:11 1997
+++ linux/include/asm-i386/irq.h	Wed Jun  3 15:17:49 1998
@@ -143,7 +143,7 @@
 	"movl "SYMBOL_NAME_STR(apic_reg)", %edx\n\t" \
 	"movl 32(%edx), %eax\n\t" \
 	"shrl $24,%eax\n\t" \
-	"andb $0x0F,%al\n"
+	"andl $0x0F,%eax\n"
 
 #define	ENTER_KERNEL \
 	"pushl %eax\n\t" \
@@ -165,10 +165,10 @@
 	"movb $1, "SYMBOL_NAME_STR(smp_blocked_interrupt_pending)"\n\t" \
 	"2: " \
         SMP_PROF_INT_SPINS \
-	"btl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
+	"btl %eax, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
 	"jnc 5f\n\t" \
 	"lock\n\t" \
-	"btrl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
+	"btrl %eax, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
 	"jnc 5f\n\t" \
 	"movl %cr3,%edx\n\t" \
 	"movl %edx,%cr3\n" \
diff -u --recursive --new-file v2.0.33/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.0.33/linux/include/asm-i386/processor.h	Tue Mar 11 13:52:29 1997
+++ linux/include/asm-i386/processor.h	Wed Jun  3 15:17:49 1998
@@ -40,6 +40,8 @@
  * so don't change it unless you know what you are doing.
  */
 #define TASK_SIZE	(0xC0000000UL)
+#define MAX_USER_ADDR	TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
diff -u --recursive --new-file v2.0.33/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.0.33/linux/include/asm-m68k/processor.h	Sun Mar 24 02:21:16 1996
+++ linux/include/asm-m68k/processor.h	Wed Jun  3 15:17:49 1998
@@ -14,6 +14,8 @@
  * so don't change it unless you know what you are doing.
  */
 #define TASK_SIZE	(0xF0000000UL)
+#define MAX_USER_ADDR	TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /*
  * Bus types
diff -u --recursive --new-file v2.0.33/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.0.33/linux/include/asm-mips/processor.h	Thu Apr 11 23:49:44 1996
+++ linux/include/asm-mips/processor.h	Wed Jun  3 15:17:49 1998
@@ -44,6 +44,8 @@
  * so don't change it unless you know what you are doing.
  */
 #define TASK_SIZE	(0x80000000UL)
+#define MAX_USER_ADDR	TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
diff -u --recursive --new-file v2.0.33/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.0.33/linux/include/asm-ppc/processor.h	Mon May 27 02:00:59 1996
+++ linux/include/asm-ppc/processor.h	Wed Jun  3 15:17:49 1998
@@ -80,6 +80,8 @@
  * "this is gonna have to change to 1gig for the sparc" - David S. Miller
  */
 #define TASK_SIZE	(0x80000000UL)
+#define MAX_USER_ADDR	TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 struct thread_struct 
    {
diff -u --recursive --new-file v2.0.33/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
--- v2.0.33/linux/include/asm-sparc/processor.h	Sun Apr 21 02:30:33 1996
+++ linux/include/asm-sparc/processor.h	Wed Jun  3 15:17:49 1998
@@ -31,6 +31,8 @@
 
 /* Whee, this is STACK_TOP and the lowest kernel address too... */
 #define TASK_SIZE	(KERNBASE)
+#define MAX_USER_ADDR	TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /* The Sparc processor specific thread struct. */
 struct thread_struct {
diff -u --recursive --new-file v2.0.33/linux/include/linux/bios32.h linux/include/linux/bios32.h
--- v2.0.33/linux/include/linux/bios32.h	Fri May  3 05:40:09 1996
+++ linux/include/linux/bios32.h	Wed Jun  3 15:17:49 1998
@@ -54,8 +54,8 @@
 				      unsigned char where, unsigned char val);
 extern int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
 				      unsigned char where, unsigned short val);
-extern pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
-				   unsigned char where, unsigned int val);
+extern int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
+				       unsigned char where, unsigned int val);
 extern const char *pcibios_strerror (int error);
 
 #endif /* BIOS32_H */
diff -u --recursive --new-file v2.0.33/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.0.33/linux/include/linux/fs.h	Tue Dec  2 13:52:33 1997
+++ linux/include/linux/fs.h	Wed Jun  3 15:17:49 1998
@@ -304,16 +304,16 @@
 	struct inode *i_hash_next, *i_hash_prev;
 	struct inode *i_bound_to, *i_bound_by;
 	struct inode *i_mount;
-	unsigned short i_count;
+	unsigned long i_count;	/* needs to be > (address_space * tasks)>>pagebits */
 	unsigned short i_flags;
+	unsigned short i_writecount;
 	unsigned char i_lock;
 	unsigned char i_dirt;
 	unsigned char i_pipe;
 	unsigned char i_sock;
 	unsigned char i_seek;
 	unsigned char i_update;
-	unsigned char i_condemned;
-	unsigned short i_writecount;
+ 	unsigned char i_condemned;
 	union {
 		struct pipe_inode_info pipe_i;
 		struct minix_inode_info minix_i;
diff -u --recursive --new-file v2.0.33/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v2.0.33/linux/include/linux/genhd.h	Wed Oct 15 15:22:04 1997
+++ linux/include/linux/genhd.h	Wed Jun  3 15:17:49 1998
@@ -21,10 +21,11 @@
 #define CONFIG_SUN_PARTITION 1
 #endif
 
-/* These two have identical behaviour; use the second one if DOS fdisk gets
+/* These three have identical behaviour; use the second one if DOS fdisk gets
    confused about extended/logical partitions starting past cylinder 1023. */
 #define DOS_EXTENDED_PARTITION 5
 #define LINUX_EXTENDED_PARTITION 0x85
+#define WIN98_EXTENDED_PARTITION 0x0f
 
 #define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
 #define EZD_PARTITION		0x55	/* EZ-DRIVE:  same as DM6 (we think) */
diff -u --recursive --new-file v2.0.33/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v2.0.33/linux/include/linux/hdreg.h	Wed Oct 15 15:22:04 1997
+++ linux/include/linux/hdreg.h	Wed Jun  3 15:17:49 1998
@@ -78,7 +78,8 @@
 #define ID_ERR		0x10	/* ID field not found */
 #define MC_ERR		0x20	/* media changed */
 #define ECC_ERR		0x40	/* Uncorrectable ECC error */
-#define	BBD_ERR		0x80	/* block marked bad */
+#define	BBD_ERR		0x80	/* pre-EIDE meaning:  block marked bad */
+#define	ICRC_ERR	0x80	/* new meaning:  CRC error during transfer */
 
 struct hd_geometry {
       unsigned char heads;
@@ -151,11 +152,28 @@
 	unsigned short  eide_dma_time;	/* recommended mword dma cycle time (ns) */
 	unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
 	unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
-	unsigned short  reserved69;	/* reserved (word 69) */
-	unsigned short  reserved70;	/* reserved (word 70) */
-	/* unsigned short reservedxx[57];*/	/* reserved (words 71-127) */
-	/* unsigned short vendor7  [32];*/	/* vendor unique (words 128-159) */
-	/* unsigned short reservedyy[96];*/	/* reserved (words 160-255) */
+	unsigned short  word69;
+	unsigned short  word70;
+	/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+	unsigned short  word71;
+	unsigned short  word72;
+	unsigned short  word73;
+	unsigned short  word74;
+	unsigned short  word75;
+	unsigned short  word76;
+	unsigned short  word77;
+	unsigned short  word78;
+	unsigned short  word79;
+	unsigned short  word80;
+	unsigned short  word81;
+	unsigned short  word82;
+	unsigned short  word83;
+	unsigned short  word84;
+	unsigned short  word85;
+	unsigned short  word86;
+	unsigned short  word87;
+	unsigned short  dma_ultra;
+	unsigned short  reserved[167];
 };
 
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.0.33/linux/include/linux/if_frad.h linux/include/linux/if_frad.h
--- v2.0.33/linux/include/linux/if_frad.h	Wed Oct 15 15:11:54 1997
+++ linux/include/linux/if_frad.h	Wed Jun  3 15:17:49 1998
@@ -24,6 +24,7 @@
 #ifndef _FRAD_H_
 #define _FRAD_H_
 
+#include <linux/config.h>
 #include <linux/if.h>
 
 /* Structures and constants associated with the DLCI device driver */
diff -u --recursive --new-file v2.0.33/linux/include/linux/ioport.h linux/include/linux/ioport.h
--- v2.0.33/linux/include/linux/ioport.h	Sat Dec 30 11:00:41 1995
+++ linux/include/linux/ioport.h	Wed Jun  3 15:17:49 1998
@@ -24,7 +24,7 @@
 
 
 #define HAVE_AUTOIRQ
-extern void *irq2dev_map[16];		/* Use only if you own the IRQ. */
+extern void *irq2dev_map[];		/* Use only if you own the IRQ. */
 extern int autoirq_setup(int waittime);
 extern int autoirq_report(int waittime);
 
diff -u --recursive --new-file v2.0.33/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- v2.0.33/linux/include/linux/iso_fs.h	Tue Oct  8 09:47:22 1996
+++ linux/include/linux/iso_fs.h	Wed Jun  3 15:17:49 1998
@@ -19,6 +19,7 @@
 
 /* volume descriptor types */
 #define ISO_VD_PRIMARY 1
+#define ISO_VD_SUPPLEMENTARY 2
 #define ISO_VD_END 255
 
 #define ISO_STANDARD_ID "CD001"
@@ -59,6 +60,43 @@
 	char unused5			[ISODCL (1396, 2048)];
 };
 
+/* Almost the same as the primary descriptor but two fields are specified */
+struct iso_supplementary_descriptor {
+	char type			[ISODCL (  1,   1)]; /* 711 */
+	char id				[ISODCL (  2,   6)];
+	char version			[ISODCL (  7,   7)]; /* 711 */
+	char flags			[ISODCL (  8,   8)]; /* 853 */
+	char system_id			[ISODCL (  9,  40)]; /* achars */
+	char volume_id			[ISODCL ( 41,  72)]; /* dchars */
+	char unused2			[ISODCL ( 73,  80)];
+	char volume_space_size		[ISODCL ( 81,  88)]; /* 733 */
+	char escape			[ISODCL ( 89, 120)]; /* 856 */
+	char volume_set_size		[ISODCL (121, 124)]; /* 723 */
+	char volume_sequence_number	[ISODCL (125, 128)]; /* 723 */
+	char logical_block_size		[ISODCL (129, 132)]; /* 723 */
+	char path_table_size		[ISODCL (133, 140)]; /* 733 */
+	char type_l_path_table		[ISODCL (141, 144)]; /* 731 */
+	char opt_type_l_path_table	[ISODCL (145, 148)]; /* 731 */
+	char type_m_path_table		[ISODCL (149, 152)]; /* 732 */
+	char opt_type_m_path_table	[ISODCL (153, 156)]; /* 732 */
+	char root_directory_record	[ISODCL (157, 190)]; /* 9.1 */
+	char volume_set_id		[ISODCL (191, 318)]; /* dchars */
+	char publisher_id		[ISODCL (319, 446)]; /* achars */
+	char preparer_id		[ISODCL (447, 574)]; /* achars */
+	char application_id		[ISODCL (575, 702)]; /* achars */
+	char copyright_file_id		[ISODCL (703, 739)]; /* 7.5 dchars */
+	char abstract_file_id		[ISODCL (740, 776)]; /* 7.5 dchars */
+	char bibliographic_file_id	[ISODCL (777, 813)]; /* 7.5 dchars */
+	char creation_date		[ISODCL (814, 830)]; /* 8.4.26.1 */
+	char modification_date		[ISODCL (831, 847)]; /* 8.4.26.1 */
+	char expiration_date		[ISODCL (848, 864)]; /* 8.4.26.1 */
+	char effective_date		[ISODCL (865, 881)]; /* 8.4.26.1 */
+	char file_structure_version	[ISODCL (882, 882)]; /* 711 */
+	char unused4			[ISODCL (883, 883)];
+	char application_data		[ISODCL (884, 1395)];
+	char unused5			[ISODCL (1396, 2048)];
+};
+
 
 #define HS_STANDARD_ID "CDROM"
 
@@ -142,10 +180,12 @@
 extern int iso_date(char *, int);
 
 extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
-extern int get_rock_ridge_filename(struct iso_directory_record *, char ** name, int * len, struct inode *);
+extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
 
 extern char * get_rock_ridge_symlink(struct inode *);
 extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
+
+int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
 
 /* The stuff that follows may be totally unneeded. I have not checked to see 
  which prototypes we are still using.  */
diff -u --recursive --new-file v2.0.33/linux/include/linux/iso_fs_i.h linux/include/linux/iso_fs_i.h
--- v2.0.33/linux/include/linux/iso_fs_i.h	Wed Dec  1 04:44:15 1993
+++ linux/include/linux/iso_fs_i.h	Wed Jun  3 15:17:49 1998
@@ -8,6 +8,8 @@
 	unsigned int i_first_extent;
 	unsigned int i_backlink;
 	unsigned char i_file_format;
+	unsigned long i_next_section_ino;
+	off_t i_section_size;
 };
 
 #endif
diff -u --recursive --new-file v2.0.33/linux/include/linux/iso_fs_sb.h linux/include/linux/iso_fs_sb.h
--- v2.0.33/linux/include/linux/iso_fs_sb.h	Thu Dec 21 22:51:08 1995
+++ linux/include/linux/iso_fs_sb.h	Wed Jun  3 15:17:49 1998
@@ -5,26 +5,29 @@
  * iso9660 super-block data in memory
  */
 struct isofs_sb_info {
-			unsigned long s_ninodes;
-			unsigned long s_nzones;
-			unsigned long s_firstdatazone;
-			unsigned long s_log_zone_size;
-			unsigned long s_max_size;
-
-			unsigned char s_high_sierra; /* A simple flag */
-			unsigned char s_mapping;
-			unsigned char s_conversion;
-			unsigned char s_rock;
-			unsigned char s_name_check; /* r = relaxed, s = strict */
-			unsigned char s_cruft; /* Broken disks with high
-						  byte of length containing
-						  junk */
-			unsigned char s_unhide;
-			unsigned char s_nosuid;
-			unsigned char s_nodev;
-			mode_t s_mode;
-			gid_t s_gid;
-			uid_t s_uid;
+	unsigned long s_ninodes;
+	unsigned long s_nzones;
+	unsigned long s_firstdatazone;
+	unsigned long s_log_zone_size;
+	unsigned long s_max_size;
+	
+	unsigned char s_high_sierra; /* A simple flag */
+	unsigned char s_mapping;
+	unsigned char s_conversion;
+	unsigned char s_rock;
+	unsigned char s_joliet_level;
+	unsigned char s_utf8;
+	unsigned char s_name_check; /* r = relaxed, s = strict */
+	unsigned char s_cruft; /* Broken disks with high
+				  byte of length containing
+				  junk */
+	unsigned char s_unhide;
+	unsigned char s_nosuid;
+	unsigned char s_nodev;
+	mode_t s_mode;
+	gid_t s_gid;
+	uid_t s_uid;
+	struct nls_table *s_nls_iocharset; /* Native language support table */
 };
 
 #endif
diff -u --recursive --new-file v2.0.33/linux/include/linux/lists.h linux/include/linux/lists.h
--- v2.0.33/linux/include/linux/lists.h	Tue Jan  9 23:27:39 1996
+++ linux/include/linux/lists.h	Wed Jun  3 15:17:49 1998
@@ -13,7 +13,7 @@
 
 #define DLIST_INIT(listnam)	                                \
 	(listnam).dl_prev = &(listnam);				\
-	(listnam).dl_last = &(listnam);
+	(listnam).dl_next = &(listnam);
 
 #define DLIST_NEXT(listnam)	listnam.dl_next
 #define DLIST_PREV(listnam)	listnam.dl_prev
@@ -38,3 +38,25 @@
 	node->listnam.dl_next->listnam.dl_prev =		\
 		node->listnam.dl_prev;				\
 	} while (0)
+
+/*
+ * queue-style operations, which have a head and tail
+ */
+
+#define QUEUE_INIT(head, listnam, ptype)				\
+	(head)->listnam.dl_prev = (head)->listnam.dl_next = (ptype)(head);
+
+#define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam)
+#define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam)
+#define QUEUE_EMPTY(head, listnam) \
+	((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \
+	 ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head)) 
+
+#define QUEUE_ENTER(head, new, listnam, ptype) do {		\
+	(new)->listnam.dl_prev = (ptype)(head);			\
+	(new)->listnam.dl_next = (head)->listnam.dl_next;	\
+	(head)->listnam.dl_next->listnam.dl_prev = (new);	\
+	(head)->listnam.dl_next = (new);			\
+	} while (0)
+
+#define QUEUE_REMOVE(head, node, listnam) DLIST_DELETE(node, listnam)
diff -u --recursive --new-file v2.0.33/linux/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h
--- v2.0.33/linux/include/linux/mc146818rtc.h	Mon May 27 21:39:19 1996
+++ linux/include/linux/mc146818rtc.h	Wed Jun  3 15:17:49 1998
@@ -142,6 +142,8 @@
 #define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
 #define RTC_IRQP_READ	_IOR('p', 0x0b, unsigned long)	 /* Read IRQ rate   */
 #define RTC_IRQP_SET	_IOW('p', 0x0c, unsigned long)	 /* Set IRQ rate    */
+#define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
+#define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
 
 
 #endif /* _MC146818RTC_H */
diff -u --recursive --new-file v2.0.33/linux/include/linux/module.h linux/include/linux/module.h
--- v2.0.33/linux/include/linux/module.h	Wed Oct 15 15:27:44 1997
+++ linux/include/linux/module.h	Wed Jun  3 15:17:49 1998
@@ -109,6 +109,7 @@
 
 /* insert new symbol table */
 extern int register_symtab_from(struct symbol_table *, long *);
+extern void *get_module_symbol(char *, char *);
 #ifdef MODULE
 #define register_symtab(symtab) register_symtab_from(symtab, &mod_use_count_)
 #else
diff -u --recursive --new-file v2.0.33/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.0.33/linux/include/linux/msdos_fs.h	Wed Oct 15 15:25:55 1997
+++ linux/include/linux/msdos_fs.h	Wed Jun  3 15:17:49 1998
@@ -7,6 +7,8 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/fd.h>
+#include <linux/config.h>
+#include <asm/byteorder.h>
 
 #define MSDOS_ROOT_INO  1 /* == MINIX_ROOT_INO */
 #define SECTOR_SIZE     512 /* sector size (bytes) */
@@ -69,6 +71,10 @@
 
 #define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */
 
+#define EOF_FAT12 0xFF8		/* standard EOF */
+#define EOF_FAT16 0xFFF8
+#define EOF_FAT32 0xFFFFFF8
+
 /*
  * Inode flags
  */
@@ -77,8 +83,8 @@
 /*
  * ioctl commands
  */
-#define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, long)
-#define	VFAT_IOCTL_READDIR_SHORT	_IOW('r', 2, long)
+#define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct dirent [2])
+#define	VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct dirent [2])
 
 /*
  * Conversion from and to little-endian byte order. (no-op on i386/i486)
@@ -93,7 +99,7 @@
 #define CT_LE_L(v) (v)
 
 
-struct msdos_boot_sector {
+struct fat_boot_sector {
 	__s8	ignored[3];	/* Boot strap short or near jump */
 	__s8	system_id[8];	/* Name - can be used to special case
 				   partition manager volumes */
@@ -109,6 +115,24 @@
 	__u16	heads;		/* number of heads */
 	__u32	hidden;		/* hidden sectors (unused) */
 	__u32	total_sect;	/* number of sectors (if sectors == 0) */
+
+	/* The following fields are only used by FAT32 */
+	__u32	fat32_length;	/* sectors/FAT */
+	__u16	flags;		/* bit 8: fat mirroring, low 4: active fat */
+	__u8	version[2];	/* major, minor filesystem version */
+	__u32	root_cluster;	/* first cluster in root directory */
+	__u16	info_sector;	/* filesystem info sector */
+	__u16	backup_boot;	/* backup boot sector */
+	__u16	reserved2[6];	/* Unused */
+};
+
+struct fat_boot_fsinfo {
+	__u32   reserved1;	/* Nothing as far as I can tell */
+	__u32   signature;	/* 0x61417272L */
+	__u32   free_clusters;	/* Free cluster count.  -1 if unknown */
+	__u32   next_cluster;	/* Most recently allocated cluster.
+				 * Unused under Linux. */
+	__u32   reserved2[4];
 };
 
 struct msdos_dir_entry {
@@ -119,7 +143,7 @@
 	__u16	ctime;		/* Creation time */
 	__u16	cdate;		/* Creation date */
 	__u16	adate;		/* Last access date */
-	__u8    unused[2];
+	__u16   starthi;	/* High 16 bits of cluster in FAT32 */
 	__u16	time,date,start;/* time, date and first cluster */
 	__u32	size;		/* file size (in bytes) */
 };
@@ -132,7 +156,7 @@
 	__u8    reserved;	/* always 0 */
 	__u8    alias_checksum;	/* checksum for 8.3 alias */
 	__u8    name5_10[12];	/* 6 more characters in name */
-	__u8    start[2];	/* starting cluster number */
+	__u16   start;		/* starting cluster number, 0 in long slots */
 	__u8    name11_12[4];	/* last 2 characters in name */
 };
 
@@ -185,6 +209,7 @@
 		    struct msdos_dir_entry **res_de,int *ino,char scantype);
 extern int fat_parent_ino(struct inode *dir,int locked);
 extern int fat_subdirs(struct inode *dir);
+void fat_clusters_flush(struct super_block *sb);
 
 /* fat.c */
 extern int fat_access(struct super_block *sb,int nr,int new_value);
@@ -254,13 +279,32 @@
 			struct inode *new_dir,const char *new_name,int new_len,
 			int must_be_dir);
 
+/* nls.c */
+extern int init_fat_nls(void);
+extern struct fat_nls_table *fat_load_nls(int codepage);
+
+/* tables.c */
+extern unsigned char fat_uni2esc[];
+extern unsigned char fat_esc2uni[];
+
 /* fatfs_syms.c */
 extern int init_fat_fs(void);
+extern void cleanup_fat_fs(void);
+
+/* nls.c */
+extern int fat_register_nls(struct fat_nls_table * fmt);
+extern int fat_unregister_nls(struct fat_nls_table * fmt);
+extern struct fat_nls_table *fat_find_nls(int codepage);
+extern struct fat_nls_table *fat_load_nls(int codepage);
+extern void fat_unload_nls(int codepage);
+extern int init_fat_nls(void);
+
 
 /* vfat/namei.c - these are for dmsdos */
 extern int vfat_create(struct inode *dir,const char *name,int len,int mode,
 		       struct inode **result);
 extern int vfat_unlink(struct inode *dir,const char *name,int len);
+extern int vfat_unlink_uvfat(struct inode *dir,const char *name,int len);
 extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode);
 extern int vfat_rmdir(struct inode *dir,const char *name,int len);
 extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
@@ -272,6 +316,10 @@
 extern void vfat_read_inode(struct inode *inode);
 extern int vfat_lookup(struct inode *dir,const char *name,int len,
 		       struct inode **result);
+
+/* vfat/vfatfs_syms.c */
+extern struct file_system_type vfat_fs_type;
+
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.0.33/linux/include/linux/msdos_fs_i.h linux/include/linux/msdos_fs_i.h
--- v2.0.33/linux/include/linux/msdos_fs_i.h	Sun Apr 21 01:11:13 1996
+++ linux/include/linux/msdos_fs_i.h	Wed Jun  3 15:17:49 1998
@@ -26,6 +26,7 @@
 	*/
 	struct pipe_inode_info reserved;
 	int i_start;	/* first cluster or 0 */
+	int i_logstart;	/* logical first cluster */
 	int i_attrs;	/* unused attribute bits */
 	int i_busy;	/* file is either deleted but still open, or
 			   inconsistent (mkdir) */
diff -u --recursive --new-file v2.0.33/linux/include/linux/msdos_fs_sb.h linux/include/linux/msdos_fs_sb.h
--- v2.0.33/linux/include/linux/msdos_fs_sb.h	Mon Mar 11 01:25:58 1996
+++ linux/include/linux/msdos_fs_sb.h	Wed Jun  3 15:17:49 1998
@@ -9,6 +9,8 @@
 	uid_t fs_uid;
 	gid_t fs_gid;
 	unsigned short fs_umask;
+	unsigned short codepage;  /* Codepage for shortname conversions */
+	char *iocharset;          /* Charset used for filename input/display */
 	unsigned char name_check; /* r = relaxed, n = normal, s = strict */
 	unsigned char conversion; /* b = binary, t = text, a = auto */
 	unsigned quiet:1,         /* set = fake successful chmods and chowns */
@@ -16,11 +18,17 @@
 		 sys_immutable:1, /* set = system files are immutable */
 		 dotsOK:1,        /* set = hidden and system files are named '.filename' */
 		 isvfat:1,        /* 0=no vfat long filename support, 1=vfat support */
+		 utf8:1,	  /* Use of UTF8 character set (Default) */
 		 unicode_xlate:1, /* create escape sequences for unhandled Unicode */
 		 posixfs:1,       /* Allow names like makefile and Makefile to coexist */
-		 numtail:1;       /* Does first alias have a numeric '~1' type tail? */
+		 numtail:1,       /* Does first alias have a numeric '~1' type tail? */
+		 fat32:1;	  /* Is this a FAT32 partition? */
 };
 
+struct vfat_unicode {
+	unsigned char uni1;
+	unsigned char uni2;
+};
 
 struct msdos_sb_info {
 	unsigned short cluster_size; /* sectors/cluster */
@@ -29,11 +37,15 @@
 	unsigned short dir_start,dir_entries; /* root dir start & entries */
 	unsigned short data_start;   /* first data sector */
 	unsigned long clusters;      /* number of clusters */
+	unsigned long root_cluster;  /* first cluster of the root directory */
+	unsigned long fsinfo_offset; /* FAT32 fsinfo offset from start of disk */
 	struct wait_queue *fat_wait;
 	int fat_lock;
 	int prev_free;               /* previously returned free cluster number */
 	int free_clusters;           /* -1 if undefined */
 	struct fat_mount_options options;
+	struct nls_table *nls_disk;  /* Codepage used on disk */
+	struct nls_table *nls_io;    /* Charset used for input and display */
 };
 
 #endif
diff -u --recursive --new-file v2.0.33/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.0.33/linux/include/linux/netdevice.h	Wed Oct 15 15:22:48 1997
+++ linux/include/linux/netdevice.h	Wed Jun  3 15:17:49 1998
@@ -35,7 +35,7 @@
 #define MAX_ADDR_LEN	7
 #ifndef CONFIG_AX25
 #ifndef CONFIG_TR
-#ifndef CONFIG_NET_IPIP
+#if !defined(CONFIG_NET_IPIP) && !defined(CONFIG_NET_IPIP_MODULE)
 #define MAX_HEADER	32		/* We really need about 18 worst case .. so 32 is aligned */
 #else
 #define MAX_HEADER	80		/* We need to allow for having tunnel headers */
diff -u --recursive --new-file v2.0.33/linux/include/linux/nfs.h linux/include/linux/nfs.h
--- v2.0.33/linux/include/linux/nfs.h	Sun Jan 29 20:51:02 1995
+++ linux/include/linux/nfs.h	Wed Jun  3 15:17:49 1998
@@ -70,6 +70,7 @@
 	NFSERR_EAGAIN = 11,
 	NFSERR_ACCES = 13,
 	NFSERR_EXIST = 17,
+	NFSERR_XDEV = 18,
 	NFSERR_NODEV = 19,
 	NFSERR_NOTDIR = 20,
 	NFSERR_ISDIR = 21,
diff -u --recursive --new-file v2.0.33/linux/include/linux/nls.h linux/include/linux/nls.h
--- v2.0.33/linux/include/linux/nls.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/nls.h	Wed Jun  3 15:17:49 1998
@@ -0,0 +1,62 @@
+/*
+ * Native language support structures and functions
+ */
+#ifndef _LINUX_NLS_H
+#define _LINUX_NLS_H
+
+struct nls_unicode {
+	unsigned char uni1;
+	unsigned char uni2;
+};
+
+struct nls_table {
+	char *charset;
+	unsigned char **page_uni2charset;
+	struct nls_unicode *charset2uni;
+
+	void (*inc_use_count) (void);
+	void (*dec_use_count) (void);
+	struct nls_table *next;
+};
+
+/* nls.c */
+extern int init_nls(void);
+extern int register_nls(struct nls_table *);
+extern int unregister_nls(struct nls_table *);
+extern struct nls_table *find_nls(char *);
+extern struct nls_table *load_nls(char *);
+extern void unload_nls(struct nls_table *);
+extern struct nls_table *load_nls_default(void);
+
+extern int utf8_mbtowc(__u16 *, const __u8 *, int);
+extern int utf8_mbstowcs(__u16 *, const __u8 *, int);
+extern int utf8_wctomb(__u8 *, __u16, int);
+extern int utf8_wcstombs(__u8 *, const __u16 *, int);
+
+extern int init_nls_iso8859_1(void);
+extern int init_nls_iso8859_2(void);
+extern int init_nls_iso8859_3(void);
+extern int init_nls_iso8859_4(void);
+extern int init_nls_iso8859_5(void);
+extern int init_nls_iso8859_6(void);
+extern int init_nls_iso8859_7(void);
+extern int init_nls_iso8859_8(void);
+extern int init_nls_iso8859_9(void);
+extern int init_nls_cp437(void);
+extern int init_nls_cp737(void);
+extern int init_nls_cp775(void);
+extern int init_nls_cp850(void);
+extern int init_nls_cp852(void);
+extern int init_nls_cp855(void);
+extern int init_nls_cp857(void);
+extern int init_nls_cp860(void);
+extern int init_nls_cp861(void);
+extern int init_nls_cp862(void);
+extern int init_nls_cp863(void);
+extern int init_nls_cp864(void);
+extern int init_nls_cp865(void);
+extern int init_nls_cp866(void);
+extern int init_nls_cp869(void);
+extern int init_nls_cp874(void);
+
+#endif /* _LINUX_NLS_H */
diff -u --recursive --new-file v2.0.33/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.0.33/linux/include/linux/pci.h	Tue Dec  2 13:52:33 1997
+++ linux/include/linux/pci.h	Wed Jun  3 15:17:49 1998
@@ -217,14 +217,21 @@
 
 /*
  * Vendor and card ID's: sort these numerically according to vendor
- * (and according to card ID within vendor)
+ * (and according to card ID within vendor). Send all updates to
+ * <linux-pcisupport@cck.uni-kl.de>.
  */
 #define PCI_VENDOR_ID_COMPAQ		0x0e11
 #define PCI_DEVICE_ID_COMPAQ_1280	0x3033
-#define PCI_DEVICE_ID_COMPAQ_NETELL100	0xae32
-#define PCI_DEVICE_ID_COMPAQ_NETELL10	0xae34
-#define PCI_DEVICE_ID_COMPAQ_NETFLEX3	0xae35
+#define PCI_DEVICE_ID_COMPAQ_TRIFLEX	0x4000
+#define PCI_DEVICE_ID_COMPAQ_SMART2P	0xae10
+#define PCI_DEVICE_ID_COMPAQ_NETEL100	0xae32
+#define PCI_DEVICE_ID_COMPAQ_NETEL10	0xae34
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I	0xae35
+#define PCI_DEVICE_ID_COMPAQ_NETEL100D	0xae40
+#define PCI_DEVICE_ID_COMPAQ_NETEL100PI	0xae43
+#define PCI_DEVICE_ID_COMPAQ_NETEL100I	0xb011
 #define PCI_DEVICE_ID_COMPAQ_THUNDER	0xf130
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B	0xf150
 
 #define PCI_VENDOR_ID_NCR		0x1000
 #define PCI_DEVICE_ID_NCR_53C810	0x0001
@@ -236,13 +243,22 @@
 #define PCI_DEVICE_ID_NCR_53C895	0x000c
 #define PCI_DEVICE_ID_NCR_53C885	0x000d
 #define PCI_DEVICE_ID_NCR_53C875	0x000f
+#define PCI_DEVICE_ID_NCR_53C875J	0x008f
 
 #define PCI_VENDOR_ID_ATI		0x1002
 #define PCI_DEVICE_ID_ATI_68800		0x4158
 #define PCI_DEVICE_ID_ATI_215CT222	0x4354
 #define PCI_DEVICE_ID_ATI_210888CX	0x4358
+#define PCI_DEVICE_ID_ATI_215GB		0x4742
+#define PCI_DEVICE_ID_ATI_215GD		0x4744
+#define PCI_DEVICE_ID_ATI_215GI		0x4749
+#define PCI_DEVICE_ID_ATI_215GP		0x4750
+#define PCI_DEVICE_ID_ATI_215GQ		0x4751
 #define PCI_DEVICE_ID_ATI_215GT		0x4754
+#define PCI_DEVICE_ID_ATI_215GTB	0x4755
 #define PCI_DEVICE_ID_ATI_210888GX	0x4758
+#define PCI_DEVICE_ID_ATI_215LG		0x4c47
+#define PCI_DEVICE_ID_ATI_264LT		0x4c54
 #define PCI_DEVICE_ID_ATI_264VT		0x5654
 
 #define PCI_VENDOR_ID_VLSI		0x1004
@@ -250,12 +266,19 @@
 #define PCI_DEVICE_ID_VLSI_82C593	0x0006
 #define PCI_DEVICE_ID_VLSI_82C594	0x0007
 #define PCI_DEVICE_ID_VLSI_82C597	0x0009
+#define PCI_DEVICE_ID_VLSI_82C541	0x000c
+#define PCI_DEVICE_ID_VLSI_82C543	0x000d
+#define PCI_DEVICE_ID_VLSI_82C532	0x0101
+#define PCI_DEVICE_ID_VLSI_82C534	0x0102
+#define PCI_DEVICE_ID_VLSI_82C535	0x0104
+#define PCI_DEVICE_ID_VLSI_82C147	0x0105
 #define PCI_DEVICE_ID_VLSI_VAS96011	0x0702
 
 #define PCI_VENDOR_ID_ADL		0x1005
 #define PCI_DEVICE_ID_ADL_2301		0x2301
 
 #define PCI_VENDOR_ID_NS		0x100b
+#define PCI_DEVICE_ID_NS_87415		0x0002
 #define PCI_DEVICE_ID_NS_87410		0xd001
 
 #define PCI_VENDOR_ID_TSENG		0x100c
@@ -274,10 +297,12 @@
 #define PCI_DEVICE_ID_DEC_TULIP		0x0002
 #define PCI_DEVICE_ID_DEC_TGA		0x0004
 #define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
+#define PCI_DEVICE_ID_DEC_TGA2		0x000D
 #define PCI_DEVICE_ID_DEC_FDDI		0x000F
 #define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
 #define PCI_DEVICE_ID_DEC_21142		0x0019
 #define PCI_DEVICE_ID_DEC_21052		0x0021
+#define PCI_DEVICE_ID_DEC_21150		0x0022
 #define PCI_DEVICE_ID_DEC_21152		0x0024
 
 #define PCI_VENDOR_ID_CIRRUS		0x1013
@@ -298,8 +323,13 @@
 
 #define PCI_VENDOR_ID_IBM		0x1014
 #define PCI_DEVICE_ID_IBM_FIRE_CORAL	0x000a
+#define PCI_DEVICE_ID_IBM_TR		0x0018
 #define PCI_DEVICE_ID_IBM_82G2675	0x001d
+#define PCI_DEVICE_ID_IBM_MCA		0x0020
 #define PCI_DEVICE_ID_IBM_82351		0x0022
+#define PCI_DEVICE_ID_IBM_SERVERAID	0x002e
+#define PCI_DEVICE_ID_IBM_TR_WAKE	0x003e
+#define PCI_DEVICE_ID_IBM_3780IDSP	0x007d
 
 #define PCI_VENDOR_ID_WD		0x101c
 #define PCI_DEVICE_ID_WD_7197		0x3296
@@ -309,9 +339,11 @@
 #define PCI_DEVICE_ID_AMD_SCSI		0x2020
 
 #define PCI_VENDOR_ID_TRIDENT		0x1023
+#define PCI_DEVICE_ID_TRIDENT_9397	0x9397
 #define PCI_DEVICE_ID_TRIDENT_9420	0x9420
 #define PCI_DEVICE_ID_TRIDENT_9440	0x9440
 #define PCI_DEVICE_ID_TRIDENT_9660	0x9660
+#define PCI_DEVICE_ID_TRIDENT_9750	0x9750
 
 #define PCI_VENDOR_ID_AI		0x1025
 #define PCI_DEVICE_ID_AI_M1435		0x1435
@@ -321,6 +353,7 @@
 #define PCI_DEVICE_ID_MATROX_MIL	0x0519
 #define PCI_DEVICE_ID_MATROX_MYS	0x051A
 #define PCI_DEVICE_ID_MATROX_MIL_2	0x051b
+#define PCI_DEVICE_ID_MATROX_MIL_2_AGP	0x051f
 #define PCI_DEVICE_ID_MATROX_MGA_IMP	0x0d10
 
 #define PCI_VENDOR_ID_CT		0x102c
@@ -328,18 +361,24 @@
 #define PCI_DEVICE_ID_CT_65548		0x00dc
 #define PCI_DEVICE_ID_CT_65550		0x00e0
 #define PCI_DEVICE_ID_CT_65554		0x00e4
+#define PCI_DEVICE_ID_CT_65555		0x00e5
 
 #define PCI_VENDOR_ID_MIRO		0x1031
 #define PCI_DEVICE_ID_MIRO_36050	0x5601
 
+#define PCI_VENDOR_ID_NEC		0x1033
+#define PCI_DEVICE_ID_NEC_PCX2		0x0046
+
 #define PCI_VENDOR_ID_FD		0x1036
 #define PCI_DEVICE_ID_FD_36C70		0x0000
 
 #define PCI_VENDOR_ID_SI		0x1039
-#define PCI_DEVICE_ID_SI_6201		0x0001
+#define PCI_DEVICE_ID_SI_5591_AGP	0x0001
 #define PCI_DEVICE_ID_SI_6202		0x0002
-#define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_503		0x0008
+#define PCI_DEVICE_ID_SI_ACPI		0x0009
+#define PCI_DEVICE_ID_SI_5597_VGA	0x0200
+#define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_501		0x0406
 #define PCI_DEVICE_ID_SI_496		0x0496
 #define PCI_DEVICE_ID_SI_601		0x0601
@@ -347,6 +386,8 @@
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
 #define PCI_DEVICE_ID_SI_5571		0x5571
+#define PCI_DEVICE_ID_SI_5591		0x5591
+#define PCI_DEVICE_ID_SI_5597		0x5597
 #define PCI_DEVICE_ID_SI_7001		0x7001
 
 #define PCI_VENDOR_ID_HP		0x103c
@@ -356,6 +397,9 @@
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
 #define PCI_DEVICE_ID_PCTECH_RZ1001	0x1001
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_0	0x3000
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_1	0x3010
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
 
 #define PCI_VENDOR_ID_DPT               0x1044   
 #define PCI_DEVICE_ID_DPT               0xa400  
@@ -365,7 +409,11 @@
 #define PCI_DEVICE_ID_OPTI_82C557	0xc557
 #define PCI_DEVICE_ID_OPTI_82C558	0xc558
 #define PCI_DEVICE_ID_OPTI_82C621	0xc621
+#define PCI_DEVICE_ID_OPTI_82C700	0xc700
+#define PCI_DEVICE_ID_OPTI_82C701	0xc701
+#define PCI_DEVICE_ID_OPTI_82C814	0xc814
 #define PCI_DEVICE_ID_OPTI_82C822	0xc822
+#define PCI_DEVICE_ID_OPTI_82C825	0xd568
 
 #define PCI_VENDOR_ID_SGS		0x104a
 #define PCI_DEVICE_ID_SGS_2000		0x0008
@@ -377,8 +425,11 @@
 #define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT     0x8130
 
 #define PCI_VENDOR_ID_TI		0x104c
+#define PCI_DEVICE_ID_TI_TVP4010	0x3d04
+#define PCI_DEVICE_ID_TI_TVP4020	0x3d07
 #define PCI_DEVICE_ID_TI_PCI1130	0xac12
 #define PCI_DEVICE_ID_TI_PCI1131	0xac15
+#define PCI_DEVICE_ID_TI_PCI1250	0xac16
 
 #define PCI_VENDOR_ID_OAK		0x104e
 #define PCI_DEVICE_ID_OAK_OTI107	0x0107
@@ -393,11 +444,13 @@
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
 
 #define PCI_VENDOR_ID_PROMISE		0x105a
+#define PCI_DEVICE_ID_PROMISE_20246	0x4d33
 #define PCI_DEVICE_ID_PROMISE_5300	0x5300
 
 #define PCI_VENDOR_ID_N9		0x105d
 #define PCI_DEVICE_ID_N9_I128		0x2309
 #define PCI_DEVICE_ID_N9_I128_2		0x2339
+#define PCI_DEVICE_ID_N9_I128_T2R	0x493d
 
 #define PCI_VENDOR_ID_UMC		0x1060
 #define PCI_DEVICE_ID_UMC_UM8673F	0x0101
@@ -413,6 +466,10 @@
 #define PCI_VENDOR_ID_X			0x1061
 #define PCI_DEVICE_ID_X_AGX016		0x0001
 
+#define PCI_VENDOR_ID_PICOP		0x1066
+#define PCI_DEVICE_ID_PICOP_PT86C52X	0x0001
+#define PCI_DEVICE_ID_PICOP_PT80C524	0x8002
+
 #define PCI_VENDOR_ID_APPLE		0x106b
 #define PCI_DEVICE_ID_APPLE_BANDIT	0x0001
 #define PCI_DEVICE_ID_APPLE_GC		0x0002
@@ -425,11 +482,22 @@
 #define PCI_DEVICE_ID_QLOGIC_ISP1020	0x1020
 #define PCI_DEVICE_ID_QLOGIC_ISP1022	0x1022
 
+#define PCI_VENDOR_ID_CYRIX		0x1078
+#define PCI_DEVICE_ID_CYRIX_5510	0x0000
+#define PCI_DEVICE_ID_CYRIX_PCI_MASTER	0x0001
+#define PCI_DEVICE_ID_CYRIX_5520	0x0002
+#define PCI_DEVICE_ID_CYRIX_5530_LEGACY	0x0100
+#define PCI_DEVICE_ID_CYRIX_5530_SMI	0x0101
+#define PCI_DEVICE_ID_CYRIX_5530_IDE	0x0102
+#define PCI_DEVICE_ID_CYRIX_5530_AUDIO	0x0103
+#define PCI_DEVICE_ID_CYRIX_5530_VIDEO	0x0104
+
 #define PCI_VENDOR_ID_LEADTEK		0x107d
 #define PCI_DEVICE_ID_LEADTEK_805	0x0000
 
 #define PCI_VENDOR_ID_CONTAQ		0x1080
 #define PCI_DEVICE_ID_CONTAQ_82C599	0x0600
+#define PCI_DEVICE_ID_CONTAQ_82C693	0xc693
 
 #define PCI_VENDOR_ID_FOREX		0x1083
 
@@ -441,6 +509,13 @@
 #define PCI_DEVICE_ID_OLICOM_OC2326	0x0014
 #define PCI_DEVICE_ID_OLICOM_OC6151	0x0021
 
+#define PCI_VENDOR_ID_SUN		0x108e
+#define PCI_DEVICE_ID_SUN_EBUS		0x1000
+#define PCI_DEVICE_ID_SUN_HAPPYMEAL	0x1001
+#define PCI_DEVICE_ID_SUN_SIMBA		0x5000
+#define PCI_DEVICE_ID_SUN_PBM		0x8000
+#define PCI_DEVICE_ID_SUN_SABRE		0xa000
+
 #define PCI_VENDOR_ID_CMD		0x1095
 #define PCI_DEVICE_ID_CMD_640		0x0640
 #define PCI_DEVICE_ID_CMD_643		0x0643
@@ -453,6 +528,8 @@
 
 #define PCI_VENDOR_ID_BROOKTREE		0x109e
 #define PCI_DEVICE_ID_BROOKTREE_848	0x0350
+#define PCI_DEVICE_ID_BROOKTREE_849A	0x0351
+#define PCI_DEVICE_ID_BROOKTREE_8474	0x8474
 
 #define PCI_VENDOR_ID_SIERRA		0x10a8
 #define PCI_DEVICE_ID_SIERRA_STB	0x0000
@@ -468,7 +545,14 @@
 #define PCI_VENDOR_ID_DATABOOK		0x10b3
 #define PCI_DEVICE_ID_DATABOOK_87144	0xb106
 
+#define PCI_VENDOR_ID_PLX		0x10b5
+#define PCI_DEVICE_ID_PLX_9080		0x9080
+
+#define PCI_VENDOR_ID_MADGE		0x10b6
+#define PCI_DEVICE_ID_MADGE_MK2		0x0002
+
 #define PCI_VENDOR_ID_3COM		0x10b7
+#define PCI_DEVICE_ID_3COM_3C339	0x3390
 #define PCI_DEVICE_ID_3COM_3C590	0x5900
 #define PCI_DEVICE_ID_3COM_3C595TX	0x5950
 #define PCI_DEVICE_ID_3COM_3C595T4	0x5951
@@ -476,8 +560,11 @@
 #define PCI_DEVICE_ID_3COM_3C900TPO	0x9000
 #define PCI_DEVICE_ID_3COM_3C900COMBO	0x9001
 #define PCI_DEVICE_ID_3COM_3C905TX	0x9050
+#define PCI_DEVICE_ID_3COM_3C905T4	0x9051
+#define PCI_DEVICE_ID_3COM_3C905B_TX	0x9055
 
 #define PCI_VENDOR_ID_SMC		0x10b8
+#define PCI_DEVICE_ID_SMC_EPIC100	0x0005
 
 #define PCI_VENDOR_ID_AL		0x10b9
 #define PCI_DEVICE_ID_AL_M1445		0x1445
@@ -487,21 +574,44 @@
 #define PCI_DEVICE_ID_AL_M1489		0x1489
 #define PCI_DEVICE_ID_AL_M1511		0x1511
 #define PCI_DEVICE_ID_AL_M1513		0x1513
+#define PCI_DEVICE_ID_AL_M1521		0x1521
+#define PCI_DEVICE_ID_AL_M1523		0x1523
+#define PCI_DEVICE_ID_AL_M1531		0x1531
+#define PCI_DEVICE_ID_AL_M1533		0x1533
+#define PCI_DEVICE_ID_AL_M3307		0x3307
 #define PCI_DEVICE_ID_AL_M4803		0x5215
+#define PCI_DEVICE_ID_AL_M5219		0x5219
+#define PCI_DEVICE_ID_AL_M5229		0x5229
+#define PCI_DEVICE_ID_AL_M5237		0x5237
+#define PCI_DEVICE_ID_AL_M7101		0x7101
 
 #define PCI_VENDOR_ID_MITSUBISHI	0x10ba
 
+#define PCI_VENDOR_ID_SURECOM		0x10bd
+#define PCI_DEVICE_ID_SURECOM_NE34	0x0e34
+
 #define PCI_VENDOR_ID_NEOMAGIC          0x10c8
 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001
 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004
 
 #define PCI_VENDOR_ID_ASP		0x10cd
 #define PCI_DEVICE_ID_ASP_ABP940	0x1200
 #define PCI_DEVICE_ID_ASP_ABP940U	0x1300
+#define PCI_DEVICE_ID_ASP_ABP940UW	0x2300
+
+#define PCI_VENDOR_ID_MACRONIX		0x10d9
+#define PCI_DEVICE_ID_MACRONIX_MX98713	0x0512
+#define PCI_DEVICE_ID_MACRONIX_MX987x5	0x0531
 
 #define PCI_VENDOR_ID_CERN		0x10dc
 #define PCI_DEVICE_ID_CERN_SPSB_PMC	0x0001
 #define PCI_DEVICE_ID_CERN_SPSB_PCI	0x0002
+#define PCI_DEVICE_ID_CERN_HIPPI_DST	0x0021
+#define PCI_DEVICE_ID_CERN_HIPPI_SRC	0x0022
+
+#define PCI_VENDOR_ID_NVIDIA		0x10de
 
 #define PCI_VENDOR_ID_IMS		0x10e0
 #define PCI_DEVICE_ID_IMS_8849		0x8849
@@ -515,6 +625,7 @@
 #define PCI_VENDOR_ID_AMCC		0x10e8
 #define PCI_DEVICE_ID_AMCC_MYRINET	0x8043
 #define PCI_DEVICE_ID_AMCC_S5933	0x807d
+#define PCI_DEVICE_ID_AMCC_S5933_HEPC3	0x809c
 
 #define PCI_VENDOR_ID_INTERG		0x10ea
 #define PCI_DEVICE_ID_INTERG_1680	0x1680
@@ -523,12 +634,14 @@
 #define PCI_VENDOR_ID_REALTEK		0x10ec
 #define PCI_DEVICE_ID_REALTEK_8029	0x8029
 #define PCI_DEVICE_ID_REALTEK_8129	0x8129
+#define PCI_DEVICE_ID_REALTEK_8139	0x8139
 
 #define PCI_VENDOR_ID_TRUEVISION	0x10fa
 #define PCI_DEVICE_ID_TRUEVISION_T1000	0x000c
 
 #define PCI_VENDOR_ID_INIT		0x1101
 #define PCI_DEVICE_ID_INIT_320P		0x9100
+#define PCI_DEVICE_ID_INIT_360P		0x9500
 
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
@@ -537,8 +650,15 @@
 #define PCI_DEVICE_ID_VIA_82C576	0x0576
 #define PCI_DEVICE_ID_VIA_82C585	0x0585
 #define PCI_DEVICE_ID_VIA_82C586_0	0x0586
+#define PCI_DEVICE_ID_VIA_82C595	0x0595
+#define PCI_DEVICE_ID_VIA_82C597_0	0x0597
 #define PCI_DEVICE_ID_VIA_82C926	0x0926
 #define PCI_DEVICE_ID_VIA_82C416	0x1571
+#define PCI_DEVICE_ID_VIA_82C595_97	0x1595
+#define PCI_DEVICE_ID_VIA_82C586_2	0x3038
+#define PCI_DEVICE_ID_VIA_82C586_3	0x3040
+#define PCI_DEVICE_ID_VIA_86C100A	0x6100
+#define PCI_DEVICE_ID_VIA_82C597_1	0x8597
 
 #define PCI_VENDOR_ID_VORTEX		0x1119
 #define PCI_DEVICE_ID_VORTEX_GDT60x0	0x0000
@@ -555,6 +675,24 @@
 #define PCI_DEVICE_ID_VORTEX_GDT6x25	0x000b
 #define PCI_DEVICE_ID_VORTEX_GDT6535	0x000c
 #define PCI_DEVICE_ID_VORTEX_GDT6555	0x000d
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP	0x0100
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP	0x0101
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP	0x0102
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP	0x0103
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP	0x0104
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP	0x0105
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP1	0x0110
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP1	0x0111
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP1	0x0112
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP1	0x0113
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP1	0x0114
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP1	0x0115
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP2	0x0120
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP2	0x0121
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP2	0x0122
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP2	0x0123
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP2	0x0124
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP2	0x0125
 
 #define PCI_VENDOR_ID_EF		0x111a
 #define PCI_DEVICE_ID_EF_ATM_FPGA	0x0000
@@ -570,31 +708,46 @@
 #define PCI_VENDOR_ID_PHILIPS		0x1131
 #define PCI_DEVICE_ID_PHILIPS_SAA7146	0x7146
 
-#define PCI_VENDOR_ID_PLX		0x113c
-#define PCI_DEVICE_ID_PLX_9060		0x0001
+#define PCI_VENDOR_ID_CYCLONE		0x113c
+#define PCI_DEVICE_ID_CYCLONE_SDK	0x0001
 
 #define PCI_VENDOR_ID_ALLIANCE		0x1142
 #define PCI_DEVICE_ID_ALLIANCE_PROMOTIO	0x3210
 #define PCI_DEVICE_ID_ALLIANCE_PROVIDEO	0x6422
+#define PCI_DEVICE_ID_ALLIANCE_AT24	0x6424
+#define PCI_DEVICE_ID_ALLIANCE_AT3D	0x643d
 
 #define PCI_VENDOR_ID_VMIC		0x114a
 #define PCI_DEVICE_ID_VMIC_VME		0x7587
 
 #define PCI_VENDOR_ID_DIGI		0x114f
+#define PCI_DEVICE_ID_DIGI_EPC		0x0002
 #define PCI_DEVICE_ID_DIGI_RIGHTSWITCH	0x0003
+#define PCI_DEVICE_ID_DIGI_XEM		0x0004
+#define PCI_DEVICE_ID_DIGI_XR		0x0005
+#define PCI_DEVICE_ID_DIGI_CX		0x0006
+#define PCI_DEVICE_ID_DIGI_XRJ		0x0009
+#define PCI_DEVICE_ID_DIGI_EPCJ		0x000a
+#define PCI_DEVICE_ID_DIGI_XR_920	0x0027
 
 #define PCI_VENDOR_ID_MUTECH		0x1159
 #define PCI_DEVICE_ID_MUTECH_MV1000	0x0001
 
 #define PCI_VENDOR_ID_RENDITION		0x1163
 #define PCI_DEVICE_ID_RENDITION_VERITE	0x0001
+#define PCI_DEVICE_ID_RENDITION_VERITE2100 0x2000
 
 #define PCI_VENDOR_ID_TOSHIBA		0x1179
 #define PCI_DEVICE_ID_TOSHIBA_601	0x0601
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95	0x060a
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
 
 #define PCI_VENDOR_ID_RICOH		0x1180
 #define PCI_DEVICE_ID_RICOH_RL5C466	0x0466
 
+#define PCI_VENDOR_ID_ARTOP		0x1191
+#define PCI_DEVICE_ID_ARTOP_ATP850UF	0x0005
+
 #define PCI_VENDOR_ID_ZEITNET		0x1193
 #define PCI_DEVICE_ID_ZEITNET_1221	0x0001
 #define PCI_DEVICE_ID_ZEITNET_1225	0x0002
@@ -602,13 +755,22 @@
 #define PCI_VENDOR_ID_OMEGA		0x119b
 #define PCI_DEVICE_ID_OMEGA_82C092G	0x1221
 
+#define PCI_VENDOR_ID_LITEON		0x11ad
+#define PCI_DEVICE_ID_LITEON_LNE100TX	0x0002
+
 #define PCI_VENDOR_ID_NP		0x11bc
 #define PCI_DEVICE_ID_NP_PCI_FDDI	0x0001
 
+#define PCI_VENDOR_ID_ATT		0x11c1
+#define PCI_DEVICE_ID_ATT_L56XMF	0x0440
+
 #define PCI_VENDOR_ID_SPECIALIX		0x11cb
 #define PCI_DEVICE_ID_SPECIALIX_XIO	0x4000
 #define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
 
+#define PCI_VENDOR_ID_AURAVISION	0x11d1
+#define PCI_DEVICE_ID_AURAVISION_VXP524	0x01f7
+
 #define PCI_VENDOR_ID_IKON		0x11d5
 #define PCI_DEVICE_ID_IKON_10115	0x0115
 #define PCI_DEVICE_ID_IKON_10117	0x0117
@@ -617,6 +779,9 @@
 #define PCI_DEVICE_ID_ZORAN_36057	0x6057
 #define PCI_DEVICE_ID_ZORAN_36120	0x6120
 
+#define PCI_VENDOR_ID_KINETIC		0x11f4
+#define PCI_DEVICE_ID_KINETIC_2915	0x2915
+
 #define PCI_VENDOR_ID_COMPEX		0x11f6
 #define PCI_DEVICE_ID_COMPEX_ENET100VG4	0x0112
 #define PCI_DEVICE_ID_COMPEX_RL2000	0x1401
@@ -633,12 +798,28 @@
 #define PCI_DEVICE_ID_CYCLOM_Z_Lo	0x0200
 #define PCI_DEVICE_ID_CYCLOM_Z_Hi	0x0201
 
+#define PCI_VENDOR_ID_ESSENTIAL		0x120f
+#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER	0x0001
+
+#define PCI_VENDOR_ID_O2		0x1217
+#define PCI_DEVICE_ID_O2_6832		0x6832
+
 #define PCI_VENDOR_ID_3DFX		0x121a
 #define PCI_DEVICE_ID_3DFX_VOODOO	0x0001
+#define PCI_DEVICE_ID_3DFX_VOODOO2	0x0002
 
 #define PCI_VENDOR_ID_SIGMADES		0x1236
 #define PCI_DEVICE_ID_SIGMADES_6425	0x6401
 
+#define PCI_VENDOR_ID_CCUBE		0x123f
+
+#define PCI_VENDOR_ID_DIPIX		0x1246
+
+#define PCI_VENDOR_ID_STALLION		0x124d
+#define PCI_DEVICE_ID_STALLION_ECHPCI832 0x0000
+#define PCI_DEVICE_ID_STALLION_ECHPCI864 0x0002
+#define PCI_DEVICE_ID_STALLION_EIOPCI	0x0003
+
 #define PCI_VENDOR_ID_OPTIBASE		0x1255
 #define PCI_DEVICE_ID_OPTIBASE_FORGE	0x1110
 #define PCI_DEVICE_ID_OPTIBASE_FUSION	0x1210
@@ -646,6 +827,22 @@
 #define PCI_DEVICE_ID_OPTIBASE_VPLEXCC	0x2120
 #define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
 
+#define PCI_VENDOR_ID_SATSAGEM		0x1267
+#define PCI_DEVICE_ID_SATSAGEM_PCR2101	0x5352
+#define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
+
+#define PCI_VENDOR_ID_ENSONIQ		0x1274
+#define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI	0x5000
+
+#define PCI_VENDOR_ID_PICTUREL		0x12c5
+#define PCI_DEVICE_ID_PICTUREL_PCIVST	0x0081
+
+#define PCI_VENDOR_ID_NVIDIA_SGS	0x12d2
+#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
+
+#define PCI_VENDOR_ID_CBOARDS		0x1307
+#define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
+
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
 
@@ -657,6 +854,7 @@
 #define PCI_DEVICE_ID_3DLABS_500TX	0x0002
 #define PCI_DEVICE_ID_3DLABS_DELTA	0x0003
 #define PCI_DEVICE_ID_3DLABS_PERMEDIA	0x0004
+#define PCI_DEVICE_ID_3DLABS_MX		0x0006
 
 #define PCI_VENDOR_ID_AVANCE		0x4005
 #define PCI_DEVICE_ID_AVANCE_ALG2064	0x2064
@@ -683,6 +881,10 @@
 #define PCI_DEVICE_ID_S3_PLATO_PXG	0x8902
 #define PCI_DEVICE_ID_S3_ViRGE_DXGX	0x8a01
 #define PCI_DEVICE_ID_S3_ViRGE_GX2	0x8a10
+#define PCI_DEVICE_ID_S3_ViRGE_MX	0x8c01
+#define PCI_DEVICE_ID_S3_ViRGE_MXP	0x8c02
+#define PCI_DEVICE_ID_S3_ViRGE_MXPMV	0x8c03
+#define PCI_DEVICE_ID_S3_SONICVIBES	0xca00
 
 #define PCI_VENDOR_ID_INTEL		0x8086
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
@@ -702,6 +904,7 @@
 #define PCI_DEVICE_ID_INTEL_82371MX	0x1234
 #define PCI_DEVICE_ID_INTEL_82437MX	0x1235
 #define PCI_DEVICE_ID_INTEL_82441	0x1237
+#define PCI_DEVICE_ID_INTEL_82380FB	0x124b
 #define PCI_DEVICE_ID_INTEL_82439	0x1250
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
@@ -712,6 +915,11 @@
 #define PCI_DEVICE_ID_INTEL_82371AB	0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
 #define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
+#define PCI_DEVICE_ID_INTEL_82443LX_0	0x7180
+#define PCI_DEVICE_ID_INTEL_82443LX_1	0x7181
+#define PCI_DEVICE_ID_INTEL_82443BX_0	0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1	0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2	0x7192
 #define PCI_DEVICE_ID_INTEL_P6		0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
 
@@ -719,8 +927,10 @@
 #define PCI_DEVICE_ID_KTI_ET32P2	0x3000
 
 #define PCI_VENDOR_ID_ADAPTEC		0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810	0x1078
 #define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
 #define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
+#define PCI_DEVICE_ID_ADAPTEC_5800	0x5800
 #define PCI_DEVICE_ID_ADAPTEC_7860	0x6078
 #define PCI_DEVICE_ID_ADAPTEC_7861	0x6178
 #define PCI_DEVICE_ID_ADAPTEC_7870	0x7078
@@ -728,14 +938,22 @@
 #define PCI_DEVICE_ID_ADAPTEC_7872	0x7278
 #define PCI_DEVICE_ID_ADAPTEC_7873	0x7378
 #define PCI_DEVICE_ID_ADAPTEC_7874	0x7478
+#define PCI_DEVICE_ID_ADAPTEC_7895	0x7895
 #define PCI_DEVICE_ID_ADAPTEC_7880	0x8078
 #define PCI_DEVICE_ID_ADAPTEC_7881	0x8178
 #define PCI_DEVICE_ID_ADAPTEC_7882	0x8278
 #define PCI_DEVICE_ID_ADAPTEC_7883	0x8378
 #define PCI_DEVICE_ID_ADAPTEC_7884	0x8478
+#define PCI_DEVICE_ID_ADAPTEC_1030	0x8b78
 
 #define PCI_VENDOR_ID_ATRONICS		0x907f
 #define PCI_DEVICE_ID_ATRONICS_2015	0x2015
+
+#define PCI_VENDOR_ID_HOLTEK		0x9412
+#define PCI_DEVICE_ID_HOLTEK_6565	0x6565
+
+#define PCI_VENDOR_ID_TIGERJET		0xe159
+#define PCI_DEVICE_ID_TIGERJET_300	0x0001
 
 #define PCI_VENDOR_ID_ARK		0xedd8
 #define PCI_DEVICE_ID_ARK_STING		0xa091
diff -u --recursive --new-file v2.0.33/linux/include/linux/personality.h linux/include/linux/personality.h
--- v2.0.33/linux/include/linux/personality.h	Tue Aug 20 23:18:10 1996
+++ linux/include/linux/personality.h	Wed Jun  3 15:17:49 1998
@@ -8,12 +8,16 @@
 /* Flags for bug emulation. These occupy the top three bytes. */
 #define STICKY_TIMEOUTS		0x4000000
 #define WHOLE_SECONDS		0x2000000
+#define ADDR_MAX_32BIT		0x1000000
+#define ADDR_MAX_31BIT		0x0800000
 
 /* Personality types. These go in the low byte. Avoid using the top bit,
  * it will conflict with error returns.
  */
 #define PER_MASK		(0x00ff)
 #define PER_LINUX		(0x0000)
+#define PER_LINUX_32BIT		(PER_LINUX | ADDR_MAX_32BIT)
+#define PER_LINUX_EM86		(PER_LINUX | ADDR_MAX_31BIT)
 #define PER_SVR4		(0x0001 | STICKY_TIMEOUTS)
 #define PER_SVR3		(0x0002 | STICKY_TIMEOUTS)
 #define PER_SCOSVR3		(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
diff -u --recursive --new-file v2.0.33/linux/include/linux/smbno.h linux/include/linux/smbno.h
--- v2.0.33/linux/include/linux/smbno.h	Thu Apr 11 23:49:47 1996
+++ linux/include/linux/smbno.h	Wed Jun  3 15:17:49 1998
@@ -266,4 +266,19 @@
 #define TRANSACT2_FINDNOTIFYNEXT  12
 #define TRANSACT2_MKDIR           13
 
+
+/* Capabilities.  See ftp://ftp.microsoft.com/developr/drg/cifs/cifs6.txt */
+#define CAP_RAW_MODE         0x0001
+#define CAP_MPX_MODE         0x0002
+#define CAP_UNICODE          0x0004
+#define CAP_LARGE_FILES      0x0008
+#define CAP_NT_SMBS          0x0010
+#define CAP_RPC_REMOTE_APIS  0x0020
+#define CAP_STATUS32         0x0040
+#define CAP_LEVEL_II_OPLOCKS 0x0080
+#define CAP_LOCK_AND_READ    0x0100
+#define CAP_NT_FIND          0x0200
+#define CAP_DFS              0x1000
+#define CAP_LARGE_READX      0x4000
+
 #endif /* _SMBNO_H_ */
diff -u --recursive --new-file v2.0.33/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.0.33/linux/include/linux/swap.h	Mon Jun  3 05:38:37 1996
+++ linux/include/linux/swap.h	Wed Jun  3 15:17:50 1998
@@ -16,11 +16,14 @@
 
 #define SWAP_CLUSTER_MAX 32
 
+#define SWAP_MAP_MAX	  0xfffe	/* max val of swapinfo->swap_map[n] */
+#define SWAP_MAP_RESERVED 0xffff	/* max val of swapinfo->swap_map[n] */
+
 struct swap_info_struct {
 	unsigned int flags;
 	kdev_t swap_device;
 	struct inode * swap_file;
-	unsigned char * swap_map;
+	unsigned short * swap_map;
 	unsigned char * swap_lockmap;
 	int lowest_bit;
 	int highest_bit;
diff -u --recursive --new-file v2.0.33/linux/include/linux/xd.h linux/include/linux/xd.h
--- v2.0.33/linux/include/linux/xd.h	Thu Feb 29 21:50:56 1996
+++ linux/include/linux/xd.h	Wed Jun  3 15:17:50 1998
@@ -35,7 +35,7 @@
 #define CMD_SEEK	0x0B	/* seek */
 
 /* Controller specific commands */
-#define CMD_DTCSETPARAM	0x0C	/* set drive parameters (DTC 5150X only?) */
+#define CMD_DTCSETPARAM	0x0C	/* set drive parameters (DTC 5150X & CX only?) */
 #define CMD_DTCGETECC	0x0D	/* get ecc error length (DTC 5150X only?) */
 #define CMD_DTCREADBUF	0x0E	/* read sector buffer (DTC 5150X only?) */
 #define CMD_DTCWRITEBUF 0x0F	/* write sector buffer (DTC 5150X only?) */
@@ -46,6 +46,7 @@
 #define CMD_DTCGETGEOM	0xFF	/* get geometry data (DTC 5150X only?) */
 #define CMD_ST11GETGEOM 0xF8	/* get geometry data (Seagate ST11R/M only?) */
 #define CMD_WDSETPARAM	0x0C	/* set drive parameters (WD 1004A27X only?) */
+#define CMD_XBSETPARAM	0x0C	/* set drive parameters (XEBEC only?) */
 
 /* Bits for command status byte */
 #define CSB_ERROR	0x02	/* error */
@@ -85,7 +86,10 @@
 	u_char control;
 } XD_INFO;
 
-#define	HDIO_GETGEO	0x0301		/* get drive geometry */
+#define	HDIO_GETGEO		0x0301	/* get drive geometry */
+#define HDIO_GET_MULTCOUNT	0x0304	/* get limit of multiblock transfer */
+#define HDIO_SET_DMA		0x0326	/* change use-dma flag */
+#define HDIO_GET_DMA		0x030b	/* get use-dma flag */
 
 /* this structure is returned to the HDIO_GETGEO ioctl */
 typedef struct {
@@ -105,6 +109,9 @@
 } XD_SIGNATURE;
 
 void xd_setup (char *command,int *integers);
+#ifndef MODULE
+void xd_manual_geo_init (char *command,int *integers);
+#endif /* MODULE */
 static u_char xd_detect (u_char *controller,u_char **address);
 static u_char xd_initdrives (void (*init_drive)(u_char drive));
 static void xd_geninit (struct gendisk *);
@@ -120,11 +127,14 @@
 static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
 static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
 static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
+static void xd_wakeup (void);
+static void xd_watchdog (void);
 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
 static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
 
 /* card specific setup and geometry gathering code */
 static void xd_dtc_init_controller (u_char *address);
+static void xd_dtc5150cx_init_drive (u_char drive);
 static void xd_dtc_init_drive (u_char drive);
 static void xd_wd_init_controller (u_char *address);
 static void xd_wd_init_drive (u_char drive);
@@ -132,6 +142,8 @@
 static void xd_seagate_init_drive (u_char drive);
 static void xd_omti_init_controller (u_char *address);
 static void xd_omti_init_drive (u_char drive);
+static void xd_xebec_init_controller (u_char *address);
+static void xd_xebec_init_drive (u_char drive);
 static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
 static void xd_override_init_drive (u_char drive);
 
diff -u --recursive --new-file v2.0.33/linux/include/net/sock.h linux/include/net/sock.h
--- v2.0.33/linux/include/net/sock.h	Wed Oct 15 15:23:11 1997
+++ linux/include/net/sock.h	Wed Jun  3 15:17:50 1998
@@ -260,8 +260,7 @@
 						   'timed out' */
 	unsigned char		protocol;
 	volatile unsigned char	state;
-	unsigned char		ack_backlog;
-	unsigned char		max_ack_backlog;
+	unsigned short		ack_backlog;
 	unsigned char		priority;
 	unsigned char		debug;
 	int			rcvbuf;
@@ -340,7 +339,12 @@
 	void			(*data_ready)(struct sock *sk,int bytes);
 	void			(*write_space)(struct sock *sk);
 	void			(*error_report)(struct sock *sk);
-  
+
+  /*
+   *	Moved solely for 2.0 to keep binary module compatibility stuff straight.
+   */
+   
+	unsigned short		max_ack_backlog;  
 };
 
 /*
diff -u --recursive --new-file v2.0.33/linux/include/scsi/scsi.h linux/include/scsi/scsi.h
--- v2.0.33/linux/include/scsi/scsi.h	Mon Mar 31 13:27:42 1997
+++ linux/include/scsi/scsi.h	Wed Jun  3 15:17:50 1998
@@ -180,6 +180,8 @@
 /* Used to obtain the host number of a device. */
 #define SCSI_IOCTL_PROBE_HOST 0x5385
 
+/* Used to get the bus number for a device */
+#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.0.33/linux/include/scsi/scsi_ioctl.h linux/include/scsi/scsi_ioctl.h
--- v2.0.33/linux/include/scsi/scsi_ioctl.h	Mon Aug 11 13:37:24 1997
+++ linux/include/scsi/scsi_ioctl.h	Wed Jun  3 15:17:50 1998
@@ -19,6 +19,7 @@
 
 extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
 extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer);
 
 #endif
 
diff -u --recursive --new-file v2.0.33/linux/init/main.c linux/init/main.c
--- v2.0.33/linux/init/main.c	Thu Aug 14 10:30:08 1997
+++ linux/init/main.c	Wed Jun  3 15:17:50 1998
@@ -78,6 +78,7 @@
 extern void lp_setup(char *str, int *ints);
 extern void eth_setup(char *str, int *ints);
 extern void xd_setup(char *str, int *ints);
+extern void xd_manual_geo_init(char *str, int *ints);
 extern void floppy_setup(char *str, int *ints);
 extern void st_setup(char *str, int *ints);
 extern void st0x_setup(char *str, int *ints);
@@ -361,6 +362,7 @@
 #endif
 #ifdef CONFIG_BLK_DEV_XD
 	{ "xd=", xd_setup },
+	{ "xd_geo=", xd_manual_geo_init },
 #endif
 #ifdef CONFIG_BLK_DEV_FD
 	{ "floppy=", floppy_setup },
@@ -452,7 +454,7 @@
 static void load_ramdisk(char *str, int *ints)
 {
    if (ints[0] > 0 && ints[1] >= 0)
-      rd_doload = ints[1] & 1;
+      rd_doload = ints[1] & 3;
 }
 
 static void prompt_ramdisk(char *str, int *ints)
@@ -565,11 +567,26 @@
 		{ "hdb",     0x0340 },
 		{ "hdc",     0x1600 },
 		{ "hdd",     0x1640 },
+		{ "hde",     0x2100 },
+		{ "hdf",     0x2140 },
+		{ "hdg",     0x2200 },
+		{ "hdh",     0x2240 },
 		{ "sda",     0x0800 },
 		{ "sdb",     0x0810 },
 		{ "sdc",     0x0820 },
 		{ "sdd",     0x0830 },
 		{ "sde",     0x0840 },
+		{ "sdf",     0x0850 },
+		{ "sdg",     0x0860 },
+		{ "sdh",     0x0870 },
+		{ "sdi",     0x0880 },
+		{ "sdj",     0x0890 },
+		{ "sdk",     0x08a0 },
+		{ "sdl",     0x08b0 },
+		{ "sdm",     0x08c0 },
+		{ "sdn",     0x08d0 },
+		{ "sdo",     0x08e0 },
+		{ "sdp",     0x08f0 },
 		{ "fd",      0x0200 },
 		{ "xda",     0x0d00 },
 		{ "xdb",     0x0d40 },
diff -u --recursive --new-file v2.0.33/linux/ipc/shm.c linux/ipc/shm.c
--- v2.0.33/linux/ipc/shm.c	Mon Aug  4 15:25:11 1997
+++ linux/ipc/shm.c	Wed Jun  3 15:17:50 1998
@@ -494,10 +494,10 @@
 			return -EINVAL;
 	}
 	/*
-	 * Check if addr exceeds TASK_SIZE (from do_mmap)
+	 * Check if addr exceeds MAX_USER_ADDR (from do_mmap)
 	 */
 	len = PAGE_SIZE*shp->shm_npages;
-       if (addr >= TASK_SIZE || len > TASK_SIZE  || addr > TASK_SIZE - len)
+       if (addr >= MAX_USER_ADDR || len > MAX_USER_ADDR  || addr > MAX_USER_ADDR - len)
 		return -EINVAL;
 	/*
 	 * If shm segment goes below stack, make sure there is some
diff -u --recursive --new-file v2.0.33/linux/kernel/exit.c linux/kernel/exit.c
--- v2.0.33/linux/kernel/exit.c	Tue Mar 10 13:19:09 1998
+++ linux/kernel/exit.c	Wed Jun  3 15:17:50 1998
@@ -660,9 +660,14 @@
 			if (p->pgrp != -pid)
 				continue;
 		}
-		/* wait for cloned processes iff the __WCLONE flag is set */
-		if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
-			continue;
+		/* If you are tracing a process, then you don't need to get the
+		 * WCLONE bit right -- useful for strace and gdb
+		 */
+		if (!(p->flags & (PF_PTRACED|PF_TRACESYS))) {
+			/* wait for cloned processes iff the __WCLONE flag is set */
+			if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+				continue;
+		}
 		flag = 1;
 		switch (p->state) {
 			case TASK_STOPPED:
diff -u --recursive --new-file v2.0.33/linux/kernel/fork.c linux/kernel/fork.c
--- v2.0.33/linux/kernel/fork.c	Tue Mar 10 13:19:09 1998
+++ linux/kernel/fork.c	Wed Jun  3 15:17:50 1998
@@ -136,7 +136,9 @@
 			exit_mmap(mm);
 			goto free_mm;
 		}
+		down(&mm->mmap_sem);
 		if (dup_mmap(mm)) {
+			up(&mm->mmap_sem);
 			tsk->mm = NULL;
 			exit_mmap(mm);
 			free_page_tables(mm);
@@ -144,6 +146,7 @@
 			kfree(mm);
 			return -ENOMEM;
 		}
+		up(&mm->mmap_sem);
 		return 0;
 	}
 	SET_PAGE_DIR(tsk, current->mm->pgd);
diff -u --recursive --new-file v2.0.33/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.0.33/linux/kernel/ksyms.c	Tue Dec  2 13:52:33 1997
+++ linux/kernel/ksyms.c	Wed Jun  3 15:17:50 1998
@@ -87,6 +87,7 @@
 
 	/* stackable module support */
 	X(register_symtab_from),
+	X(get_module_symbol),
 #ifdef CONFIG_KERNELD
 	X(kerneld_send),
 #endif
@@ -162,6 +163,7 @@
 	X(__brelse),
 	X(__bforget),
 	X(ll_rw_block),
+	X(brw_page),
 	X(__wait_on_buffer),
 	X(mark_buffer_uptodate),
 	X(unlock_buffer),
diff -u --recursive --new-file v2.0.33/linux/kernel/module.c linux/kernel/module.c
--- v2.0.33/linux/kernel/module.c	Tue May 21 02:00:30 1996
+++ linux/kernel/module.c	Wed Jun  3 15:17:50 1998
@@ -86,7 +86,7 @@
 	int sspace = sizeof(struct module) + MOD_MAX_NAME;
 	char name[MOD_MAX_NAME];
 
-	if (!suser())
+	if (!suser() || securelevel > 0)
 		return -EPERM;
 	if (module_name == NULL || size == 0)
 		return -EINVAL;
@@ -138,7 +138,7 @@
 	int error;
 	struct mod_routines rt;
 
-	if (!suser())
+	if (!suser() || securelevel > 0)
 		return -EPERM;
 
 #ifdef __i386__
@@ -264,7 +264,7 @@
 	char name[MOD_MAX_NAME];
 	int error;
 
-	if (!suser())
+	if (!suser() || securelevel > 0)
 		return -EPERM;
 	/* else */
 	if (module_name != NULL) {
@@ -594,6 +594,36 @@
 	if (len > length)
 		len = length;
 	return len;
+}
+
+/*
+ * Gets the address for a symbol in the given module.  If modname is
+ * NULL, it looks for the name in any registered symbol table.  If the
+ * modname is an empty string, it looks for the symbol in kernel exported
+ * symbol tables.
+ */
+void *get_module_symbol(char *modname, char *symname)
+{
+	struct module *mp;
+	struct internal_symbol *sym;
+	int i;
+
+	for (mp = module_list; mp; mp = mp->next) {
+		if (((modname == NULL) || (strcmp(mp->name, modname) == 0)) &&
+			(mp->state == MOD_RUNNING) &&
+		    (mp->symtab != NULL) &&
+		    (mp->symtab->n_symbols > 0)) {
+			for (i = mp->symtab->n_symbols,
+				sym = mp->symtab->symbol;
+				i > 0; --i, ++sym) {
+
+				if (strcmp(sym->name, symname) == 0) {
+					return sym->addr;
+				}
+			}
+		}
+	}
+	return NULL;
 }
 
 /*
diff -u --recursive --new-file v2.0.33/linux/kernel/panic.c linux/kernel/panic.c
--- v2.0.33/linux/kernel/panic.c	Mon Aug  4 17:15:07 1997
+++ linux/kernel/panic.c	Wed Jun  3 15:17:50 1998
@@ -10,6 +10,7 @@
  */
 #include <stdarg.h>
 
+#include <linux/config.h> /* CONFIG_SCSI_GDTH */
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
diff -u --recursive --new-file v2.0.33/linux/kernel/sys.c linux/kernel/sys.c
--- v2.0.33/linux/kernel/sys.c	Mon Aug  4 17:15:07 1997
+++ linux/kernel/sys.c	Wed Jun  3 15:17:50 1998
@@ -171,7 +171,7 @@
 #endif
 
 extern void hard_reset_now(void);
-extern asmlinkage sys_kill(int, int);
+extern asmlinkage int sys_kill(int, int);
 
 /*
  * Reboot system call: for obvious reasons only root may call it,
@@ -663,7 +663,8 @@
 	int i;
 	int * groups;
 
-	if (gidsetsize < 0)
+	/* Avoid an integer overflow on systems with 32 bit gid_t (Alpha) */
+	if (gidsetsize & ~0x3FFFFFFF)
 		return -EINVAL;
 	groups = current->groups;
 	for (i = 0 ; i < NGROUPS ; i++) {
diff -u --recursive --new-file v2.0.33/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.0.33/linux/kernel/sysctl.c	Wed Aug 13 15:02:42 1997
+++ linux/kernel/sysctl.c	Wed Jun  3 15:17:50 1998
@@ -180,7 +180,7 @@
 	struct ctl_table_header *tmp;
 	void *context;
 	
-	if (nlen == 0 || nlen >= CTL_MAXNAME)
+	if (nlen <= 0 || nlen >= CTL_MAXNAME)
 		return -ENOTDIR;
 	
 	error = verify_area(VERIFY_READ,name,nlen*sizeof(int));
@@ -307,7 +307,8 @@
 	if (newval) 
 		op |= 002;
 	if (ctl_perm(table, op))
-		return -EPERM;
+		if( table->data != &securelevel || current->euid)
+			return -EPERM;
 
 	if (table->strategy) {
 		rc = table->strategy(table, name, nlen, oldval, oldlenp,
@@ -378,12 +379,13 @@
 	return tmp;
 }
 
-void unregister_sysctl_table(struct ctl_table_header * table)
+void unregister_sysctl_table(struct ctl_table_header * header)
 {
-	DLIST_DELETE(table, ctl_entry);
+	DLIST_DELETE(header, ctl_entry);
 #ifdef CONFIG_PROC_FS
-	unregister_proc_table(table->ctl_table, &proc_sys_root);
+	unregister_proc_table(header->ctl_table, &proc_sys_root);
 #endif
+	kfree(header);
 }
 
 /*
@@ -451,6 +453,7 @@
 			unregister_proc_table(table->child, de);
 		}
 		proc_unregister(root, de->low_ino);
+		table->de = NULL;
 		kfree(de);			
 	}
 }
diff -u --recursive --new-file v2.0.33/linux/kernel/time.c linux/kernel/time.c
--- v2.0.33/linux/kernel/time.c	Tue Dec  2 13:52:33 1997
+++ linux/kernel/time.c	Wed Jun  3 15:17:50 1998
@@ -20,6 +20,10 @@
  *	support for external PPS signal, error checking in adjtimex()
  *	Updated NTP code according to technical memorandum Jan '96
  *	"A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1998-03-05	Ulrich Windl
+ *	Allow time_constant larger than MAXTC(6) for NTP v4
+ *	(debated with and blessed by Dave Mills, despite of earlier work
+ *	and words)
  */
 
 #include <linux/errno.h>
@@ -270,7 +274,7 @@
 	    }
 
 	    if (txc.modes & ADJ_TIMECONST) {	/* p. 24 */
-		if (txc.constant < 0 || txc.constant > MAXTC) {
+		if (txc.constant < 0) {		/* NTP v4 uses values > 6 */
 		    error = -EINVAL;
 		    goto leave;
 		}
diff -u --recursive --new-file v2.0.33/linux/mm/filemap.c linux/mm/filemap.c
--- v2.0.33/linux/mm/filemap.c	Tue Mar 10 13:19:09 1998
+++ linux/mm/filemap.c	Wed Jun  3 15:17:50 1998
@@ -9,6 +9,7 @@
  * most "normal" filesystems (but you don't /have/ to use this:
  * the NFS filesystem does this differently, for example)
  */
+#include <linux/config.h> /* CONFIG_READA_SMALL */
 #include <linux/stat.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.0.33/linux/mm/mmap.c linux/mm/mmap.c
--- v2.0.33/linux/mm/mmap.c	Tue Dec  2 13:52:33 1997
+++ linux/mm/mmap.c	Wed Jun  3 15:17:50 1998
@@ -45,7 +45,7 @@
  * Check that a process has enough memory to allocate a
  * new virtual mapping.
  */
-static inline int vm_enough_memory(long pages)
+int vm_enough_memory(long pages)
 {
 	/*
 	 * stupid algorithm to decide if we have enough memory: while
@@ -147,7 +147,7 @@
 	if ((len = PAGE_ALIGN(len)) == 0)
 		return addr;
 
-	if (len > TASK_SIZE || addr > TASK_SIZE-len)
+	if (len > MAX_USER_ADDR || addr > MAX_USER_ADDR-len)
 		return -EINVAL;
 
 	/* offset overflow? */
@@ -178,6 +178,9 @@
 			 */
 			if (locks_verify_locked(file->f_inode))
 				return -EAGAIN;
+			/* cevans -- whoops another append-only file flaw */
+			if (IS_APPEND(file->f_inode) && (prot & PROT_WRITE))
+				return -EACCES;
 			/* fall through */
 		case MAP_PRIVATE:
 			if (!(file->f_mode & 1))
@@ -306,15 +309,15 @@
 {
 	struct vm_area_struct * vmm;
 
-	if (len > TASK_SIZE)
+	if (len > MAX_USER_ADDR)
 		return 0;
 	if (!addr)
-		addr = TASK_SIZE / 3;
+		addr = MMAP_SEARCH_START;
 	addr = PAGE_ALIGN(addr);
 
 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
 		/* At this point:  (!vmm || addr < vmm->vm_end). */
-		if (TASK_SIZE - len < addr)
+		if (MAX_USER_ADDR - len < addr)
 			return 0;
 		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
@@ -794,7 +797,7 @@
 {
 	struct vm_area_struct *mpnt, *prev, *next, **npp, *free;
 
-	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
+	if ((addr & ~PAGE_MASK) || addr > MAX_USER_ADDR || len > MAX_USER_ADDR-addr)
 		return -EINVAL;
 
 	if ((len = PAGE_ALIGN(len)) == 0)
diff -u --recursive --new-file v2.0.33/linux/mm/mremap.c linux/mm/mremap.c
--- v2.0.33/linux/mm/mremap.c	Fri Nov 22 06:25:17 1996
+++ linux/mm/mremap.c	Wed Jun  3 15:17:50 1998
@@ -19,6 +19,8 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 
+extern int vm_enough_memory(long pages);
+
 static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
 {
 	pgd_t * pgd;
@@ -173,7 +175,7 @@
 	 * Always allow a shrinking remap: that just unmaps
 	 * the unnecessary pages..
 	 */
-	if (old_len > new_len) {
+	if (old_len >= new_len) {
 		do_munmap(addr+new_len, old_len - new_len);
 		return addr;
 	}
@@ -196,11 +198,16 @@
 	if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
 	    > current->rlim[RLIMIT_AS].rlim_cur)
 		return -ENOMEM;
+	/* Private writable mapping? Check memory availability.. */
+	if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) {
+		if (!vm_enough_memory((new_len - old_len) >> PAGE_SHIFT))
+			return -ENOMEM;
+	}
 
 	/* old_len exactly to the end of the area.. */
 	if (old_len == vma->vm_end - addr &&
 	    (old_len != new_len || !(flags & MREMAP_MAYMOVE))) {
-		unsigned long max_addr = TASK_SIZE;
+		unsigned long max_addr = MAX_USER_ADDR;
 		if (vma->vm_next)
 			max_addr = vma->vm_next->vm_start;
 		/* can we just expand the current mapping? */
diff -u --recursive --new-file v2.0.33/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.0.33/linux/mm/swap_state.c	Wed Mar 13 05:17:23 1996
+++ linux/mm/swap_state.c	Wed Jun  3 15:17:50 1998
@@ -81,6 +81,12 @@
 	return (unsigned long) (swap_cache + swap_cache_size);
 }
 
+/* We shouldn't be able to have more processes sharing a swapped page than
+   we can count in the swap map */
+#if NR_TASKS > SWAP_MAP_MAX
+#error SWAP_MAP_MAX is too small
+#endif
+
 void swap_duplicate(unsigned long entry)
 {
 	struct swap_info_struct * p;
@@ -98,14 +104,16 @@
 	}
 	p = type + swap_info;
 	if (offset >= p->max) {
-		printk("swap_duplicate: weirdness\n");
-		return;
-	}
-	if (!p->swap_map[offset]) {
-		printk("swap_duplicate: trying to duplicate unused page\n");
+		printk("swap_duplicate: weirdness, entry %08lx\n", entry);
 		return;
 	}
-	p->swap_map[offset]++;
+	if (!p->swap_map[offset])
+		printk("swap_duplicate: trying to duplicate unused page, "
+		       "entry %08lx\n", entry);
+	else if (p->swap_map[offset] == SWAP_MAP_RESERVED)
+		printk("swap_duplicate: trying to duplicate reserved page, "
+		       "entry %08lx\n", entry);
+	else p->swap_map[offset]++;
 	return;
 }
 
diff -u --recursive --new-file v2.0.33/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.0.33/linux/mm/swapfile.c	Mon Mar 31 13:22:37 1997
+++ linux/mm/swapfile.c	Wed Jun  3 15:17:50 1998
@@ -145,9 +145,10 @@
 	if (offset > p->highest_bit)
 		p->highest_bit = offset;
 	if (!p->swap_map[offset])
-		printk("swap_free: swap-space map bad (entry %08lx)\n",entry);
-	else
-		if (!--p->swap_map[offset])
+		printk("swap_free: swap-space map null (entry %08lx)\n",entry);
+	else if (p->swap_map[offset] == SWAP_MAP_RESERVED)
+		printk("swap_free: swap-space reserved (entry %08lx)\n",entry);
+	else if (!--p->swap_map[offset])
 			nr_swap_pages++;
 	if (p->prio > swap_info[swap_list.next].prio) {
 	    swap_list.next = swap_list.head;
@@ -503,7 +504,7 @@
 		error = -EINVAL;
 		goto bad_swap;
 	}
-	p->swap_map = (unsigned char *) vmalloc(p->max);
+	p->swap_map = (unsigned short *) vmalloc(p->max * sizeof(short));
 	if (!p->swap_map) {
 		error = -ENOMEM;
 		goto bad_swap;
@@ -512,9 +513,9 @@
 		if (test_bit(i,p->swap_lockmap))
 			p->swap_map[i] = 0;
 		else
-			p->swap_map[i] = 0x80;
+			p->swap_map[i] = SWAP_MAP_RESERVED;
 	}
-	p->swap_map[0] = 0x80;
+	p->swap_map[0] = SWAP_MAP_RESERVED;
 	memset(p->swap_lockmap,0,PAGE_SIZE);
 	p->flags = SWP_WRITEOK;
 	p->pages = j;
@@ -562,7 +563,7 @@
 			continue;
 		for (j = 0; j < swap_info[i].max; ++j)
 			switch (swap_info[i].swap_map[j]) {
-				case 128:
+				case SWAP_MAP_RESERVED:
 					continue;
 				case 0:
 					++val->freeswap;
diff -u --recursive --new-file v2.0.33/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v2.0.33/linux/mm/vmalloc.c	Tue Mar 10 13:19:09 1998
+++ linux/mm/vmalloc.c	Wed Jun  3 15:17:50 1998
@@ -143,10 +143,8 @@
 		pte_t * pte = pte_alloc_kernel(pmd, address);
 		if (!pte)
 			return -ENOMEM;
-		if (alloc_area_pte(pte, address, end - address)) {
-			pte_free_kernel(pte);
+		if (alloc_area_pte(pte, address, end - address))
 			return -ENOMEM;
-		}
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	}
@@ -164,10 +162,8 @@
 		pmd_t *pmd = pmd_alloc_kernel(dir, address);
 		if (!pmd)
 			return -ENOMEM;
-		if (alloc_area_pmd(pmd, address, end - address)) {
-			pmd_free_kernel(pmd);
+		if (alloc_area_pmd(pmd, address, end - address))
 			return -ENOMEM;
-		}
 		set_pgdir(address, *dir);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
@@ -228,10 +224,8 @@
 		pmd_t *pmd = pmd_alloc_kernel(dir, address);
 		if (!pmd)
 			return -ENOMEM;
-		if (remap_area_pmd(pmd, address, end - address, offset + address)) {
-			pmd_free_kernel(pmd);
+		if (remap_area_pmd(pmd, address, end - address, offset + address))
 			return -ENOMEM;
-		}
 		set_pgdir(address, *dir);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
diff -u --recursive --new-file v2.0.33/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.0.33/linux/mm/vmscan.c	Tue Mar 10 13:19:09 1998
+++ linux/mm/vmscan.c	Wed Jun  3 15:17:50 1998
@@ -120,8 +120,6 @@
 			if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
 				kill_proc(pid, SIGBUS, 1);
 		} else {
-			if (page_map->count != 1)
-				return 0;
 			if (!(entry = get_swap_page()))
 				return 0;
 			vma->vm_mm->rss--;
diff -u --recursive --new-file v2.0.33/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.0.33/linux/net/ax25/af_ax25.c	Thu Nov 14 05:20:10 1996
+++ linux/net/ax25/af_ax25.c	Wed Jun  3 15:17:50 1998
@@ -1533,6 +1533,8 @@
 
 	newsk = skb->sk;
 	newsk->pair = NULL;
+	newsk->socket = newsock;
+	newsk->sleep = newsock->wait;
 	sti();
 
 	/* Now attach up the new socket */
diff -u --recursive --new-file v2.0.33/linux/net/core/dev.c linux/net/core/dev.c
--- v2.0.33/linux/net/core/dev.c	Tue Aug 12 14:15:56 1997
+++ linux/net/core/dev.c	Wed Jun  3 15:17:50 1998
@@ -225,7 +225,7 @@
 
 extern __inline__ void dev_load(const char *name)
 {
-	if(!dev_get(name)) {
+	if(!dev_get(name) && suser()) {
 #ifdef CONFIG_NET_ALIAS
 		const char *sptr;
  
@@ -1113,6 +1113,8 @@
 			{
 				int old_flags = dev->flags;
 				
+				if(securelevel>0)
+					ifr.ifr_flags&=~IFF_PROMISC;
 				/*
 				 *	We are not allowed to potentially close/unload
 				 *	a device until we get this lock.
@@ -1191,6 +1193,8 @@
 			{
 				if(dev->set_mac_address==NULL)
 					return -EOPNOTSUPP;
+				if(securelevel>0)
+					return -EPERM;
 				ret=dev->set_mac_address(dev,&ifr.ifr_addr);
 			}
 			else
@@ -1336,6 +1340,8 @@
 		case SIOCSIFHWADDR:
 			if(dev->set_mac_address==NULL)
 				return -EOPNOTSUPP;
+			if(securelevel > 0)
+				return -EPERM;
 			if(ifr.ifr_hwaddr.sa_family!=dev->type)
 				return -EINVAL;
 			ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr);
@@ -1523,9 +1529,6 @@
 	 *
 	 * Some devices want to be initialized early..
 	 */
-#if defined(CONFIG_LANCE)
-	lance_init();
-#endif
 #if defined(CONFIG_PI)
 	pi_init();
 #endif	
diff -u --recursive --new-file v2.0.33/linux/net/core/sock.c linux/net/core/sock.c
--- v2.0.33/linux/net/core/sock.c	Tue Dec  2 13:52:33 1997
+++ linux/net/core/sock.c	Wed Jun  3 15:17:50 1998
@@ -72,6 +72,7 @@
  *					easier (suggested by Craig Metz).
  *		Michael Pall	:	SO_ERROR returns positive errno again
  *              Elliot Poger    :       Added support for SO_BINDTODEVICE.
+ *		Russell King	:	Add #ifdef CONFIG_INET to SO_BINDTODEVICE
  *
  * To Fix:
  *
@@ -247,13 +248,13 @@
  				if(err)
  					return err;
  				memcpy_fromfs(&req,optval,sizeof(req));
-
+#ifdef CONFIG_INET
 				/* Remove any cached route for this socket. */
 				if (sk->ip_route_cache) {
 					ip_rt_put(sk->ip_route_cache);
 					sk->ip_route_cache=NULL;
 				}
-
+#endif
  				if (*(req.ifr_name) == '\0') {
  					sk->bound_device = NULL;
  				} else {
diff -u --recursive --new-file v2.0.33/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v2.0.33/linux/net/ethernet/eth.c	Mon Aug  5 00:13:55 1996
+++ linux/net/ethernet/eth.c	Wed Jun  3 15:17:50 1998
@@ -30,6 +30,8 @@
  *		Alan Cox	: Protect against forwarding explosions with
  *				  older network drivers and IFF_ALLMULTI.
  *	Christer Weinigel	: Better rebuild header message.
+ *		Russell King	: eth_header_cache_bind and eth_header_cache_update
+ *				  only compiled if CONFIG_INET is selected
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -218,6 +220,7 @@
 	return htons(ETH_P_802_2);
 }
 
+#ifdef CONFIG_INET
 /*
  * Upper level calls this function to bind hardware header cache entry.
  * If the call is successful, then corresponding Address Resolution Protocol
@@ -258,6 +261,7 @@
 	memcpy(hh->hh_data, haddr, ETH_ALEN);
 	hh->hh_uptodate = 1;
 }
+#endif
 
 /*
  *	Copy from an ethernet device memory space to an sk_buff while checksumming if IP
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v2.0.33/linux/net/ipv4/Config.in	Tue Aug 12 11:30:25 1997
+++ linux/net/ipv4/Config.in	Wed Jun  3 15:17:50 1998
@@ -4,9 +4,9 @@
 bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD
 bool 'IP: multicasting' CONFIG_IP_MULTICAST
 bool 'IP: syn cookies' CONFIG_SYN_COOKIES
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'IP: rst cookies' CONFIG_RST_COOKIES
-fi
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#  bool 'IP: rst cookies' CONFIG_RST_COOKIES
+#fi
 if [ "$CONFIG_FIREWALL" = "y" ]; then
   bool 'IP: firewalling' CONFIG_IP_FIREWALL
   if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
@@ -15,7 +15,7 @@
       if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
         comment 'Protocol-specific masquerading support will be built as modules.'
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then	
-          bool 'IP: ipautofw masq support' CONFIG_IP_MASQUERADE_IPAUTOFW
+          bool 'IP: ipautofw masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
         fi
         bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
       fi
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.0.33/linux/net/ipv4/af_inet.c	Fri Aug 15 12:23:23 1997
+++ linux/net/ipv4/af_inet.c	Wed Jun  3 15:17:50 1998
@@ -838,8 +838,6 @@
 		__u32 addr = sk->rcv_saddr;
 		if (!addr) {
 			addr = sk->saddr;
-			if (!addr)
-				addr = ip_my_addr();
 		}
 		sin->sin_port = sk->dummy_th.source;
 		sin->sin_addr.s_addr = addr;
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.0.33/linux/net/ipv4/arp.c	Wed Sep 17 12:00:47 1997
+++ linux/net/ipv4/arp.c	Wed Jun  3 15:17:50 1998
@@ -739,7 +739,7 @@
 	unsigned long now = jiffies;
 	int result = 0;
 
-	static last_index;
+	static int last_index;
 
 	if (ARP_LOCKED())
 		return 0;
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.0.33/linux/net/ipv4/icmp.c	Mon Sep 15 09:54:52 1997
+++ linux/net/ipv4/icmp.c	Wed Jun  3 15:17:50 1998
@@ -665,16 +665,16 @@
 			case ICMP_HOST_UNREACH:
 				break;
 			case ICMP_PROT_UNREACH:
-/*				printk(KERN_INFO "ICMP: %s:%d: protocol unreachable.\n",
-					in_ntoa(iph->daddr), (int)iph->protocol);*/
+				NETDEBUG(printk(KERN_INFO "ICMP: %s:%d: protocol unreachable.\n",
+					in_ntoa(iph->daddr), (int)iph->protocol));
 			/* Drop through */
 			case ICMP_PORT_UNREACH:
 				match_addr=1;
 				break;
 			case ICMP_FRAG_NEEDED:
 #ifdef CONFIG_NO_PATH_MTU_DISCOVERY
-				printk(KERN_INFO "ICMP: %s: fragmentation needed and DF set.\n",
-								in_ntoa(iph->daddr));
+				NETDEBUG(printk(KERN_INFO "ICMP: %s: fragmentation needed and DF set.\n",
+								in_ntoa(iph->daddr))); 
 				break;
 #else
 			{
@@ -745,7 +745,7 @@
 			}
 #endif
 			case ICMP_SR_FAILED:
-				printk(KERN_INFO "ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
+				NETDEBUG(printk(KERN_INFO "ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr)));
 				break;
 			default:
 				break;
@@ -864,12 +864,12 @@
 			 *	(not some confused thing sending our
 			 *	address)
 			 */
-			printk(KERN_INFO "ICMP redirect from %s\n", in_ntoa(source));
+			NETDEBUG(printk(KERN_INFO "ICMP redirect from %s\n", in_ntoa(source)));
 			ip_rt_redirect(source, ip, icmph->un.gateway, dev);
 			break;
 		case ICMP_REDIR_NETTOS:
 		case ICMP_REDIR_HOSTTOS:
-			printk(KERN_INFO "ICMP: cannot handle TOS redirects yet!\n");
+			NETDEBUG(printk(KERN_INFO "ICMP: cannot handle TOS redirects yet!\n"));
 			break;
 		default:
 			break;
@@ -1059,7 +1059,7 @@
 	if(len < sizeof(struct icmphdr))
 	{
 		icmp_statistics.IcmpInErrors++;
-		printk(KERN_INFO "ICMP: runt packet\n");
+		NETDEBUG(printk(KERN_INFO "ICMP: runt packet\n"));
 		kfree_skb(skb, FREE_READ);
 		return 0;
 	}
@@ -1072,7 +1072,7 @@
 	{
 		/* Failed checksum! */
 		icmp_statistics.IcmpInErrors++;
-		printk(KERN_INFO "ICMP: failed checksum from %s!\n", in_ntoa(saddr));
+		NETDEBUG(printk(KERN_INFO "ICMP: failed checksum from %s!\n", in_ntoa(saddr)));
 		kfree_skb(skb, FREE_READ);
 		return(0);
 	}
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.0.33/linux/net/ipv4/igmp.c	Thu Nov 14 05:20:10 1996
+++ linux/net/ipv4/igmp.c	Wed Jun  3 15:17:50 1998
@@ -64,6 +64,9 @@
  *		Alexey Kuznetsov:	Wrong group leaving behaviour, backport
  *					fix from pending 2.1.x patches.
  *		Alan Cox:		Forget to enable FDDI support earlier.
+ *     Elena Apolinario Fdez de Sousa,: IGMP Leave Messages must be sent to
+ *     Juan-Mariano de Goyeneche        the "all routers" group, not the group
+ *					group being left.
  */
 
 
@@ -424,7 +427,9 @@
 extern __inline__ void igmp_group_dropped(struct ip_mc_list *im)
 {
 	del_timer(&im->timer);
-	igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
+        /* It seems we have to send Leave Messages to 224.0.0.2 and not to
+           the group itself, to remain RFC 2236 compliant... (jmel) */
+        igmp_send_report(im->interface, IGMP_ALL_ROUTER, IGMP_HOST_LEAVE_MESSAGE);
 	ip_mc_filter_del(im->interface, im->multiaddr);
 }
 
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.0.33/linux/net/ipv4/ip_forward.c	Tue Mar 10 13:19:09 1998
+++ linux/net/ipv4/ip_forward.c	Wed Jun  3 15:17:50 1998
@@ -323,7 +323,7 @@
 #ifdef CONFIG_IP_MASQUERADE
 		__u32	premasq_saddr = iph->saddr;
 		__u16	premasq_sport = 0;
-		__u16	*portptr;
+		__u16	*portptr=NULL;
 		long	premasq_len_diff = skb->len;
 
 		if (iph->protocol==IPPROTO_UDP ||
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.0.33/linux/net/ipv4/ip_fragment.c	Tue Dec  2 13:52:33 1997
+++ linux/net/ipv4/ip_fragment.c	Wed Jun  3 15:17:50 1998
@@ -345,7 +345,7 @@
 	
 	if(len>65535)
 	{
-		printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr));
+		NETDEBUG(printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr)));
 		ip_statistics.IpReasmFails++;
 		ip_free(qp);
 		return NULL;
@@ -375,7 +375,7 @@
 	fp = qp->fragments;
 	while(fp != NULL)
 	{
-		if (fp->len < 0 || count+fp->len > skb->len)
+		if (fp->len < 0 || fp->offset+qp->ihlen+fp->len > skb->len)
 		{
 			NETDEBUG(printk("Invalid fragment list: Fragment over size.\n"));
 			ip_free(qp);
@@ -489,7 +489,7 @@
 	if(ntohs(iph->tot_len)+(int)offset>65535)
 	{
 		skb->sk = NULL;
-		printk("Oversized packet received from %s\n",in_ntoa(iph->saddr));
+		NETDEBUG(printk("Oversized packet received from %s\n",in_ntoa(iph->saddr)));
 		kfree_skb(skb, FREE_READ);
 		ip_statistics.IpReasmFails++;
 		return NULL;
@@ -698,7 +698,7 @@
 	if(mtu<8)
 	{
 		/* It's wrong but it's better than nothing */
-		icmp_send(skb,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,dev->mtu, dev);
+		icmp_send(skb,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,htons(dev->mtu), dev);
 		ip_statistics.IpFragFails++;
 		return;
 	}
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v2.0.33/linux/net/ipv4/ip_masq.c	Tue Aug  5 10:44:26 1997
+++ linux/net/ipv4/ip_masq.c	Wed Jun  3 15:17:50 1998
@@ -762,13 +762,16 @@
                 ip_masq_set_expire(ms,0);
                 
                 /*
-                 *	If sysctl !=0 and no pkt has been received yet
-                 *	in this tunnel and routing iface address has changed...
-                 *	 "You are welcome, diald".
+                 *	If sysctl & 3 and either
+		 *        no pkt has been received yet
+		 *      or
+		 *        sysctl & 4
+                 *	in this tunnel ...
+                 *	 "You are welcome, diald, ipppd, pppd-3.3...".
                  */
-                if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && dev->pa_addr != ms->maddr) {
+                if ( (sysctl_ip_dynaddr & 3) && (ms->flags & IP_MASQ_F_NO_REPLY || sysctl_ip_dynaddr & 4) && dev->pa_addr != ms->maddr) {
                         unsigned long flags;
-                        if (sysctl_ip_dynaddr > 1) {
+                        if (sysctl_ip_dynaddr & 2) {
                                 printk(KERN_INFO "ip_fw_masquerade(): change maddr from %s",
                                        in_ntoa(ms->maddr));
                                 printk(" to %s\n", in_ntoa(dev->pa_addr));
@@ -971,11 +974,14 @@
 		/* Rewrite source address */
                 
                 /*
-                 *	If sysctl !=0 and no pkt has been received yet
-                 *	in this tunnel and routing iface address has changed...
-                 *	 "You are welcome, diald".
+                 *	If sysctl & 3 and either
+		 *        no pkt has been received yet
+		 *      or
+		 *        sysctl & 4
+                 *	in this tunnel ...
+                 *	 "You are welcome, diald, ipppd, pppd-3.3...".
                  */
-                if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && dev->pa_addr != ms->maddr) {
+                if ( (sysctl_ip_dynaddr & 3) && (ms->flags & IP_MASQ_F_NO_REPLY || sysctl_ip_dynaddr & 4) && dev->pa_addr != ms->maddr) {
                         unsigned long flags;
 #ifdef DEBUG_CONFIG_IP_MASQUERADE
                         printk(KERN_INFO "ip_fw_masq_icmp(): change masq.addr %s",
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.0.33/linux/net/ipv4/ip_output.c	Mon Sep 15 09:53:36 1997
+++ linux/net/ipv4/ip_output.c	Wed Jun  3 15:17:50 1998
@@ -28,6 +28,8 @@
  *					output firewall rules)
  *              Elliot Poger    :       Added support for SO_BINDTODEVICE.
  *		Juan Jose Ciarlante:	sk/skb source address rewriting
+ * 	Elena Apolinario Fdez de Sousa,:ipmr_forward never received multicast
+ *	Juan-Mariano de Goyeneche	traffic generated locally.
  */
 
 #include <asm/segment.h>
@@ -69,7 +71,9 @@
 
 /*
  *	Allows dynamic re-writing of packet's addresses.
- *	if value > 1, be verbose about addr rewriting.
+ *      value & 3    do rewrite
+ *      value & 2    be verbose
+ *      value & 4    rewrite connected sockets too
  *	Currently implemented:
  *		tcp_output.c   if sk->state!=TCP_SYN_SENT
  *		ip_masq.c      if no packet has been received by tunnel
@@ -79,7 +83,8 @@
 /*
  *	Very Promisc source address re-assignation.
  *	ONLY acceptable if socket is NOT connected yet.
- *      Caller already checked sysctl_ip_dynaddr != 0 and consistent sk->state
+ *      Caller already checked sysctl_ip_dynaddr & 3 and EITHER
+ *      sysctl_ip_dynaddr & 4 OR consistent sk->state
  *	 (TCP_SYN_SENT for tcp, udp-connect sockets are set TCP_ESTABLISHED)
  */
 
@@ -107,12 +112,12 @@
         }
         
         /*
-         *	Be verbose if sysctl value > 1
+         *	Be verbose if sysctl value & 2
          */
-        if (sysctl_ip_dynaddr > 1) {
+        if (sysctl_ip_dynaddr & 2) {
                 printk(KERN_INFO "ip_rewrite_addrs(): shifting saddr from %s",
                        in_ntoa(skb->saddr));
-                printk(" to %s\n", in_ntoa(new_saddr));
+                printk(" to %s (state %d)\n", in_ntoa(new_saddr), sk->state);
         }
         
         iph = skb->ip_hdr;
@@ -121,7 +126,7 @@
                 iph->saddr = new_saddr;
                 skb->saddr = new_saddr;
                 ip_send_check(iph);
-        } else if (sysctl_ip_dynaddr > 1) {
+        } else if (sysctl_ip_dynaddr & 2) {
                 printk(KERN_WARNING "ip_rewrite_addrs(): skb already changed (???).\n");
                 return 0;
         }
@@ -134,7 +139,7 @@
                 sk->saddr = new_saddr;
                 sk->rcv_saddr = new_saddr;
                 sk->prot->rehash(sk);
-        } else if (sysctl_ip_dynaddr > 1)
+        } else if (sysctl_ip_dynaddr & 2)
                 printk(KERN_NOTICE "ip_rewrite_addrs(): no change needed for sock\n");
         return 1;
 }
@@ -996,6 +1001,22 @@
 	 
 		if (MULTICAST(daddr) && !(dev->flags&IFF_LOOPBACK)) 
 		{
+#ifdef CONFIG_IP_MROUTE
+		/* We need this so that mrouted "hears" packets sent from the
+		   same host it is running on... (jmel) */
+                if (mroute_socket&&(iph->protocol!=IPPROTO_IGMP))
+                {
+			if((skb->ip_hdr->daddr&htonl(0xFFFFFF00))!=htonl(0xE0000000)) 
+			{ 
+				struct sk_buff* skb2=skb_clone(skb, GFP_ATOMIC);                                
+				if(skb2)
+                       		{
+                       		        skb2->free=1;
+                       		        ipmr_forward(skb2, 0);
+                       	 	}
+			}
+                }
+#endif
 			/*
 			 *	Loop back any frames. The check for IGMP_ALL_HOSTS is because
 			 *	you are always magically a member of this group.
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.0.33/linux/net/ipv4/proc.c	Tue Apr  8 08:47:47 1997
+++ linux/net/ipv4/proc.c	Wed Jun  3 15:17:50 1998
@@ -29,6 +29,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  */
+#include <linux/config.h>
 #include <asm/system.h>
 #include <linux/sched.h>
 #include <linux/socket.h>
@@ -166,6 +167,10 @@
  */
 int afinet_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
+#ifdef CONFIG_SYN_COOKIES
+	extern unsigned int ui_c_send_cookies;
+	static unsigned int ui_c_last_send_cookies = 0;
+#endif	
 	/* From  net/socket.c  */
 	extern int socket_get_info(char *, char **, off_t, int);
 	extern struct proto packet_prot;
@@ -180,6 +185,13 @@
 		       raw_prot.inuse, raw_prot.highestinuse);
 	len += sprintf(buffer+len,"PAC: inuse %d highest %d\n",
 		       packet_prot.inuse, packet_prot.highestinuse);
+ 
+#if defined(CONFIG_SYN_COOKIES)
+	len += sprintf(buffer+len,"SYN_COOKIES: count %u since_last_check %u\n",
+        	ui_c_send_cookies, (ui_c_send_cookies - ui_c_last_send_cookies));
+
+	ui_c_last_send_cookies = ui_c_send_cookies;
+#endif
 	*start = buffer + offset;
 	len -= offset;
 	if (len > length)
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v2.0.33/linux/net/ipv4/rarp.c	Tue Dec  2 13:52:33 1997
+++ linux/net/ipv4/rarp.c	Wed Jun  3 15:17:50 1998
@@ -28,7 +28,9 @@
  * Fixes
  *	Alan Cox	:	Rarp delete on device down needed as
  *				reported by Walter Wolfgang.
- *  Lawrence V. Stefani : Added FDDI support.
+ *  Lawrence V. Stefani :	Added FDDI support.
+ *      San Mehat	:	Fixed bug where rarp would fail to build
+ *				if procfs was not compiled into the kernel
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.0.33/linux/net/ipv4/raw.c	Tue Apr  8 08:47:47 1997
+++ linux/net/ipv4/raw.c	Wed Jun  3 15:17:50 1998
@@ -425,6 +425,7 @@
 		mroute_socket=NULL;
 	}
 #endif	
+	sk->dead=1;
 	destroy_sock(sk);
 }
 
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.0.33/linux/net/ipv4/route.c	Tue Mar 10 13:19:09 1998
+++ linux/net/ipv4/route.c	Wed Jun  3 15:17:50 1998
@@ -905,7 +905,7 @@
 		restore_flags(flags);
 		if (hh && atomic_dec_and_test(&hh->hh_refcnt))
 			kfree_s(hh, sizeof(struct hh_cache));
-		kfree_s(rt, sizeof(struct rt_table));
+		kfree_s(rt, sizeof(struct rtable));
 		return;
 	}
 	rt->rt_next = rt_free_queue;
@@ -943,7 +943,7 @@
 			sti();
 			if (hh && atomic_dec_and_test(&hh->hh_refcnt))
 				kfree_s(hh, sizeof(struct hh_cache));
-			kfree_s(rt, sizeof(struct rt_table));
+			kfree_s(rt, sizeof(struct rtable));
 #if RT_CACHE_DEBUG >= 2
 			printk("rt_kick_free_queue: %08x is free\n", daddr);
 #endif
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.0.33/linux/net/ipv4/tcp.c	Sun Aug 17 13:35:10 1997
+++ linux/net/ipv4/tcp.c	Wed Jun  3 15:17:50 1998
@@ -740,16 +740,8 @@
 
 	if (type == ICMP_SOURCE_QUENCH)
 	{
-		/*
-		 * FIXME:
-		 * Follow BSD for now and just reduce cong_window to 1 again.
-		 * It is possible that we just want to reduce the
-		 * window by 1/2, or that we want to reduce ssthresh by 1/2
-		 * here as well.
-		 */
-		sk->cong_window = 1;
-		sk->cong_count = 0;
-		sk->high_seq = sk->sent_seq;
+		/* Current practice says these frames are bad, plus the drops
+		   will account right anyway. If we act on this we stall doubly */
 		return;
 	}
 
@@ -2075,9 +2067,11 @@
 	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
 		current->state = TASK_INTERRUPTIBLE;
+		end_bh_atomic();
 		release_sock(sk);
 		schedule();
 		lock_sock(sk);
+		start_bh_atomic();
 		skb = tcp_find_established(sk);
 		if (skb)
 			break;
@@ -2109,7 +2103,7 @@
 	if (sk->state != TCP_LISTEN)
 		goto no_listen;
 
-	lock_sock(sk);
+	lock_sock(sk);start_bh_atomic();
 
 	skb = tcp_find_established(sk);
 	if (skb) {
@@ -2120,6 +2114,7 @@
 		sk->ack_backlog--;
 		error = 0;
 out:
+		end_bh_atomic();
 		release_sock(sk);
 no_listen:
 		sk->err = error;
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.33/linux/net/ipv4/tcp_input.c	Tue Dec  2 13:52:33 1997
+++ linux/net/ipv4/tcp_input.c	Wed Jun  3 15:17:50 1998
@@ -216,6 +216,7 @@
  *	(e.g. long delay packet radio links, 1200 baud modems.)
  */
 static __u32 cookie_mtu[8] = { 64, 256, 512, 536, 1024, 1440, 1460, 4312 };
+unsigned int ui_c_send_cookies = 0;
 #endif
 
 extern void tcp_v4_hash(struct sock *sk);
@@ -594,6 +595,7 @@
 #endif
 #ifdef CONFIG_SYN_COOKIES
 			send_cookie = 1;
+			ui_c_send_cookies++;
 #else
 			/* If we only have RST cookies we should
 			 * not drop through to the rest of the response code.
@@ -1723,7 +1725,7 @@
 		if(sk->ip_xmit_timeout==TIME_KEEPOPEN)
 			tcp_reset_xmit_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
 	}
-	return 1;
+	return 0;
 }
 
 
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.0.33/linux/net/ipv4/tcp_output.c	Wed Oct 15 14:47:56 1997
+++ linux/net/ipv4/tcp_output.c	Wed Jun  3 15:17:50 1998
@@ -370,7 +370,7 @@
                          * a packet that contains both old and new data. (Feh!)
                          * Soooo, we have this uglyness here.
                          */
-			if (after(sk->rcv_ack_seq,skb->seq+th->syn+th->fin))
+			if (after(sk->rcv_ack_seq,skb->seq+th->syn))
 				tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);
 
 			size = skb->len - (((unsigned char *) th) - skb->data);
@@ -487,6 +487,21 @@
 
 		iph = (struct iphdr *)skb->data;
 		th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2));
+
+		/* See if we need to shrink the leading packet on
+		 * the retransmit queue. Strictly speaking, we
+		 * should never need to do this, but some buggy TCP
+		 * implementations get confused if you send them
+		 * a packet that contains both old and new data. (Feh!)
+		 * Soooo, we have this uglyness here.
+		 *
+		 * Is the && test needed here? If so, then it implies that
+		 * we might be retransmitting an acked packet. This code is
+		 * needed here to talk to Solaris 2.6 stack.
+		 */
+		if (after(sk->rcv_ack_seq,skb->seq+th->syn) && before(sk->rcv_ack_seq, skb->end_seq))
+			tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);
+
 		size = ntohs(iph->tot_len) - (iph->ihl<<2);
 		
 		/*
@@ -546,7 +561,7 @@
 				struct sk_buff *skb2 = sk->write_queue.next;
 				while (skb2 && skb2->dev == skb->dev) {
 					skb2->raddr=rt->rt_gateway;
-                                        if (sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr)
+                                        if (sysctl_ip_dynaddr & 4 || (sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr & 3))
                                                 ip_rewrite_addrs (sk, skb2, dev);
 					skb_pull(skb2,((unsigned char *)skb2->ip_hdr)-skb2->data);
 					skb2->dev = dev;
@@ -572,7 +587,7 @@
 				}
 			}
 			skb->raddr=rt->rt_gateway;
-                        if (skb->dev !=dev && sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr)
+			if ((skb->dev !=dev || skb->dev->pa_addr != skb->ip_hdr->saddr) && (sysctl_ip_dynaddr & 4 || (sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr & 3)))
                                 ip_rewrite_addrs(sk, skb, dev);
 			skb->dev=dev;
 			skb->arp=1;
@@ -820,6 +835,7 @@
 	t1->urg = 0;
 	t1->rst = 0;
 	t1->psh = 0;
+	t1->fin = 0;		/* In case someone sent us a SYN|FIN frame! */
 	t1->doff = sizeof(*t1)/4;
 
 	tcp_send_check(t1, saddr, daddr, sizeof(*t1), buff);
@@ -1398,6 +1414,10 @@
  * Needed to deal with buggy TCP implementations that can't deal
  * with seeing a packet that contains some data that has already
  * been received.
+ *
+ * Note that the SYN sequence number is at the start of the packet
+ * while the FIN is at the end. This means that we always clear out
+ * the SYN bit, and never clear out the FIN bit.
  */
 void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack)
 {
@@ -1415,9 +1435,9 @@
 	th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2));
 
 	/* how much data are we droping from the tcp frame */
-	diff = ack - skb->seq;
+	diff = ack - (skb->seq + th->syn);
 	/* how much data are we keeping in the tcp frame */
-	len = (skb->end_seq - (th->fin + th->syn)) - ack;
+	len = (skb->end_seq - th->fin) - ack;
 
 	/* pointers to new start of remaining data, and old start */
 	new = (unsigned char *)th + th->doff*4;
@@ -1426,6 +1446,7 @@
 	/* Update our starting seq number */
 	skb->seq = ack;
 	th->seq = htonl(ack);
+	th->syn = 0;		/* Turn SYN off as it is logically at the start of the packet */
 
 	iph->tot_len = htons(ntohs(iph->tot_len)-diff);
 	ip_send_check(iph);
diff -u --recursive --new-file v2.0.33/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.0.33/linux/net/ipx/af_ipx.c	Tue Aug 12 11:30:39 1997
+++ linux/net/ipx/af_ipx.c	Wed Jun  3 15:17:50 1998
@@ -1283,6 +1283,9 @@
 	 */
 
 	__u32 i=length>>1;
+	char    hops = packet->ipx_tctrl;
+
+	packet->ipx_tctrl = 0;     /* hop count excluded from checksum calc */
 
 	/*
 	 *	Loop through all complete words except the checksum field 
@@ -1298,6 +1301,7 @@
 	if(packet->ipx_pktsize&htons(1))
 		sum+=ntohs(0xff00)&*p;
 
+	packet->ipx_tctrl = hops;
 	/*
 	 *	Do final fixup 
 	 */
diff -u --recursive --new-file v2.0.33/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.0.33/linux/net/netrom/af_netrom.c	Sat Aug 10 00:03:16 1996
+++ linux/net/netrom/af_netrom.c	Wed Jun  3 15:17:50 1998
@@ -908,6 +908,8 @@
 
 	newsk = skb->sk;
 	newsk->pair = NULL;
+	newsk->socket = newsock;
+	newsk->sleep = newsock->wait;
 	sti();
 
 	/* Now attach up the new socket */
diff -u --recursive --new-file v2.0.33/linux/net/netsyms.c linux/net/netsyms.c
--- v2.0.33/linux/net/netsyms.c	Tue Mar 10 13:19:09 1998
+++ linux/net/netsyms.c	Wed Jun  3 15:17:50 1998
@@ -13,6 +13,7 @@
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
 #include <linux/ioport.h>
+#include <net/sock.h>
 
 #ifdef CONFIG_AX25
 #include <net/ax25.h>
diff -u --recursive --new-file v2.0.33/linux/net/socket.c linux/net/socket.c
--- v2.0.33/linux/net/socket.c	Mon Jul 15 01:31:51 1996
+++ linux/net/socket.c	Wed Jun  3 15:17:50 1998
@@ -588,7 +588,7 @@
 	if ((fd = get_fd(SOCK_INODE(sock))) < 0) 
 	{
 		sock_release(sock);
-		return(-EINVAL);
+		return fd;
 	}
 
 	sock->file=current->files->fd[fd];
diff -u --recursive --new-file v2.0.33/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.0.33/linux/net/unix/af_unix.c	Sat Nov  9 00:53:54 1996
+++ linux/net/unix/af_unix.c	Wed Jun  3 15:17:50 1998
@@ -28,6 +28,7 @@
  *		Nick Nevin	:	recvmsg bugfix.
  *		Alan Cox	:	Started proper garbage collector
  *		Heiko EiBfeldt	:	Missing verify_area check
+ *		Alan Cox	:	Shutdown() bug
  *
  * Known differences from reference BSD that was tested:
  *
@@ -1155,6 +1156,9 @@
 {
 	unix_socket *sk=(unix_socket *)sock->data;
 	unix_socket *other=sk->protinfo.af_unix.other;
+	
+	mode++;
+	
 	if(mode&SEND_SHUTDOWN)
 	{
 		sk->shutdown|=SEND_SHUTDOWN;
diff -u --recursive --new-file v2.0.33/linux/scripts/Configure linux/scripts/Configure
--- v2.0.33/linux/scripts/Configure	Sun Aug  3 15:38:39 1997
+++ linux/scripts/Configure	Wed Jun  3 15:17:50 1998
@@ -458,9 +458,9 @@
   echo "# Using defaults found in" $DEFAULTS
   echo "#"
   . $DEFAULTS
-  sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > /tmp/conf.$$
-  . /tmp/conf.$$
-  rm /tmp/conf.$$
+  sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .tmp.conf.$$
+  . .tmp.conf.$$
+  rm .tmp.conf.$$
 else
   echo "#"
   echo "# No defaults found"
diff -u --recursive --new-file v2.0.33/linux/scripts/Makefile linux/scripts/Makefile
--- v2.0.33/linux/scripts/Makefile	Fri Jun  7 01:58:11 1996
+++ linux/scripts/Makefile	Wed Jun  3 15:17:50 1998
@@ -2,6 +2,11 @@
 HEADER=header.tk
 TAIL=tail.tk
 
+# Ksymoops - to compile error-parsing program
+#
+ksymoops:
+	g++ ksymoops.cc -I /usr/include/g++/ -o ksymoops
+
 # We allow the Makefile in drivers/sound to decide when to rebuild its
 # files, rather than trying to second-guess it like we did before.
 #
diff -u --recursive --new-file v2.0.33/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.0.33/linux/scripts/Menuconfig	Tue Aug  5 09:01:54 1997
+++ linux/scripts/Menuconfig	Wed Jun  3 15:17:50 1998
@@ -21,6 +21,14 @@
 #
 # Please send comments / questions / bug fixes to roadcapw@titus.org
 #
+# 070498 Stepan Kasal <kasal@math.cas.cz> - one change borrowed
+# from 2.1.x version:
+#     131197 Michael Chastain (mec@shout.net) - output all lines for a
+#     choice list, not just the selected one.  This makes the output
+#     the same as Configure output, which is important for smart config
+#     dependencies.
+# It also fixes the bug when menuconfig sets CONFIG_M386=y every time
+# it is ran.
 #----------------------------------------------------------------------------
 
 #
@@ -62,10 +70,10 @@
 }
 
 #
-# Don't need this yet, but we don't want to puke either.
+# Define a boolean to a specific value.
 #
 function define_bool () {
-	:	
+	eval $1=$2
 }
 
 #
@@ -972,11 +980,19 @@
 		: ${current:=$default}
 
 		#
-		# Then extract the actual option from the list of choices.
+		# Output all choices (to be compatible with other configs).
 		#
-		current=${choices#*$current} ; set $current
-
-		define_bool "$1" "y"
+		set -- $choices
+		while [ -n "$2" ]
+		do
+			if eval [ "$1" = "$current" ]
+			then
+			    define_bool "$2" "y"
+			else
+			    define_bool "$2" "n"
+			fi
+			shift ; shift
+		done
 	}
 
 	function mainmenu_name () {
diff -u --recursive --new-file v2.0.33/linux/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c
--- v2.0.33/linux/scripts/lxdialog/checklist.c	Sat Mar  2 23:22:25 1996
+++ linux/scripts/lxdialog/checklist.c	Wed Jun  3 15:17:50 1998
@@ -188,9 +188,16 @@
     check_x = (list_width - check_x) / 2;
     item_x = check_x + 4;
 
+    if (choice >= list_height) {
+	scroll = choice - list_height + 1;
+	choice -= scroll;
+    }
+
     /* Print the list */
-    for (i = 0; i < max_choice; i++)
-	print_item (list, items[i * 3 + 1], status[i], i, i == choice);
+    for (i = 0; i < max_choice; i++) {
+	print_item (list, items[(scroll+i) * 3 + 1],
+		    status[i+scroll], i, i == choice);
+    }
 
     wnoutrefresh (list);
 
