diff -u --recursive --new-file v2.3.46/linux/CREDITS linux/CREDITS
--- v2.3.46/linux/CREDITS	Wed Feb 16 17:03:51 2000
+++ linux/CREDITS	Fri Feb 18 14:51:22 2000
@@ -367,6 +367,13 @@
 S: Orlando, Florida
 S: USA
 
+N: Lennert Buytenhek
+E: buytenh@gnu.org
+D: Rewrite of the ethernet bridging code
+S: Handelstraat 35
+S: 3131 EK Vlaardingen
+S: The Netherlands
+
 N: Michael Callahan
 E: callahan@maths.ox.ac.uk
 D: PPP for Linux
@@ -1271,10 +1278,6 @@
 S: L3R 8B2
 S: Canada
 
-N: Andrzej M. Krzysztofowicz
-E: ankry@mif.pg.gda.pl
-D: Some 8-bit XT disk driver and /devfs hacking 
-
 N: Andreas S. Krebs
 E: akrebs@altavista.net
 D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards
@@ -1289,7 +1292,7 @@
 
 N: Andrzej M. Krzysztofowicz
 E: ankry@mif.pg.gda.pl
-D: XT disk driver
+D: Some 8-bit XT disk driver and devfs hacking 
 D: Aladdin 1533/1543(C) chipset IDE
 D: PIIX chipset IDE
 S: ul. Matemblewska 1B/10
@@ -1528,6 +1531,13 @@
 D: XF86_Mach8
 D: XF86_8514
 D: cfdisk (curses based disk partitioning program)
+
+N: Heinz Mauelshagen
+E: mge@EZ-Darmstadt.Telekom.de
+D: Logical Volume Manager
+S: Bartningstr. 12
+S: 64289 Darmstadt
+S: Germany 
 
 N: Mike McLagan
 E: mike.mclagan@linux.org
diff -u --recursive --new-file v2.3.46/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.46/linux/Documentation/Configure.help	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/Configure.help	Sun Feb 20 20:37:09 2000
@@ -65,7 +65,7 @@
 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 
+  drivers, file systems, 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
@@ -224,7 +224,7 @@
 RAM disk support
 CONFIG_BLK_DEV_RAM
   Saying Y here will allow you to use a portion of your RAM memory as
-  a block device, so that you can make filesystems on it, read and
+  a block device, so that you can make file systems on it, read and
   write to it and do all the other things that you can do with normal
   block devices (such as hard drives). It is usually used to load and
   store a copy of a minimal root file system off of a floppy into RAM
@@ -260,7 +260,7 @@
   burning the CD, or if you want to use floppy images without first
   writing them to floppy.
 
-  The loop device driver can also be used to "hide" a filesystem in a
+  The loop device driver can also be used to "hide" a file system in a
   disk partition, floppy, or regular file, either using encryption
   (scrambling the data) or steganography (hiding the data in the low
   bits of, say, a sound file). This is also safe if the file resides
@@ -270,12 +270,12 @@
   ftp://verden.pvv.org/pub/linux/kerneli/v2.1/ , and then you need to
   say Y to this option.
 
-  Note that alternative ways to use encrypted filesystems are provided
+  Note that alternative ways to use encrypted file systems are provided
   by the cfs package, which can be gotten from
   ftp://ftp.replay.com/pub/crypto/disk/ , and the newer tcfs package,
   available at http://tcfs.dia.unisa.it/ . You do not need to say Y
   here if you want to use one of these. However, using cfs requires
-  saying Y to "NFS filesystem support" below while using tcfs requires
+  saying Y to "NFS file system support" below while using tcfs requires
   applying a kernel patch.
 
   To use the loop device, you need the losetup utility and a recent
@@ -297,7 +297,7 @@
 CONFIG_BLK_DEV_NBD
   Saying Y here will allow your computer to be a client for network
   block devices, i.e. it will be able to use block devices exported by
-  servers (mount filesystems on them etc.). Communication between
+  servers (mount file systems on them etc.). Communication between
   client and server works over TCP/IP networking, but to the client
   program this is hidden: it looks like a regular local file access to
   a block device special file such as /dev/nd0. 
@@ -343,7 +343,7 @@
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt and
   Documentation/ide.txt. The module will be called ide.o. Do not
-  compile this driver as a module if your root filesystem (the one
+  compile this driver as a module if your root file system (the one
   containing the directory /) is located on an IDE device.
 
   If you have one or more IDE drives, say Y or M here. If your system
@@ -400,7 +400,7 @@
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. The module will be
   called ide-disk.o. Do not compile this driver as a module if your
-  root filesystem (the one containing the directory /) is located on
+  root file system (the one containing the directory /) is located on
   the IDE disk. If unsure, say Y.
 
 Use multi-mode by default
@@ -424,7 +424,7 @@
   along with other IDE devices, as "hdb" or "hdc", or something
   similar (check the boot messages with dmesg). If this is your only
   CDROM drive, you can say N to all other CDROM options, but be sure
-  to say Y or M to "ISO 9660 CDROM filesystem support".
+  to say Y or M to "ISO 9660 CDROM file system support".
 
   Read the CDROM-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto and the file
@@ -631,7 +631,7 @@
   DMA for IDE drives and chipsets which support it. Due to concerns
   about a couple of cases where buggy hardware may have caused damage,
   the default is now to NOT use DMA automatically. To revert to the
-  previous behaviour, say Y to this question.
+  previous behavior, say Y to this question.
 
   If you suspect your hardware is at all flakey, say N here.
   Do NOT email the IDE kernel people regarding this issue!
@@ -1069,7 +1069,7 @@
   system. Among the devices supported by this driver are the
   MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If
   you have such a CD-ROM drive, you should also say Y or M to "ISO
-  9660 CDROM filesystem support" below, because that's the filesystem
+  9660 CDROM file system support" below, because that's the file system
   used on CDROMs.
 
 Parallel port ATAPI disks
@@ -1260,6 +1260,30 @@
   called on26.o. You must also have a high-level driver for the type
   of device that you want to support.
 
+Logical Volume Manager (LVM) support
+CONFIG_BLK_DEV_LVM
+  This driver lets you combine several hard disks, hard disk
+  partitions, multiple devices or even loop devices (for evaluation
+  purposes) into a volume group.  Imagine a volume group as a kind of
+  virtual disk. Logical volumes, which can be thought of as virtual
+  partitions, can be created in the volume group.  You can resize
+  volume groups and logical volumes after creation time, corresponding
+  to new capacity needs.  Logical volumes are accessed as block
+  devices named /dev/VolumeGroupName/LogicalVolumeName.
+
+  For details see /usr/src/linux/Documentaion/LVM-HOWTO.
+
+  To get the newest software see <http://linux.msede.com/lvm>.
+
+Logical Volume Manager /proc file system information
+CONFIG_LVM_PROC_FS
+  If you say Y here, you are able to access overall Logical Volume
+  Manager, Volume Group, Logical and Physical Volume information in
+  /proc/lvm.
+
+  To use this option, you have to check, that the "/proc file system
+  support" (CONFIG_PROC_FS) is enabled too.
+
 Multiple devices driver support
 CONFIG_BLK_DEV_MD
   This driver lets you combine several hard disk partitions into one
@@ -1496,7 +1520,7 @@
   are completely invisible to the outside world, even though they can
   reach the outside and can receive replies. It is even possible to
   run globally visible servers from within a masqueraded local network
-  using a mechanism called portforwarding. Masquerading is also often
+  using a mechanism called port-forwarding. Masquerading is also often
   called NAT (Network Address Translation).
 
   Another use of Netfilter is in transparent proxying: if a machine on
@@ -1506,7 +1530,7 @@
 
   Various modules exist for netfilter which replace the previous
   masquerading (ipmasqadm), packet filtering (ipchains), transparent
-  proxying, and portforwarding mechanisms. More information is
+  proxying, and port-forwarding mechanisms. More information is
   available from http://netfilter.kernelnotes.org .
  
   Make sure to say N to "Fast switching" below if you intend to say Y
@@ -1515,7 +1539,7 @@
   Chances are that you should say Y here if you compile a kernel which
   will run as a router and N for regular hosts. If unsure, say N.
  
-SYN flood protection
+SIN flood protection
 CONFIG_SYN_COOKIES
   Normal TCP/IP networking is open to an attack known as "SYN
   flooding". This denial-of-service attack prevents legitimate remote
@@ -1542,12 +1566,12 @@
   them off.
 
   If you say Y here, note that SYN cookies aren't enabled by default;
-  you can enable them by saying Y to "/proc filesystem support" and
+  you can enable them by saying Y to "/proc file system support" and
   "Sysctl support" below and executing the command
 
     echo 1 >/proc/sys/net/ipv4/tcp_syncookies 
 
-  at boot time after the proc filesystem has been mounted.
+  at boot time after the /proc file system has been mounted.
   
   If unsure, say Y.
 
@@ -1855,7 +1879,7 @@
 
 I2O /proc support
 CONFIG_I2O_PROC
-  If you say Y here and to "/proc filesystem support", you will be
+  If you say Y here and to "/proc file system support", you will be
   able to read I2O related information from the virtual directory
   /proc/i2o.
 
@@ -1875,7 +1899,7 @@
   Say Y here if you would like Linux to configure your Plug and Play
   devices. You should then also say Y to "ISA Plug and Play support",
   below. Alternatively, you can configure your PnP devices using the
-  user space utilities contained in the isapnptools package.
+  user space utilities contained in the ISAPNP tools package.
   
   This support is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -1964,7 +1988,7 @@
   certain kernel parameters and variables on the fly without requiring
   a recompile of the kernel or reboot of the system. The primary
   interface consists of a system call, but if you say Y to "/proc
-  filesystem support", a tree of modifiable sysctl entries will be
+  file system support", a tree of modifiable sysctl entries will be
   generated beneath the /proc/sys directory. They are explained in the
   files in Documentation/sysctl/. Note that enabling this option will
   enlarge the kernel by at least 8 KB.
@@ -1975,7 +1999,7 @@
 
 Kernel core (/proc/kcore) format
 CONFIG_KCORE_ELF
-  If you enabled support for /proc filesystem then the file /proc/kcore
+  If you enabled support for /proc file system then the file /proc/kcore
   will contain the kernel core image. This can be used in gdb:
 
   $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
@@ -2069,7 +2093,7 @@
   Documentation/java.txt for information about how to include Java
   support.
 
-  You must say Y to "proc filesystem support" (CONFIG_PROC_FS) to
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
   use this part of the kernel.
 
   You may say M here for module support and later load the module when
@@ -2381,7 +2405,7 @@
   provided by the text console 80x50 (and higher) modes.
   Note this is a poor quality font. The VGA 8x16 font is quite a lot
   more readable.
-  Given the resolution provided by the frame buffer device, anwser N
+  Given the resolution provided by the frame buffer device, answer N
   here is safe.
 
 Backward compatibility mode for Xpmac
@@ -2679,7 +2703,7 @@
 
 Support IEEE1284 status readback
 CONFIG_PRINTER_READBACK
-  If you have a device on your parrallel port that support this protocol,
+  If you have a device on your parallel port that support this protocol,
   this option'll enable it to report its status.
   It is safe to say Y.
 
@@ -2719,7 +2743,7 @@
 
 Kernel module loader support
 CONFIG_KMOD
-  Normally when you have selected some drivers and/or filesystems to
+  Normally when you have selected some drivers and/or file systems to
   be created as loadable modules, you also have the responsibility to
   load the corresponding modules (using the programs insmod or
   modprobe) before you can use them. If you say Y here however, the
@@ -2771,7 +2795,7 @@
   Internet connected Unix computer; for more information, read
   http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ).
   
-  If you say Y here and also to "/proc filesystem support" and "Sysctl
+  If you say Y here and also to "/proc file system support" and "Sysctl
   support" below, you can change various aspects of the behavior of
   the TCP/IP code by writing to the (virtual) files in
   /proc/sys/net/ipv4/*; the options are explained in the file
@@ -2804,12 +2828,12 @@
 
   Note that your box can only act as a router if you enable IP
   forwarding in your kernel; you can do that by saying Y to "/proc
-  filesystem support" and "Sysctl support" below and executing the
+  file system support" and "Sysctl support" below and executing the
   line
 
     echo "1" > /proc/sys/net/ipv4/ip_forward
 
-  at boot time after the /proc filesystem has been mounted. 
+  at boot time after the /proc file system has been mounted. 
 
   If you turn on IP forwarding, you will also get the rp_filter, which
   automatically rejects incoming packets if the routing table entry
@@ -2903,12 +2927,12 @@
 
   Note that your box can only act as a router if you enable IP
   forwarding in your kernel; you can do that by saying Y to "/proc
-  filesystem support" and "Sysctl support" below and executing the
+  file system support" and "Sysctl support" below and executing the
   line
 
     echo "1" > /proc/sys/net/ipv4/ip_forward
 
-  at boot time after the /proc filesystem has been mounted. You can do
+  at boot time after the /proc file system has been mounted. You can do
   that even if you say N here.
 
   If unsure, say N here.
@@ -2925,7 +2949,7 @@
 
 BOOTP support
 CONFIG_IP_PNP_BOOTP
-  If you want your Linux box to mount its whole root filesystem (the
+  If you want your Linux box to mount its whole root file system (the
   one containing the directory /) from some other computer over the
   net via NFS and you want the IP address of your computer to be
   discovered automatically at boot time using the BOOTP protocol (a
@@ -2938,7 +2962,7 @@
 
 RARP support
 CONFIG_IP_PNP_RARP
-  If you want your Linux box to mount its whole root filesystem (the
+  If you want your Linux box to mount its whole root file system (the
   one containing the directory /) from some other computer over the
   net via NFS and you want the IP address of your computer to be
   discovered automatically at boot time using the RARP protocol (an
@@ -3166,7 +3190,7 @@
   ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) or from within
   the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto ). In order to do the
-  former, you'll also have to say Y to "NCP filesystem support",
+  former, you'll also have to say Y to "NCP file systems support",
   below.
 
   IPX is similar in scope to IP, while SPX, which runs on top of IPX,
@@ -3225,7 +3249,7 @@
 
   Note that Novell NetWare file sharing does not use SPX; it uses a
   protocol called NCP, for which separate Linux support is available
-  ("NCP filesystem support" below for the client side, and the user
+  ("NCP file systems support" below for the client side, and the user
   space programs lwared or mars_nwe for the server side).
 
   Say Y here if you have use for SPX; read the IPX-HOWTO at
@@ -3250,7 +3274,7 @@
   More detailed documentation is available in the
   Documentation/networking/decnet.txt file.
 
-  Be sure to say Y to "/proc filesystem support" and "Sysctl support"
+  Be sure to say Y to "/proc file systems support" and "Sysctl support"
   below when using DECnet, since you will need sysctl support to aid
   in configuration at run time.
 
@@ -3797,25 +3821,25 @@
   This is a Logical Link Layer protocol used for X.25 connections over
   Ethernet, using ordinary Ethernet cards. 
 
-Bridging (EXPERIMENTAL)
+802.1d Ethernet Bridging
 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.
+  networks of Ethernets using the IEEE 802.1d spanning tree protocol.
   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 from ftp://shadow.cabi.net/pub/Linux . Please read the
-  Bridge mini-HOWTO for more information. 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 Ethernet-HOWTO, available from
+  In order to use the ethernet bridge, you'll need the bridge
+  configuration tools available from ftp://openrock.net/bridge. Please
+  read the Bridge mini-HOWTO for more information. 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 Ethernet-HOWTO, available from in
   http://www.linuxdoc.org/docs.html#howto .
 
-  The Bridging code is still in test. If unsure, say N.
+  If unsure, say N.
 
 Packet socket
 CONFIG_PACKET
@@ -3896,13 +3920,13 @@
   ATMARP. Typically you will either use LAN Emulation (LANE) or
   Classical IP to communicate with other IP hosts on your ATM network.
 
-Do NOT send ICMP if no neighbour
+Do NOT send ICMP if no neighbor
 CONFIG_ATM_CLIP_NO_ICMP
-  Normally, an "ICMP host unreachable" message is sent if a neighbour
+  Normally, an "ICMP host unreachable" message is sent if a neighbor
   cannot be reached because there is no VC to it in the kernel's
   ATMARP table. This may cause problems when ATMARP table entries are
   briefly removed during revalidation. If you say Y here, packets to
-  such neighbours are silently discarded instead.
+  such neighbors are silently discarded instead.
 
 LAN Emulation (LANE) support
 CONFIG_ATM_LANE
@@ -4141,7 +4165,7 @@
   The module will be called scsi_mod.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt and
   Documentation/scsi.txt. However, do not compile this as a module if
-  your root filesystem (the one containing the directory /) is located
+  your root file systems (the one containing the directory /) is located
   on a SCSI device.
 
 SCSI disk support
@@ -4157,7 +4181,7 @@
   The module will be called sd_mod.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt and
   Documentation/scsi.txt. Do not compile this driver as a module if
-  your root filesystem (the one containing the directory /) is located
+  your root file systems (the one containing the directory /) is located
   on a SCSI disk. In this case, do not compile the driver for your
   SCSI host adapter (below) as a module either.
 
@@ -4204,7 +4228,7 @@
   If you want to use a SCSI CDROM under Linux, say Y and read the
   SCSI-HOWTO and the CDROM-HOWTO at
   http://www.linuxdoc.org/docs.html#howto . Also make sure to say Y
-  or M to "ISO 9660 CDROM filesystem support" later.
+  or M to "ISO 9660 CDROM file systems support" later.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -4284,12 +4308,12 @@
   of SCSI related problems. 
 
   If you say Y here, no logging output will appear by default, but you
-  can enable logging by saying Y to "/proc filesystem support" and
+  can enable logging by saying Y to "/proc file systems support" and
   "Sysctl support" below and executing the command
 
      echo "scsi log token [level]" > /proc/scsi/scsi
 
-  at boot time after the /proc filesystem has been mounted.
+  at boot time after the /proc file systems has been mounted.
 
   There are a number of things that can be used for 'token' (you can
   find them in the source: drivers/scsi/scsi.c), and this allows you
@@ -4452,7 +4476,7 @@
   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. This will only work if
-  you also say Y to "/proc filesystem support", below. 
+  you also say Y to "/proc file system support", below. 
 
   If unsure, say N.
 
@@ -5702,16 +5726,16 @@
   This configuration option enables common code for all devices (PCI, ISA,
   PCMCIA)
   module is aironet4500_core
-  quickconfig parameters: 
+  quick config parameters: 
 	SSID=tsunami - "The Password"
 	adhoc=1  	there are no Access Points around
 	master=1 	Adhoc master (the one who creates network sync)
 	slave=1		Adhoc slave(btw, it is still forming own net 
 			sometimes)
 	channel=1..? 	meaningful in adhoc mode
-  all other parameters can be set via proc interface
+  all other parameters can be set via /proc interface
   These parameters belong to .._card module, but alas, they are here
-  if you have problems with screwin up card, both_bap_lock=1 is conservative
+  if you have problems with screwing up card, both_bap_lock=1 is conservative
   value (performance hit 15%)
   for any other configuration options look at ..._proc module
 
@@ -5747,7 +5771,7 @@
 Aironet 4500/4800 I365 broken support (EXPERIMENTAL)
 CONFIG_AIRONET4500_I365
 	This option enables support for PCMCIA cards on i365 controller 
-	_without_ cardservices. Doesnt have much sense and is not working
+	_without_ cardservices. Doesn't have much sense and is not working
 	properly. Comes from times where there was no PCMCIA support in
 	kernel main source tree
 
@@ -5760,7 +5784,7 @@
 	The same option is both on:
 		1. PCMCIA netdevices configuring panel
 		2. Wireless netdevices configuring panel
-	Possibility to change this option depeds on options set in 2.
+	Possibility to change this option depends on options set in 2.
 	
 Aironet 4500/4800 PROC interface
 CONFIG_AIRONET4500_PROC
@@ -6187,9 +6211,9 @@
   That package also contains some documentation; for more, check out
   http://snafu.freedom.org/linux2.2/iproute-notes.html .
 
-  If you say Y here and to "/proc filesystem" below, you will be able
-  to read status information about packet schedulers from the file
-  /proc/net/psched.
+  If you say Y here and to "/proc file system support" below, you will
+  be able to read status information about packet schedulers from the
+  file /proc/net/psched.
   
   The available schedulers are listed in the following questions; you
   can say Y to as many as you like. If unsure, say N now.
@@ -6392,7 +6416,7 @@
 
 Network code profiler
 CONFIG_NET_PROFILE
-  If you say Y here and to "/proc filesystem support" below, some
+  If you say Y here and to "/proc file system support" below, some
   obscure and undocumented information about the network code's
   performance will be written to /proc/net/profile. If you don't know
   what it is about, you don't need it: say N.
@@ -6747,17 +6771,29 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-RealTek 8129/8139 (not 8019/8029!) support
-CONFIG_RTL8139
+RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)
+CONFIG_RTL8129
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the RTL8129 chip. If you have one of those, say Y and
+  read the Ethernet-HOWTO, available from
+  http://www.linuxdoc.org/docs.html#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 and read Documentation/modules.txt. This is recommended.
+  The module will be called rtl8129.o.
+
+RealTek RTL-8139 PCI Fast Ethernet Adapter support
+CONFIG_8139TOO
   This is a driver for the Fast Ethernet PCI network cards based on
-  the RTL8129 and RTL8139 chips. If you have one of those, say Y and
+  the RTL8139 chip. If you have one of those, say Y and
   read the Ethernet-HOWTO, available from
   http://www.linuxdoc.org/docs.html#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 and read Documentation/modules.txt. This is recommended.
-  The module will be called rtl8139.o.
+  The module will be called 8139too.o.
 
 SiS 900 PCI Fast Ethernet Adapter support
 CONFIG_SIS900
@@ -6850,7 +6886,7 @@
   The dual link adapters support a link-failover feature.
   Read Documentation/networking/sk98lin.txt for information about
   optional driver parameters.
-  Questions concerning this driver may be addresse to:
+  Questions concerning this driver may be addressed to:
     linux@syskonnect.de
 
   If you want to compile this driver as a module ( = code which can be
@@ -7307,7 +7343,7 @@
   Documentation/networking/net-modules.txt.
 
 EISA, VLB, PCI and on board controllers
-CONFIG_NET_EISA
+CONFIG_NET_PCI
   This is another class of network cards which attach directly to the
   bus. If you have one of those, say Y and read the Ethernet-HOWTO,
   available from http://www.linuxdoc.org/docs.html#howto .
@@ -7428,7 +7464,7 @@
   Documentation/networking/net-modules.txt.
 
 EtherExpress PRO/100 support
-CONFIG_EEXPRESS_PRO100
+CONFIG_EEPRO100
   If you have an Intel EtherExpress PRO/100 PCI network (Ethernet)
   card, say Y and read the Ethernet-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto .
@@ -7643,7 +7679,7 @@
   Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several
   Madge adapters.  If selected, you will be asked to select
   which cards to support below.  If you're using modules, each
-  class of card will be supported by a seperate module.
+  class of card will be supported by a separate module.
 
   If you have such an adapter and would like to use it, say Y or M and
   read the Token-Ring mini-HOWTO, available from
@@ -7716,6 +7752,36 @@
   This is support for the DIGITAL series of EISA (DEFEA) and PCI
   (DEFPA) controllers which can connect you to a local FDDI network.
 
+SysKonnect FDDI PCI support
+CONFIG_SKFP
+  Say Y here if you have a SysKonnect FDDI PCI adapter.
+  The following adapters are supported by this driver:
+  - SK-5521 (SK-NET FDDI-UP)
+  - SK-5522 (SK-NET FDDI-UP DAS)
+  - SK-5541 (SK-NET FDDI-FP)
+  - SK-5543 (SK-NET FDDI-LP)
+  - SK-5544 (SK-NET FDDI-LP DAS)
+  - SK-5821 (SK-NET FDDI-UP64)
+  - SK-5822 (SK-NET FDDI-UP64 DAS)
+  - SK-5841 (SK-NET FDDI-FP64)
+  - SK-5843 (SK-NET FDDI-LP64)
+  - SK-5844 (SK-NET FDDI-LP64 DAS)
+  - Netelligent 100 FDDI DAS Fibre SC
+  - Netelligent 100 FDDI SAS Fibre SC
+  - Netelligent 100 FDDI DAS UTP
+  - Netelligent 100 FDDI SAS UTP
+  - Netelligent 100 FDDI SAS Fibre MIC
+  Read Documentation/networking/skfp.txt for information about
+  the driver.
+  WARNING: this driver does currently not support 64 bit systems!
+  Questions concerning this driver can be addressed to:
+    linux@syskonnect.de
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called skfp.o.
+
 HIgh Performance Parallel Interface support (EXPERIMENTAL)
 CONFIG_HIPPI
   HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
@@ -7789,7 +7855,7 @@
   read Documentation/modules.txt. 
 
   If you want to use any of these CDROM drivers, you also have to
-  answer Y or M to "ISO 9660 CDROM filesystem support" below (this
+  answer Y or M to "ISO 9660 CDROM file systems support" below (this
   answer will get "defaulted" for you if you enable any of the Linux
   CDROM drivers).
 
@@ -7806,7 +7872,7 @@
   explained in the SCSI-HOWTO. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file systems support" below, because that's the file systems used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -7828,7 +7894,7 @@
   this. If you want that one, say N here.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file systems support" below, because that's the file systems used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -7861,7 +7927,7 @@
   Documentation/cdrom/mcdx.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file systems support" below, because that's the file systems used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -7899,7 +7965,7 @@
   usable.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file systems support" below, because that's the file systems used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -7924,7 +7990,7 @@
   CDA269-031SE. Please read the file Documentation/cdrom/aztcd. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file systems support" below, because that's the file systems used on
   CDROMs.
 
   This driver is also available as a module ( = code which can be
@@ -7938,7 +8004,7 @@
   drives. Please read the file Documentation/cdrom/sonycd535.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file system support" below, because that's the file system used on
   CDROMs.
 
   This driver is also available as a module ( = code which can be
@@ -7954,7 +8020,7 @@
   kernel. Please read the file Documentation/cdrom/gscd. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file system support" below, because that's the file system used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -7969,7 +8035,7 @@
   Documentation/cdrom/cm206. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file system support" below, because that's the file system used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -7986,7 +8052,7 @@
   one. Please read the file Documentation/cdrom/optcd. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  filesystem support" below, because that's the filesystem used on
+  file system support" below, because that's the file system used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -7998,8 +8064,8 @@
 CONFIG_SJCD
   If this is your CDROM drive, say Y here and read the file
   Documentation/cdrom/sjcd. You should then also say Y or M to
-  "ISO 9660 CDROM filesystem support" below, because that's the
-  filesystem used on CDROMs.
+  "ISO 9660 CDROM file system support" below, because that's the
+  file system used on CDROMs.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -8034,7 +8100,7 @@
 CONFIG_QUOTA
   If you say Y here, you will be able to set per user limits for disk
   usage (also called disk quotas). Currently, it works only for the
-  ext2 filesystem. You need additional software in order to use quota
+  ext2 file system. You need additional software in order to use quota
   support; for details, read the Quota mini-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto . Probably the quota
   support is only useful for multi user systems. If unsure, say N.
@@ -8376,7 +8442,7 @@
   The module will be called uss720.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
   
-USB device filesystem
+USB device file system
 CONFIG_USB_DEVICEFS
   This file system implements a "devices" file, that lists
   the currently connected to your USB busses, a "drivers" file
@@ -8416,10 +8482,10 @@
 Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about OS's.
-  The minix filesystem (method to organize files on a hard disk
-  partition or a floppy disk) was the original filesystem for Linux,
-  but has been superseded by the second extended filesystem ext2fs.
-  You don't want to use the minix filesystem on your hard disk because
+  The minix file system (method to organize files on a hard disk
+  partition or a floppy disk) was the original file system for Linux,
+  but has been superseded by the second extended file system ext2fs.
+  You don't want to use the minix file system on your hard disk because
   of certain built-in restrictions, but it is sometimes found on older
   Linux floppy disks. This option will enlarge your kernel by about 
   28 kB. If unsure, say N.
@@ -8427,16 +8493,16 @@
   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. The module will be
-  called minix.o. Note that the filesystem of your root partition (the
+  called minix.o. Note that the file system of your root partition (the
   one containing the directory /) cannot be compiled as a module.
 
 Second extended fs support
 CONFIG_EXT2_FS
-  This is the de facto standard Linux filesystem (method to organize
+  This is the de facto standard Linux file system (method to organize
   files on a storage device) for hard disks. 
 
   You want to say Y here, unless you intend to use Linux exclusively
-  from inside a DOS partition using the umsdos filesystem. The
+  from inside a DOS partition using the umsdos file system. The
   advantage of the latter is that you can get away without
   repartitioning your hard drive (which often implies backing
   everything up and restoring afterwards); the disadvantage is that
@@ -8447,16 +8513,16 @@
   Linux partition later. Another (rare) case which doesn't require
   ext2fs is a diskless Linux box which mounts all files over the
   network using NFS (in this case it's sufficient to say Y to "NFS
-  filesystem support" below). Saying Y here will enlarge your kernel
+  file system support" below). Saying Y here will enlarge your kernel
   by about 44 kB.
 
   The Ext2fs-Undeletion mini-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto , gives information about
-  how to retrieve deleted files on ext2fs filesystems.
+  how to retrieve deleted files on ext2fs file systems.
 
-  To change the behavior of ext2 filesystems, you can use the tune2fs
+  To change the behavior of ext2 file systems, you can use the tune2fs
   utility ("man tune2fs"). To modify attributes of files and
-  directories on ext2 filesystems, use chattr ("man chattr").
+  directories on ext2 file systems, use chattr ("man chattr").
   
   Ext2fs partitions can be read from within DOS using the ext2tool
   command line tool package (available via FTP (user: anonymous) from
@@ -8467,35 +8533,35 @@
   NT and includes experimental write support; it is available from
   http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm .
 
-  If you want to compile this filesystem as a module ( = code which
+  If you want to compile this file system as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
   want), say M here and read Documentation/modules.txt. The module
-  will be called ext2.o. Be aware however that the filesystem of your
+  will be called ext2.o. Be aware however that the file system of your
   root partition (the one containing the directory /) cannot be
   compiled as a module, and so this could be dangerous. Most everyone
   wants to say Y here.
 
-SCO UnixWare BFS Support
+BFS file system support (EXPERIMENTAL)
 CONFIG_BFS_FS
-  Boot Filesystem (BFS) is a filesystem used under SCO UnixWare to
+  Boot File System (BFS) is a file system used under SCO UnixWare to
   allow bootloader access the kernel image and other important files
   during the boot process. It is usually mounted under /stand and
   corresponds to the slice marked as "STAND" in the UnixWare
   partition. This is useful if you want to access files on your /stand
-  slice from Linux. More information on this filesystem can be found in
+  slice from Linux. More information on this file system can be found in
   Documentation/filesystems/bfs.txt file. If you do not know what it is, 
   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. The module will be
-  called bfs.o. Note that the filesystem of your root partition (the
+  called bfs.o. Note that the file system of your root partition (the
   one containing the directory /) cannot be compiled as a module.
  
-ISO 9660 CDROM filesystem support
+ISO 9660 CDROM file system support
 CONFIG_ISO9660_FS
-  This is the standard filesystem used on CDROMs. It was previously
-  known as "High Sierra Filesystem" and is called "hsfs" on other Unix
+  This is the standard file system used on CDROMs. It was previously
+  known as "High Sierra File System" and is called "hsfs" on other Unix
   systems. The so-called Rock-Ridge extensions which allow for long
   Unix filenames and symbolic links are also supported by this driver.
   If you have a CDROM drive and want to do more with it than just
@@ -8511,21 +8577,21 @@
 
 Microsoft Joliet CDROM extensions
 CONFIG_JOLIET
-  Joliet is a Microsoft extension for the ISO 9660 CDROM filesystem
+  Joliet is a Microsoft extension for the ISO 9660 CDROM file system
   which allows for long filenames in unicode format (unicode is the
   new 16 bit character code, successor to ASCII, which encodes the
   characters of almost all languages of the world; see
   http://www.unicode.org for more information). Say Y here if you want
   to be able to read Joliet CDROMs under Linux.
 
-UDF Filesystem support (read only)
+UDF file system support (read only)
 CONFIG_UDF_FS
-  This is the new filesystem used by some CDROMS and DVD drivers. Say
+  This is the new file system used by some CDROMS and DVD drivers. Say
   Y if you intend to mount DVD discs or CDRW's written in packet mode,
   or if written to by other UDF utilities, such as DirectCD. Please
   read Documentation/filesystems/udf.txt.
 
-  This filesystem support is also available as a module ( = code which
+  This file system support is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). The module is called udf.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt. 
@@ -8534,32 +8600,32 @@
 
 UDF write support (DANGEROUS)
 CONFIG_UDF_RW
-  Say Y if you want to test write support for UDF filesystems.
+  Say Y if you want to test write support for UDF file systems.
   Due to lack of support for writing to CDR/CDRW's, this option
   is only supported for Hard Discs, DVD-RAM, and loopback files.
 
 DOS FAT fs support
 CONFIG_FAT_FS
-  If you want to use one of the FAT-based filesystems (the MS-DOS,
+  If you want to use one of the FAT-based file systems (the MS-DOS,
   VFAT (Windows 95) and UMSDOS (used to run Linux on top of an
-  ordinary DOS partition) filesystems), then you must say Y or M here
+  ordinary DOS partition) file systems), then you must say Y or M here
   to include FAT support. You will then be able to mount partitions or
-  diskettes with FAT-based filesystems and transparently access the
+  diskettes with FAT-based file systems and transparently access the
   files on them, i.e. MSDOS files will look and behave just like all
   other Unix files.
 
-  This FAT support is not a filesystem in itself, it only provides the
-  foundation for the other filesystems. You will have to say Y or M to
+  This FAT support is not a file system in itself, it only provides the
+  foundation for the other file systems. You will have to say Y or M to
   at least one of "msdos fs support" or "vfat fs support" in order to
   make use of it.
 
   Another way to read and write MSDOS floppies and hard drive
   partitions from within Linux (but not transparently) is with the
   mtools ("man mtools") program suite. This doesn't require the FAT
-  filesystem support.
+  file system support.
 
   It is now also becoming possible to read and write compressed FAT
-  filesystems; read Documentation/filesystems/fat_cvf.txt for details.
+  file systems; read Documentation/filesystems/fat_cvf.txt for details.
   
   The FAT support will enlarge your kernel by about 37 KB. If unsure,
   say Y.
@@ -8568,11 +8634,11 @@
   be inserted in and removed from the running kernel whenever you
   want), say M here and read Documentation/modules.txt. The module
   will be called fat.o. Note that if you compile the FAT support as a
-  module, you cannot compile any of the FAT-based filesystems into the
-  kernel -- they will have to be modules as well. The filesystem of
+  module, you cannot compile any of the FAT-based file systems into the
+  kernel -- they will have to be modules as well. The file system of
   your root partition (the one containing the directory /) cannot be a
   module, so don't say M here if you intend to use UMSDOS as your root
-  filesystem.
+  file system.
 
 MSDOS fs support
 CONFIG_MSDOS_FS
@@ -8587,12 +8653,12 @@
   transparent, i.e. the MSDOS files look and behave just like all
   other Unix files.
 
-  If you want to use umsdos, the Unix-like filesystem on top of DOS,
+  If you want to use umsdos, the Unix-like file system on top of DOS,
   which allows you to run Linux from within a DOS partition without
   repartitioning, you'll have to say Y or M here. 
 
   If you have Windows 95 or Windows NT installed on your MSDOS
-  partitions, you should use the VFAT filesystem (say Y to "vfat fs
+  partitions, you should use the VFAT file system (say Y to "vfat fs
   support" below), or you will not be able to see the long filenames
   generated by Windows 95 / Windows NT.
 
@@ -8605,11 +8671,11 @@
 
 VFAT (Windows-95) fs support
 CONFIG_VFAT_FS
-  This option provides support for normal Windows filesystems with
-  long filenames. That includes non-compressed FAT-based filesystems
+  This option provides support for normal Windows file systems with
+  long filenames. That includes non-compressed FAT-based file systems
   used by Windows 95, Windows 98, Windows NT 4.0, and mtools. 
 
-  You cannot use the VFAT filesystem for your Linux root partition
+  You cannot use the VFAT file system for your Linux root partition
   (the one containing the directory /); use UMSDOS instead if you
   want to run Linux from within a DOS partition (i.e. say Y to
   "umsdos: Unix like fs on top of std MSDOS fs", below).
@@ -8624,7 +8690,7 @@
   say M here and read Documentation/modules.txt. The module will be
   called vfat.o.
 
-UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem
+UMSDOS: Unix-like file system on top of standard MSDOS fs
 CONFIG_UMSDOS_FS
   Say Y here if you want to run Linux from within an existing DOS
   partition of your hard drive. The advantage of this is that you can
@@ -8634,11 +8700,11 @@
   disadvantage is that Linux becomes susceptible to DOS viruses and
   that UMSDOS is somewhat slower than ext2fs. Another use of UMSDOS
   is to write files with long unix filenames to MSDOS floppies; it
-  also allows Unix-style softlinks and owner/permissions of files on
+  also allows Unix-style soft-links and owner/permissions of files on
   MSDOS floppies. You will need a program called umssync in order to
   make use of umsdos; read Documentation/filesystems/umsdos.txt. 
 
-  To get utilities for initializing/checking UMSDOS filesystem, or
+  To get utilities for initializing/checking UMSDOS file system, or
   latest patches and/or information, visit UMSDOS homepage at
   http://www.voyager.hr/~mnalis/umsdos/ .
 
@@ -8647,13 +8713,13 @@
   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. The module will be called
-  umsdos.o. Note that the filesystem of your root partition (the one
+  umsdos.o. Note that the file system of your root partition (the one
   containing the directory /) cannot be a module, so saying M could be
   dangerous. If unsure, say N.
 
-/proc filesystem support
+/proc file system support
 CONFIG_PROC_FS
-  This is a virtual filesystem providing information about the status
+  This is a virtual file system providing information about the status
   of the system. "Virtual" means that it doesn't take up any space on
   your hard disk: the files are created on the fly by the kernel when
   you try to access them. Also, you cannot read the files with older
@@ -8666,32 +8732,34 @@
   often a source of trouble if two devices are mistakenly configured
   to use the same IRQ). 
 
-  The /proc filesystem is explained in the file
+  The /proc file system is explained in the file
   Documentation/filesystems/proc.txt and on the proc(5) manpage ("man
   5 proc").
 
   This option will enlarge your kernel by about 67 KB. Several
   programs depend on this, so everyone should say Y here.
 
-/dev filesystem support (EXPERIMENTAL)
+/dev file system support (EXPERIMENTAL)
 CONFIG_DEVFS_FS
-  This is another virtual filesystem (like /proc) which provides the
-  filesystem interface to device drivers, normally found in /dev.
+  This is another virtual file system (like /proc) which provides the
+  file system interface to device drivers, normally found in /dev.
   Devfs does not depend on major and minor number allocations. Device
   drivers register entries in /dev which appear automagically. Without
   devfs you need to populate /dev with hundreds, even thousands of
   inodes.
   This is work in progress. If you want to use this you *must* read
   Documentation/filesystems/devfs/README
+  In particular, make sure you install devfsd. If you don't, expect to
+  spend time patching broken code and updating configuration files.
 
-Enable devfs debugging output
+Debug devfs
 CONFIG_DEVFS_DEBUG
   This option appears if you have CONFIG_DEVFS_FS enabled. Setting
   this to 'Y' enables devfs debugging output. See the file
   Documentation/filesystems/devfs/boot-options for more details.
   The default is 'N'.
 
-NFS filesystem support
+NFS file system support
 CONFIG_NFS_FS
   If you are connected to some other (usually local) Unix computer
   (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
@@ -8699,25 +8767,25 @@
   protocol, say Y. "Mounting files" means that the client can access
   the files with usual UNIX commands as if they were sitting on the
   client's hard disk. For this to work, the server must run the
-  programs nfsd and mountd (but does not need to have NFS filesystem
+  programs nfsd and mountd (but does not need to have NFS file system
   support enabled in its kernel). NFS is explained in the Network
   Administrator's Guide, available from
   http://metalab.unc.edu/mdw/linux.html#guide , on its man page: "man
   nfs", and in the NFS-HOWTO.
   
   A superior but less widely used alternative to NFS is provided by
-  the Coda filesystem; see "Coda filesystem support" below.
+  the Coda file system; see "Coda file system support" below.
 
   If you say Y here, you should have said Y to TCP/IP networking also.
   This option would enlarge your kernel by about 27 KB. 
 
-  This filesystem is also available as a module ( = code which can be
+  This file system is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module is called nfs.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt. 
 
   If you are configuring a diskless machine which will mount its root
-  filesystem over NFS at boot time, say Y here and to "IP: kernel
+  file system over NFS at boot time, say Y here and to "IP: kernel
   level autoconfiguration" above and to "Root file system on NFS"
   below. You cannot compile this driver as a module in this case.
   There are two packages designed for booting diskless machines over
@@ -8728,7 +8796,7 @@
 
 Root file system on NFS
 CONFIG_ROOT_NFS
-  If you want your Linux box to mount its whole root filesystem (the
+  If you want your Linux box to mount its whole root file system (the
   one containing the directory /) from some other computer over the
   net via NFS (presumably because your box doesn't have a hard disk),
   say Y. Read Documentation/nfsroot.txt for details. It is likely that
@@ -8764,24 +8832,24 @@
 Provide NFSv3 server support (EXPERIMENTAL)
 CONFIG_NFSD_V3
   If you would like to include the NFSv3 server was well as the NFSv2
-  server, say Y here.  File locking, via the NLMv4 protocol, is not
-  supported yet. If unsure, say N.
+  server, say Y here.  File locking, via the NLMv4 protocol, is also
+  supported. If unsure, say N.
 
-OS/2 HPFS filesystem support
+OS/2 HPFS file system support
 CONFIG_HPFS_FS
   OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
-  is the filesystem used for organizing files on OS/2 hard disk
+  is the file system used for organizing files on OS/2 hard disk
   partitions. Say Y if you want to be able to read files from an OS/2
   HPFS partition of your hard drive. OS/2 floppies however are in
   regular MSDOS format, so you don't need this option in order to be
   able to read them. Read Documentation/filesystems/hpfs.txt. 
 
-  This filesystem is also available as a module ( = code which can be
+  This file system is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module is called hpfs.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt. If unsure, say N.
 
-Windows NT NTFS support (read only)
+NTFS file system support (read only)
 CONFIG_NTFS_FS
   NTFS is the file system of Microsoft Windows NT. Say Y if you want
   to get read access to files on NTFS partitions of your hard drive.
@@ -8804,7 +8872,7 @@
 
   If unsure, say N.
 
-System V and Coherent filesystem support (read only)
+System V and Coherent file system support (read only)
 CONFIG_SYSV_FS
   SCO, Xenix and Coherent are commercial Unix systems for Intel
   machines. Saying Y here would allow you to read from their floppies
@@ -8820,15 +8888,15 @@
   ftp://tsx-11.mit.edu/pub/linux/BETA ).
 
   If you only intend to mount files from some other Unix over the
-  network using NFS, you don't need the System V filesystem support
-  (but you need NFS filesystem support obviously). 
+  network using NFS, you don't need the System V file system support
+  (but you need NFS file system support obviously). 
 
   Note that this option is generally not needed for floppies, since a
   good portable way to transport files and directories between unixes
   (and even other operating systems) is given by the tar program ("man
   tar" or preferably "info tar"). Note also that this option has
   nothing whatsoever to do with the option "System V IPC". Read about
-  the System V filesystem in Documentation/filesystems/sysv-fs.txt.
+  the System V file system in Documentation/filesystems/sysv-fs.txt.
   Saying Y here will enlarge your kernel by about 27 kB.
 
   If you want to compile this as a module ( = code which can be
@@ -8838,7 +8906,7 @@
 
   If you haven't heard about all of this before, it's safe to say N.
 
-SYSV filesystem write support (DANGEROUS)
+SYSV file system write support (DANGEROUS)
 CONFIG_SYSV_FS_WRITE
   If you say Y here, you will (hopefully) be able to write to System V
   and Coherent file systems as well as read from them. The read-write
@@ -8847,9 +8915,9 @@
 
   If unsure, say N.
 
-Amiga FFS filesystem support
+Amiga FFS file system support
 CONFIG_AFFS_FS
-  The Fast File System (FFS) is the common filesystem used on hard
+  The Fast File System (FFS) is the common file system used on hard
   disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y
   if you want to be able to read and write files from and to an Amiga
   FFS partition on your hard drive. Amiga floppies however cannot be
@@ -8863,31 +8931,31 @@
   If you want to do this, you will also need to say Y or M to "Loop
   device support", above.
 
-  This filesystem is also available as a module ( = code which can be
+  This file system is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module is called affs.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt. If unsure, say N.
 
-Apple Macintosh filesystem support (EXPERIMENTAL)
+Apple Macintosh file system support (EXPERIMENTAL)
 CONFIG_HFS_FS
   If you say Y here, you will be able to mount Macintosh-formatted
   floppy disks and hard drive partitions with full read-write access.
   Please read fs/hfs/HFS.txt to learn about the available mount
   options. 
 
-  This filesystem support is also available as a module ( = code which
+  This file system support is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). The module is called hfs.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-ROM filesystem support
+ROM file system support
 CONFIG_ROMFS_FS
-  This is a very small read-only filesystem mainly intended for
+  This is a very small read-only file system mainly intended for
   initial ram disks of installation disks, but it could be used for
   other read-only media as well. Read
   Documentation/filesystems/romfs.txt for details. 
 
-  This filesystem support is also available as a module ( = code which
+  This file system support is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). The module is called romfs.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt. 
@@ -8895,14 +8963,14 @@
   If you don't know whether you need it, then you don't need it:
   answer N.
 
-QNX4 filesystem support (read only) (EXPERIMENTAL)
+QNX4 file system support (read only) (EXPERIMENTAL)
 CONFIG_QNX4FS_FS  
-  This is the filesystem used by the operating system QNX 4. Say Y if
+  This is the file system used by the operating system QNX 4. Say Y if
   you intend to mount QNX hard disks or floppies. Unless you say Y to
   "QNX4FS write support" below, you will only be able to read
-  these filesystems.
+  these file systems.
 
-  This filesystem support is also available as a module ( = code which
+  This file system support is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). The module is called qnx4.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt. 
@@ -8912,18 +8980,18 @@
 
 QNX4FS write support (DANGEROUS)
 CONFIG_QNX4FS_RW
-  Say Y if you want to test write support for QNX4 filesystems.
+  Say Y if you want to test write support for QNX4 file systems.
 
 Kernel automounter support
 CONFIG_AUTOFS_FS
-  The automounter is a tool to automatically mount remote filesystems
+  The automounter is a tool to automatically mount remote file systems
   on demand. This implementation is partially kernel-based to reduce
   overhead in the already-mounted case; this is unlike the BSD
   automounter (amd), which is a pure user space daemon.
 
   To use the automounter you need the user-space tools from
   ftp://ftp.kernel.org/pub/linux/daemons/autofs ; you also want to
-  answer Y to "NFS filesystem support", below.
+  answer Y to "NFS file system support", below.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -8936,16 +9004,16 @@
   If you want to use the newer version of autofs with more features,
   say N here and select automounter v4.
 
-Kernel automounter v4 support
+Kernel automounter version 4 support (also supports v3)
 CONFIG_AUTOFS4_FS
-  The automounter is a tool to automatically mount remote filesystems
+  The automounter is a tool to automatically mount remote file systems
   on demand. This implementation is partially kernel-based to reduce
   overhead in the already-mounted case; this is unlike the BSD
   automounter (amd), which is a pure user space daemon.
 
   To use the automounter you need the user-space tools from
   ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4 ; you also
-  want to answer Y to "NFS filesystem support", below.
+  want to answer Y to "NFS file system support", below.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -8957,17 +9025,17 @@
   have a laptop which needs to dynamically reconfigure to the local
   network, you probably do not need an automounter, and can say N here.
 
-EFS filesystem support (read only) (EXPERIMENTAL)
+EFS file system support (read only) (EXPERIMENTAL)
 CONFIG_EFS_FS
-  EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk
+  EFS is an older file system used for non-ISO9660 CDROMs and hard disk
   partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses
-  the XFS filesystem for hard disk partitions however).
+  the XFS file system for hard disk partitions however).
 
   This implementation only offers read-only access. If you don't know
   what all this is about, it's safe to say N. For more information
   about EFS see its home page at http://aeschi.ch.eu.org/efs/ .
 
-  If you want to compile the EFS filesystem support as a module ( =
+  If you want to compile the EFS file system support as a module ( =
   code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
   The module will be called efs.o. 
@@ -8977,19 +9045,19 @@
   Say Y to this only if you plan on mounting disks with SGI
   disklabels. This is not required to mount EFS-format CDROMs.
 
-UFS filesystem support (read only)
+UFS file system support (read only)
 CONFIG_UFS_FS
   BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
-  OpenBSD and NeXTstep) use a filesystem called UFS. Some System V
+  OpenBSD and NeXTstep) use a file system called UFS. Some System V
   Unixes can create and mount hard disk partitions and diskettes using
-  this filesystem as well. Saying Y here will allow you to read from
+  this file system as well. Saying Y here will allow you to read from
   these partitions; if you also want to write to them, say Y to the
-  experimental "UFS filesystem write support", below. Please read the
+  experimental "UFS file system write support", below. Please read the
   file Documentation/filesystems/ufs.txt for more information.
 
   If you only intend to mount files from some other Unix over the
-  network using NFS, you don't need the UFS filesystem support (but
-  you need NFS filesystem support obviously). 
+  network using NFS, you don't need the UFS file system support (but
+  you need NFS file system support obviously). 
 
   Note that this option is generally not needed for floppies, since a
   good portable way to transport files and directories between unixes
@@ -9000,14 +9068,14 @@
   NeXT character set to the Latin1 character set; use the program
   recode ("info recode") for this purpose. 
 
-  If you want to compile the UFS filesystem support as a module ( =
+  If you want to compile the UFS file system support as a module ( =
   code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
   The module will be called ufs.o. 
 
   If you haven't heard about all of this before, it's safe to say N.
 
-UFS filesystem write support (DANGEROUS)
+UFS file system write support (DANGEROUS)
 CONFIG_UFS_FS_WRITE
   Say Y here if you want to try writing to UFS partitions. This is
   experimental, so you should back up your UFS partitions beforehand.
@@ -9045,7 +9113,7 @@
   first sector a new partition table in BSD disklabel format. Saying Y
   here allows you to read these disklabels and further mount FreeBSD
   partitions from within Linux if you have also said Y to "UFS
-  filesystem support", above. If you don't know what all this is
+  file system support", above. If you don't know what all this is
   about, say N.
 
 Sun partition tables support
@@ -9053,7 +9121,7 @@
   Like most systems, SunOS uses its own hard disk partition table
   format, incompatible with all others. Saying Y here allows you to
   read these partition tables and further mount SunOS partitions from
-  within Linux if you have also said Y to "UFS filesystem support",
+  within Linux if you have also said Y to "UFS file system support",
   above. 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; note however that a good portable way to transport files and
@@ -9067,16 +9135,16 @@
   table format, incompatible with all others. Saying Y here allows you
   to read these partition tables and further mount Solaris x86
   partitions from within Linux if you have also said Y to "UFS
-  filesystem support", above.
+  file system support", above.
 
 SGI partition support
 CONFIG_SGI_PARTITION
   Say Y here if you would like to be able to read the hard disk
   partition table format used by SGI machines.
 
-ADFS filesystem support (read only) (EXPERIMENTAL)
+ADFS file system support (read only) (EXPERIMENTAL)
 CONFIG_ADFS_FS
-  The Acorn Disc Filing System is the standard filesystem of the
+  The Acorn Disc Filing System is the standard file system of the
   RiscOS operating system which runs on Acorn's ARM-based Risc PC
   systems and the Acorn Archimedes range of machines. If you say Y
   here, Linux will be able to read from ADFS partitions on hard drives
@@ -9093,10 +9161,10 @@
 
   If unsure, say N.
 
-/dev/pts filesystem for Unix98 PTYs
+/dev/pts file system for Unix98 PTYs
 CONFIG_DEVPTS_FS
   You should say Y here if you said Y to "Unix98 PTY support" above.
-  You'll then get a virtual filesystem which can be mounted on
+  You'll then get a virtual file system which can be mounted on
   /dev/pts with "mount -t devpts". This, together with the pseudo
   terminal master multiplexer /dev/ptmx, is used for pseudo terminal
   support as described in The Open Group's Unix98 standard: in order
@@ -9117,8 +9185,9 @@
   partition (VTOC - Virtual Table of Contents). Its format is
   incompatible with all other OSes. Saying Y here allows you to read
   VTOC and further mount UnixWare partitions read-only from within
-  Linux if you have also said Y to "UFS filesystem support" or "System
-  V and Coherent filesystem support", above.
+  Linux if you have also said Y to "UFS file system support", "System
+  V and Coherent file system support" or "BFS file system support",
+  above.
 
   This is mainly used to carry data from a UnixWare box to your
   Linux box via a removable medium like magneto-optical, ZIP or
@@ -9129,12 +9198,12 @@
 
   If you don't know what all this is about, say N.
 
-SMB filesystem support (to mount Windows shares etc.)
+SMB file system support (to mount Windows shares etc.)
 CONFIG_SMB_FS
   SMB (Server Message Block) is the protocol Windows for Workgroups
   (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share
   files and printers over local networks. Saying Y here allows you to
-  mount their filesystems (often called "shares" in this context) and
+  mount their file systems (often called "shares" in this context) and
   access them just like any other Unix directory. Currently, this
   works only if the Windows machines use TCP/IP as the underlying
   transport protocol, and not NetBEUI. For details, read
@@ -9155,10 +9224,10 @@
   want), say M here and read Documentation/modules.txt. The module
   will be called smbfs.o. Most people say N, however.
 
-Coda filesystem support (advanced network fs)
+Coda file system support (advanced network fs)
 CONFIG_CODA_FS
-  Coda is an advanced network filesystem, similar to NFS in that it
-  enables you to mount filesystems of a remote server and access them
+  Coda is an advanced network file system, similar to NFS in that it
+  enables you to mount file systems of a remote server and access them
   with regular Unix commands as if they were sitting on your hard
   disk. Coda has several advantages over NFS: support for disconnected
   operation (e.g. for laptops), read/write server replication,
@@ -9176,7 +9245,7 @@
   whenever you want), say M here and read Documentation/modules.txt.
   The module will be called coda.o. 
 
-NCP filesystem support (to mount NetWare volumes)
+NCP file system support (to mount NetWare volumes)
 CONFIG_NCP_FS
   NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
   used by Novell NetWare clients to talk to file servers. It is to IPX
@@ -9284,7 +9353,7 @@
 
 nls codepage 437
 CONFIG_NLS_CODEPAGE_437
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored
   in so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9295,7 +9364,7 @@
 
 nls codepage 737
 CONFIG_NLS_CODEPAGE_737
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored
   in so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9306,7 +9375,7 @@
 
 nls codepage 775
 CONFIG_NLS_CODEPAGE_775
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored
   in so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9317,7 +9386,7 @@
 
 nls codepage 850
 CONFIG_NLS_CODEPAGE_850
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9332,7 +9401,7 @@
 
 nls codepage 852
 CONFIG_NLS_CODEPAGE_852
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9346,7 +9415,7 @@
 
 nls codepage 855
 CONFIG_NLS_CODEPAGE_855
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9356,7 +9425,7 @@
 
 nls codepage 857
 CONFIG_NLS_CODEPAGE_857
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9366,7 +9435,7 @@
 
 nls codepage 860
 CONFIG_NLS_CODEPAGE_860
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9376,7 +9445,7 @@
 
 nls codepage 861
 CONFIG_NLS_CODEPAGE_861
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9386,7 +9455,7 @@
 
 nls codepage 862
 CONFIG_NLS_CODEPAGE_862
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9396,7 +9465,7 @@
 
 nls codepage 863
 CONFIG_NLS_CODEPAGE_863
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9407,7 +9476,7 @@
 
 nls codepage 864
 CONFIG_NLS_CODEPAGE_864
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9417,7 +9486,7 @@
 
 nls codepage 865
 CONFIG_NLS_CODEPAGE_865
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9428,7 +9497,7 @@
 
 nls codepage 866
 CONFIG_NLS_CODEPAGE_866
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9439,7 +9508,7 @@
 
 nls codepage 869
 CONFIG_NLS_CODEPAGE_869
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9452,7 +9521,7 @@
 
 nls codepage 874
 CONFIG_NLS_CODEPAGE_874
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft fat file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -9463,7 +9532,7 @@
 nls iso8859-1
 CONFIG_NLS_ISO8859_1
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 1 character
   set, which covers most West European languages such as Albanian,
@@ -9474,7 +9543,7 @@
 nls iso8859-2
 CONFIG_NLS_ISO8859_2
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 2 character
   set, which works for most Latin-written Slavic and Central European
@@ -9484,7 +9553,7 @@
 nls iso8859-3
 CONFIG_NLS_ISO8859_3
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 3 character
   set, which is popular with authors of Esperanto, Galician, Maltese,
@@ -9493,7 +9562,7 @@
 nls iso8859-4
 CONFIG_NLS_ISO8859_4
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 4 character
   set which introduces letters for Estonian, Latvian, and
@@ -9502,7 +9571,7 @@
 nls iso8859-5
 CONFIG_NLS_ISO8859_5
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for ISO8859-5, a Cyrillic
   character set with which you can type Bulgarian, Byelorussian,
@@ -9512,7 +9581,7 @@
 nls iso8859-6
 CONFIG_NLS_ISO8859_6
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for ISO8859-6, the Arabic
   character set.
@@ -9520,7 +9589,7 @@
 nls iso8859-7
 CONFIG_NLS_ISO8859_7
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for ISO8859-7, the Modern
   Greek character set.
@@ -9528,7 +9597,7 @@
 nls iso8859-8
 CONFIG_NLS_ISO8859_8
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for ISO8859-8, the Hebrew
   character set.
@@ -9536,7 +9605,7 @@
 nls iso8859-9
 CONFIG_NLS_ISO8859_9
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 5 character
   set, and it replaces the rarely needed Icelandic letters in Latin 1
@@ -9545,7 +9614,7 @@
 nls iso8859-10
 CONFIG_NLS_ISO8859_10
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 6 character
   set, which adds the last Inuit (Greenlandic) and Sami (Lappish)
@@ -9555,7 +9624,7 @@
 NLS ISO 8859-14 (Latin 8; Celtic)
 CONFIG_NLS_ISO8859_14
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 8 character
   set, which adds the last accented vowels for Welsh (aka Cymraeg)
@@ -9565,7 +9634,7 @@
 nls iso8859-15
 CONFIG_NLS_ISO8859_15
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the Latin 9 character
   set, which covers most West European languages such as Albanian,
@@ -9580,7 +9649,7 @@
 nls koi8-r
 CONFIG_NLS_KOI8_R
   If you want to display filenames with native language characters
-  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  from the Microsoft fat file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the preferred Russian
   character set.
@@ -9915,8 +9984,8 @@
   traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
 
   The entries in /dev/pts/ are created on the fly by a virtual
-  filesystem; therefore, if you say Y here you should say Y to
-  "/dev/pts filesystem for Unix98 PTYs" as well.
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
 
   If you want to say Y here, you need to have the C library glibc 2.1
   or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
@@ -9969,7 +10038,7 @@
   option "console=lp" to the kernel at boot time.
 
   Note that kernel messages can get lost if the printer is out of
-  paper (or off, or unplugged, or too busy..), but this behaviour
+  paper (or off, or unplugged, or too busy..), but this behavior
   can be changed. See drivers/char/lp.c (do this at your own risk).
 
   If unsure, say N.
@@ -10238,7 +10307,7 @@
 Procfs entry for ftape
 CONFIG_FT_PROC_FS
   Optional. Saying Y will result in creation of a directory
-  `/proc/ftape' under the proc file system. The files can be viewed
+  `/proc/ftape' under the /proc file system. The files can be viewed
   with your favorite pager (i.e. use "more /proc/ftape/history" or
   "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The
   file will contain some status information about the inserted
@@ -10248,9 +10317,10 @@
   by approximately 2 KB.
 
   WARNING: When compiling ftape as a module (i.e. saying M to
-  "Floppy tape drive") it is dangerous to use ftape's proc file system
-  interface. Accessing `/proc/ftape' while the module is unloaded will
-  result in a kernel Oops. This cannot be fixed from inside ftape.
+  "Floppy tape drive") it is dangerous to use ftape's /proc file
+  system interface. Accessing `/proc/ftape' while the module is
+  unloaded will result in a kernel Oops. This cannot be fixed from
+  inside ftape.
 
 Controlling the amount of debugging output of ftape
 CONFIG_FT_NORMAL_DEBUG
@@ -10579,6 +10649,11 @@
    11) exchange RAM chips 
    12) exchange the motherboard.
 
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read Documentation/modules.txt. The module will be called
+  apm.o.
+
 Ignore USER SUSPEND
 CONFIG_APM_IGNORE_USER_SUSPEND
   This option will ignore USER SUSPEND requests. On machines with a
@@ -10660,14 +10735,6 @@
   many of the newer IBM Thinkpads.  If you experience hangs when you
   suspend, try setting this to Y.  Otherwise, say N.
 
-Entry point offset fix (some Acer laptops)
-CONFIG_APM_BAD_ENTRY_OFFSET
-  Some implementations of the APM BIOS provide the driver with a bad
-  entry point offset.  If you set this option to Y, then the upper
-  sixteen bits of the offset will be set to zero.  This is usually
-  unnecessary but harmless.  This is required for the Acer Travelmate
-  510DX, Travelmate 510T and Extensa 503T.  For others, say N.
-
 Use real mode APM BIOS call to power off
 CONFIG_APM_REAL_MODE_POWER_OFF
   Use real mode APM BIOS calls to switch off the computer. This is
@@ -10699,7 +10766,7 @@
 
 Disable watchdog shutdown on close
 CONFIG_WATCHDOG_NOWAYOUT
-  The default watchdog behaviour (which you get if you say N here) is
+  The default watchdog behavior (which you get if you say N here) is
   to stop the timer if the process managing it closes the file
   /dev/watchdog. It's always remotely possible that this process might
   get killed. If you say Y here, the watchdog cannot be stopped once
@@ -10799,7 +10866,7 @@
   Every PC has such a clock built in. It can be used to generate
   signals from as low as 1Hz up to 8192Hz, and can also be used
   as a 24 hour alarm. It reports status information via the file
-  /proc/driver/rtc and its behaviour is set by various ioctls on
+  /proc/driver/rtc and its behavior is set by various ioctls on
   /dev/rtc.
 
   If you run Linux on a multiprocessor machine and said Y to
@@ -10992,7 +11059,7 @@
   row.
 
   Do not hold the button down for too long, as the driver does not
-  alter the behaviour of the hardware reset circuitry attached to the
+  alter the behavior of the hardware reset circuitry attached to the
   button; it will still execute a hard reset if the button is held
   down for longer than approximately five seconds.
 
@@ -12335,7 +12402,7 @@
   Say Y if you want your expansion cards to be identified on bootup;
   it will enlarge your kernel by about 10 KB. The identification
   information is also available through /proc/zorro (say Y to
-  "/proc filesystem support"!).
+  "/proc file system support"!).
 
   Note that even if you say N here, you can still use your expansion
   cards. If in doubt, say Y.
@@ -13114,7 +13181,7 @@
 
 Colour QuickCam Video For Linux
 CONFIG_VIDEO_CQCAM
-  This is the video4linux driver for the colour version of the
+  This is the video4linux driver for the color version of the
   Connectix Quickcam. If you have one of these cameras, say Y here,
   otherwise say N. This driver does not work with the original
   monochrome Quickcam, Quickcam VC or QuickClip. It is also available
@@ -13167,7 +13234,7 @@
   megs due to kernel allocation issues), you could use PCI accesses
   and have up to a couple gigs of texture space.
 
-  Note that this is the only meas to have get XFree4/GLX use
+  Note that this is the only mean to have get XFree4/GLX use
   write-combining with MTRR support on AGP bus. Without, OpenGL
   direct rendering will be a lot slower but still faster than PIO.
 
@@ -13306,7 +13373,7 @@
   Say Y to include the NWFPE floating point emulator in the kernel.
   This is necessary to run most binaries. Linux does not currently
   support floating point hardware so you need to say Y here even if
-  your machine has an FPA or floating point co-processor podule.
+  your machine has an FPA or floating point co-processor module.
 
   It is also possible to say M to build the emulator as a module
   (nwfpe.o) or indeed to leave it out altogether. However, unless you
@@ -13363,12 +13430,12 @@
   time and disk space needed for compilation of the kernel. If in
   doubt say N.
 
-Split initialisation functions into discardable section
+Split initialization functions into discardable section
 CONFIG_TEXT_SECTIONS
   If you say Y here, kernel code that is only used during
-  initialisation is collected into a special area of the kernel so
+  initialization is collected into a special area of the kernel so
   that it can be discarded and the memory reclaimed when
-  initialisation is complete. In addition, if the kernel you wish to
+  initialization is complete. In addition, if the kernel you wish to
   build is able to run on multiple architectures, it allows the unused
   code to be discarded. Some versions of binutils, however, have a bug
   that causes the kernel to crash during startup when this option is
@@ -13429,7 +13496,7 @@
 MFM hard disk support
 CONFIG_BLK_DEV_MFM
   Support the MFM hard drives on the Acorn Archimedes both
-  on-board the A4x0 motherboards and via the Acorn MFM podules.
+  on-board the A4x0 motherboards and via the Acorn MFM modules.
   Drives up to 64MB are supported. If you haven't got one of these
   machines or drives just say N.
 
@@ -13748,7 +13815,7 @@
 CONFIG_KHTTPD
   The kernel httpd acceleration daemon (kHTTPd) is a (limited) 
   web server build into the kernel. It is limited since it can only
-  serve files from the filesystem. Saying "M" here builds the
+  serve files from the file system. Saying "M" here builds the
   kHTTPd module; this is NOT enough to have a working kHTTPd. 
   For safety reasons, the module has to be activated by doing a
   "echo 1 > /proc/sys/net/khttpd/start" after inserting the module.
@@ -13824,7 +13891,7 @@
 # LocalWords:  CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab
 # LocalWords:  unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz
 # LocalWords:  cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd
-# LocalWords:  HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN
+# LocalWords:  HD CDROMs IDECD NEC MITSUMI XT XD PCI BIOS cezar ATEN
 # LocalWords:  ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt
 # LocalWords:  BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB
 # LocalWords:  netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP
@@ -13854,7 +13921,7 @@
 # LocalWords:  readprofile diskdrives org com masq EtherTalk tcp netrom sunacm
 # LocalWords:  misc AIC aic pio scc Portmaster eql GIS PhotoCDs MCDX Perell PG
 # LocalWords:  mcdx gscd optcd sjcd ISP hdparm Workgroups Lan samba PARIDE PCD
-# LocalWords:  filesystems smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI
+# LocalWords:  smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI
 # LocalWords:  chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport
 # LocalWords:  Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
 # LocalWords:  Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
@@ -13876,7 +13943,7 @@
 # LocalWords:  AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm
 # LocalWords:  Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT
 # LocalWords:  OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP
-# LocalWords:  NOWAYOUT behaviour dialin isdn callback BTX Teles ICN EDSS Cisco
+# LocalWords:  NOWAYOUT behavior dialin isdn callback BTX Teles ICN EDSS Cisco
 # LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
 # LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
 # LocalWords:  initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
@@ -13981,7 +14048,7 @@
 # LocalWords:  struct APIC realtime OSs LynxOS CNC tmp cvf HFS hfs ADFS Risc os
 # LocalWords:  adfs ncpmount namespace SUBDIR reexport NDS kcore FT SPX spx DAT
 # LocalWords:  interserver BLKSZ NUMBUFFERS apmd Tadpole ANA roestock QuickCam
-# LocalWords:  isapnptools Colour CQCAM colour Connectix QuickClip prive mentre
+# LocalWords:  isapnptools Colour CQCAM color Connectix QuickClip prive mentre
 # LocalWords:  KMOD kmod conformant utexas kharker UnixWare Mwave cgi cl ts ibm
 # LocalWords:  eXchange threepio oakland simtel pre ULTRAMCA EtherLink isa luik
 # LocalWords:  EtherLink OpenBSD pts DEVPTS devpts ptmx ttyp glibc readback SA
@@ -14045,7 +14112,7 @@
 # LocalWords:  VROOTHUB KBD ARRs MCRs NWBUTTON nwbutton NUM WaveArtist APNE cpu
 # LocalWords:  apne blackhawke PlanB lu mlan planb NWFPE FPA nwfpe unbootable
 # LocalWords:  FPEmulator ds vmlinux initialisation discardable pgtable PGT mdw
-# LocalWords:  quicklist pagetable arthur StrongARM podule podules Autodetect
+# LocalWords:  quicklist pagetable arthur StrongARM module modules Autodetect
 # LocalWords:  dodgy IrPORT irport Litelink litelink SuSE rtfm internet hda CY
 # LocalWords:  multmode DriveReady SeekComplete DriveStatusError miscompile AEC
 # LocalWords:  mainboard's Digital's alim FastTrak aec PIIXn piix Gayle Eyetech
diff -u --recursive --new-file v2.3.46/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- v2.3.46/linux/Documentation/DMA-mapping.txt	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/DMA-mapping.txt	Fri Feb 18 15:07:20 2000
@@ -28,19 +28,126 @@
 
 #include <linux/pci.h>
 
-is in your driver. This file defines a dma_addr_t type which should be
-used everywhere you hold a DMA (bus) address returned from the DMA mapping
-functions.
+is in your driver. This file will obtain for you the definition of
+the dma_addr_t type which should be used everywhere you hold a DMA
+(bus) address returned from the DMA mapping functions.
+
+			DMA addressing limitations
+
+Does your device have any DMA addressing limitations?  For example, is
+your device only capable of driving the low order 24-bits of address
+on the PCI bus for DMA transfers?  If your device can handle any PCI
+dma address fully, then please skip to the next section, the rest of
+this section does not concern your device.
+
+For correct operation, you must interrogate the PCI layer in your
+device probe routine to see if the PCI controller on the machine can
+properly support the DMA addressing limitation your device has.  This
+query is performed via a call to pci_dma_supported():
+
+	int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask)
+
+Here, pdev is a pointer to the PCI device struct of your device, and
+device_mask is a bit mask describing which bits of a PCI address your
+device supports.  It returns non-zero if your card can perform DMA
+properly on the machine.  If it returns zero, your device can not
+perform DMA properly on this platform, and attempting to do so will
+result in undefined behavior.
+
+In the failure case, you have two options:
+
+1) Use some non-DMA mode for data transfer, if possible.
+2) Ignore this device and do not initialize it.
+
+It is recommended that your driver print a kernel KERN_WARN message
+when you do one of these two things.  In this manner, if a user of
+your driver reports that performance is bad or that the device is not
+even detected, you can ask him for the kernel messages to find out
+exactly why.
+
+So if, for example, you device can only drive the low 24-bits of
+address during PCI bus mastering you might do something like:
+
+	if (! pci_dma_supported(pdev, 0x00ffffff))
+		goto ignore_this_device;
+
+There is a case which we are aware of at this time, which is worth
+mentioning in this documentation.  If your device supports multiple
+functions (for example a sound card provides playback and record
+functions) and the various different functions have _different_
+DMA addressing limitations, you may wish to probe each mask and
+only provide the functionality which the machine can handle.
+Here is pseudo-code showing how this might be done:
+
+	#define PLAYBACK_ADDRESS_BITS	0xffffffff
+	#define RECORD_ADDRESS_BITS	0x00ffffff
+
+	struct my_sound_card *card;
+	struct pci_dev *pdev;
+
+	...
+	if (pci_dma_supported(pdev, PLAYBACK_ADDRESS_BITS)) {
+		card->playback_enabled = 1;
+	} else {
+		card->playback_enabled = 0;
+		printk(KERN_WARN "%s: Playback disabled due to DMA limitations.\n",
+		       card->name);
+	}
+	if (pci_dma_supported(pdev, RECORD_ADDRESS_BITS)) {
+		card->record_enabled = 1;
+	} else {
+		card->record_enabled = 0;
+		printk(KERN_WARN "%s: Record disabled due to DMA limitations.\n",
+		       card->name);
+	}
+
+A sound card was used as an example here because this genre of PCI
+devices seems to be littered with ISA chips given a PCI front end,
+and thus retaining the 16MB DMA addressing limitations of ISA.
+
+			Types of DMA mappings
 
 There are two types of DMA mappings:
-- static DMA mappings which are usually mapped at driver initialization,
-  unmapped at the end and for which the hardware should not assume
-  sequential accesses (from both the DMA engine in the card and CPU).
-- streaming DMA mappings which are usually mapped for one DMA transfer,
+
+- Consistent DMA mappings which are usually mapped at driver
+  initialization, unmapped at the end and for which the hardware should
+  guarentee that the device and the cpu can access the data
+  in parallel and will see updates made by each other without any
+  explicit software flushing.
+
+  Think of "consistent" as "synchronous" or "coherent".
+
+  Good examples of what to use consistent mappings for are:
+
+	- Network card DMA ring descriptors.
+	- SCSI adapter mailbox command data structures.
+	- Device firmware microcode executed out of
+	  main memory.
+
+  The invariant these examples all require is that any cpu store
+  to memory is immediately visible to the device, and vice
+  versa.  Consistent mappings guarentee this.
+
+- Streaming DMA mappings which are usually mapped for one DMA transfer,
   unmapped right after it (unless you use pci_dma_sync below) and for which
   hardware can optimize for sequential accesses.
 
-To allocate and map a static DMA region, you should do:
+  This of "streaming" as "asynchronous" or "outside the coherency
+  domain".
+
+  Good examples of what to use streaming mappings for are:
+
+	- Networking buffers transmitted/received by a device.
+	- Filesystem buffers written/read by a SCSI device.
+
+  The interfaces for using this type of mapping were designed in
+  such a way that an implementation can make whatever performance
+  optimizations the hardware allows.  To this end, when using
+  such mappings you must be explicit about what you want to happen.
+
+		 Using Consistent DMA mappings.
+
+To allocate and map a consistent DMA region, you should do:
 
 	dma_addr_t dma_handle;
 
@@ -48,13 +155,18 @@
 
 where dev is a struct pci_dev *. You should pass NULL for PCI like buses
 where devices don't have struct pci_dev (like ISA, EISA).
+
 This argument is needed because the DMA translations may be bus
-specific (and often is private to the bus which the device is attached to).
+specific (and often is private to the bus which the device is attached
+to).
+
 Size is the length of the region you want to allocate.
+
 This routine will allocate RAM for that region, so it acts similarly to
-__get_free_pages (but takes size instead of page order).
-It returns two values: the virtual address which you can use to access it
-from the CPU and dma_handle which you pass to the card.
+__get_free_pages (but takes size instead of a page order).
+
+It returns two values: the virtual address which you can use to access
+it from the CPU and dma_handle which you pass to the card.
 
 The cpu return address and the DMA bus master address are both
 guaranteed to be aligned to the smallest PAGE_SIZE order which
@@ -68,7 +180,66 @@
 	pci_free_consistent(dev, size, cpu_addr, dma_handle);
 
 where dev, size are the same as in the above call and cpu_addr and
-dma_handle are the values pci_alloc_consistent returned.
+dma_handle are the values pci_alloc_consistent returned to you.
+
+			DMA Direction
+
+The interfaces described in subsequent portions of this document
+take a DMA direction argument, which is an integer and takes on
+one of the following values:
+
+ PCI_DMA_BIDIRECTIONAL
+ PCI_DMA_TODEVICE
+ PCI_DMA_FROMDEVICE
+ PCI_DMA_NONE
+
+One should provide the exact DMA direction if you know it.
+
+PCI_DMA_TODEVICE means "from main memory to the PCI device"
+PCI_DMA_FROMDEVICE means "from the PCI device to main memory"
+
+Cou are _strongly_ encouraged to specify this as precisely
+as you possibly can.
+
+If you absolutely cannot know the direction of the DMA transfer,
+specify PCI_DMA_BIDIRECTIONAL.  It means that the DMA can go in
+either direction.  The platform guarentees that you may legally
+specify this, and that it will work, but this may be at the
+cost of performance for example.
+
+The value PCI_DMA_NONE is to be used for debugging.  One can
+hold this in a data structure before you come to know the
+precise direction, and this will help catch cases where your
+direction tracking logic has failed to set things up properly.
+
+Another advantage of specifying this value precisely (outside
+of potential platform-specific optimizations of such) is for
+debugging.  Some platforms actually have a write permission
+boolean which DMA mappings can be marked with, much like page
+protections in a user program can have.  Such platforms can
+and do report errors in the kernel logs when the PCI controller
+hardware detects violation of the permission setting.
+
+Only streaming mappings specify a direction, consistent mappings
+implicitly have a direction attribute setting of
+PCI_DMA_BIDIRECTIONAL.
+
+The SCSI subsystem provides mechanisms for you to easily obtain
+the direction to use, in the SCSI command:
+
+	scsi_to_pci_dma_dir(SCSI_DIRECTION)
+
+Where SCSI_DIRECTION is obtained from the 'sc_data_direction'
+member of the SCSI command your driver is working on.  The
+mentioned interface above returns a value suitable for passing
+into the streaming DMA mapping interfaces below.
+
+For Networking drivers, it's a rather simple affair.  For transmit
+packets, map/unmap them with the PCI_DMA_TODEVICE direction
+specifier.  For receive packets, just the opposite, map/unmap them
+with the PCI_DMA_FROMDEVICE direction specifier.
+
+		  Using Streaming DMA mappings
 
 The streaming DMA mapping routines can be called from interrupt context.
 There are two versions of each map/unmap, one which map/unmap a single
@@ -78,18 +249,18 @@
 
 	dma_addr_t dma_handle;
 
-	dma_handle = pci_map_single(dev, addr, size);
+	dma_handle = pci_map_single(dev, addr, size, direction);
 
 and to unmap it:
 
-	pci_unmap_single(dev, dma_handle, size);
+	pci_unmap_single(dev, dma_handle, size, direction);
 
 You should call pci_unmap_single when the DMA activity is finished, e.g.
 from interrupt which told you the DMA transfer is done.
 
 Similarly with scatterlists, you map a region gathered from several regions by:
 
-	int i, count = pci_map_sg(dev, sglist, nents);
+	int i, count = pci_map_sg(dev, sglist, nents, direction);
 	struct scatterlist *sg;
 
 	for (i = 0, sg = sglist; i < count; i++, sg++) {
@@ -98,13 +269,15 @@
 	}
 
 where nents is the number of entries in the sglist.
+
 The implementation is free to merge several consecutive sglist entries
 into one (e.g. if DMA mapping is done with PAGE_SIZE granularity, any
 consecutive sglist entries can be merged into one provided the first one
 ends and the second one starts on a page boundary - in fact this is a huge
 advantage for cards which either cannot do scatter-gather or have very
 limited number of scatter-gather entries) and returns the actual number
-of sg entries it mapped them too.
+of sg entries it mapped them to.
+
 Then you should loop count times (note: this can be less than nents times)
 and use sg_dma_address() and sg_dma_length() macros where you previously
 accessed sg->address and sg->length as shown above.
@@ -114,6 +287,12 @@
 	pci_unmap_sg(dev, sglist, nents);
 
 Again, make sure DMA activity finished.
+
+PLEASE NOTE:  The 'nents' argument to the pci_unmap_sg call must be
+              the _same_ one you passed into the pci_map_sg call,
+	      it should _NOT_ be the 'count' value _returned_ from the
+              pci_map_sg call.
+
 Every pci_map_{single,sg} call should have its pci_unmap_{single,sg}
 counterpart, because the bus address space is a shared resource (although
 in some ports the mapping is per each BUS so less devices contend for the
@@ -124,15 +303,64 @@
 the data in between the DMA transfers, just map it
 with pci_map_{single,sg}, after each DMA transfer call either:
 
-	pci_dma_sync_single(dev, dma_handle, size);
+	pci_dma_sync_single(dev, dma_handle, size, direction);
 
 or:
 
-	pci_dma_sync_sg(dev, sglist, nents);
+	pci_dma_sync_sg(dev, sglist, nents, direction);
 
 and after the last DMA transfer call one of the DMA unmap routines
 pci_unmap_{single,sg}. If you don't touch the data from the first pci_map_*
-call till pci_unmap_*, then you don't have to call pci_sync_* routines.
+call till pci_unmap_*, then you don't have to call the pci_sync_*
+routines at all.
+
+Here is pseudo code which shows a situation in which you would need
+to use the pci_dma_sync_*() interfaces.
+
+	my_card_setup_receive_buffer(struct my_card *cp, char *buffer, int len)
+	{
+		dma_addr_t mapping;
+
+		mapping = pci_map_single(cp->pdev, buffer, len, PCI_DMA_FROMDEVICE);
+
+		cp->rx_buf = buffer;
+		cp->rx_len = len;
+		cp->rx_dma = mapping;
+
+		give_rx_buf_to_card(cp);
+	}
+
+	...
+
+	my_card_interrupt_handler(int irq, void *devid, struct pt_regs *regs)
+	{
+		struct my_card *cp = devid;
+
+		...
+		if (read_card_status(cp) == RX_BUF_TRANSFERRED) {
+			struct my_card_header *hp;
+
+			/* Examine the header to see if we wish
+			 * to except the data.  But synchronize
+			 * the DMA transfer with the CPU first
+			 * so that we see updated contents.
+			 */
+			pci_dma_sync_single(cp->pdev, cp->rx_buf, cp->rx_len,
+					    PCI_DMA_FROMDEVICE);
+
+			/* Now it is safe to examine the buffer. */
+			hp = (struct my_card_header *) cp->rx_buf;
+			if (header_is_ok(hp)) {
+				pci_unmap_single(cp->pdev, cp->rx_buf, cp->rx_len,
+						 PCI_DMA_FROMDEVICE);
+				pass_to_upper_layers(cp->rx_buf);
+				make_and_setup_new_rx_buf(cp);
+			} else {
+				/* Just give the buffer back to the card. */
+				give_rx_buf_to_card(cp);
+			}
+		}
+	}
 
 Drivers converted fully to this interface should not use virt_to_bus any
 longer, nor should they use bus_to_virt. Some drivers have to be changed a
@@ -142,8 +370,14 @@
 stores them in the scatterlist itself if the platform supports dynamic DMA
 mapping in hardware) in your driver structures and/or in the card registers.
 
-For PCI cards which recognize fewer address lines than 32 in Single
-Address Cycle, you should set corresponding pci_dev's dma_mask field to a
-different mask. The dma mapping routines then should either honour your request
-and allocate the DMA only with the bus address with bits set in your
-dma_mask or should complain that the device is not supported on that platform.
+This document, and the API itself, would not be in it's current
+form without the feedback and suggestions from numerous individuals.
+We would like to specifically mention, in no particular order, the
+following people:
+
+	Russell King <rmk@arm.linux.org.uk>
+	Leo Dagum <dagum@barrel.engr.sgi.com>
+	Ralf Baechle <ralf@oss.sgi.com>
+	Grant Grundler <grundler@cup.hp.com>
+	Jay Estabrook <Jay.Estabrook@compaq.com>
+	Thomas Sailer <sailer@ife.ee.ethz.ch>
diff -u --recursive --new-file v2.3.46/linux/Documentation/LVM-HOWTO linux/Documentation/LVM-HOWTO
--- v2.3.46/linux/Documentation/LVM-HOWTO	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/LVM-HOWTO	Thu Feb 17 16:13:04 2000
@@ -0,0 +1,119 @@
+Heinz Mauelshagen's LVM (Logical Volume Manager) howto.             02/10/1999
+
+
+Abstract:
+---------
+The LVM adds a kind of virtual disks and virtual partitions functionality
+to the Linux operating system.
+
+It achieves this by adding an additional layer between the physical peripherals
+and the i/o interface in the kernel.
+
+This allows the concatenation of several disk partitions or total disks
+(so-called physical volumes or PVs) or even multiple devices
+to form a storage pool (so-called Volume Group or VG) with
+allocation units called physical extents (called PE).
+You can think of the volume group as a virtual disk.
+Please see scenario below.
+
+Some or all PEs of this VG then can be allocated to so-called Logical Volumes
+or LVs in units called logical extents or LEs.
+Each LE is mapped to a corresponding PE.
+LEs and PEs are equal in size.
+Logical volumes are a kind of virtual partitions.
+
+
+The LVs can be used through device special files similar to the known
+/dev/sd[a-z]* or /dev/hd[a-z]* named /dev/VolumeGroupName/LogicalVolumeName.
+
+But going beyond this, you are able to extend or reduce
+VGs _AND_ LVs at runtime!
+
+So...
+If for example the capacity of a LV gets too small and your VG containing
+this LV is full, you could add another PV to that VG and simply extend
+the LV afterwards.
+If you reduce or delete a LV you can use the freed capacity for different
+LVs in the same VG.
+
+
+The above scenario looks like this:
+
+     /------------------------------------------\
+     |  /--PV2---\      VG 1      /--PVn---\    |
+     |  |-VGDA---|                |-VGDA-- |    |
+     |  |PE1PE2..|                |PE1PE2..|    |
+     |  |        |     ......     |        |    |
+     |  |        |                |        |    |
+     |  |    /-----------------------\     |    |
+     |  |    \-------LV 1------------/     |    |
+     |  |   ..PEn|                |   ..PEn|    |
+     |  \--------/                \--------/    |
+     \------------------------------------------/
+
+PV 1 could be /dev/sdc1 sized 3GB
+PV n could be /dev/sde1 sized 4GB
+VG 1 could be test_vg
+LV 1 could be /dev/test_vg/test_lv
+VGDA is the volume group descriptor area holding the LVM metadata
+PE1 up to PEn is the number of physical extents on each disk(partition)
+
+
+
+Installation steps see INSTALL and insmod(1)/modprobe(1), kmod/kerneld(8)
+to load the logical volume manager module if you did not bind it
+into the kernel.
+
+
+Configuration steps for getting the above scenario:
+
+1. Set the partition system id to 0x8e on /dev/sdc1 and /dev/sde1.
+
+2. do a "pvcreate /dev/sd[ce]1"
+   For testing purposes you can use more than one partition on a disk.
+   You should not use more than one partition because in the case of
+   a striped LV you'll have a performance breakdown.
+
+3. do a "vgcreate test_vg /dev/sd[ce]1" to create the new VG named "test_vg"
+   which has the total capacity of both partitions.
+   vgcreate activates (transfers the metadata into the LVM driver in the kernel)
+   the new volume group too to be able to create LVs in the next step.
+
+4. do a "lvcreate -L1500 -ntest_lv test_vg" to get a 1500MB linear LV named
+   "test_lv" and it's block device special "/dev/test_vg/test_lv".
+
+   Or do a "lvcreate -i2 -I4 -l1500 -nanother_test_lv test_vg" to get a 100 LE
+   large logical volume with 2 stripes and stripesize 4 KB.
+
+5. For example generate a filesystem in one LV with
+   "mke2fs /dev/test_vg/test_lv" and mount it.
+
+6. extend /dev/test_vg/test_lv to 1600MB with relative size by
+   "lvextend -L+100 /dev/test_vg/test_lv"
+   or with absolute size by
+   "lvextend -L1600 /dev/test_vg/test_lv"
+ 
+7. reduce /dev/test_vg/test_lv to 900 logical extents with relative extents by
+   "lvreduce -l-700 /dev/test_vg/test_lv"
+   or with absolute extents by
+   "lvreduce -l900 /dev/test_vg/test_lv"
+ 
+9. rename a VG by deactivating it with
+   "vgchange -an test_vg"   # only VGs with _no_ open LVs can be deactivated!
+   "vgrename test_vg whatever"
+   and reactivate it again by
+   "vgchange -ay whatever"
+
+9. rename a LV after closing it by
+   "lvchange -an /dev/whatever/test_lv" # only closed LVs can be deactivated
+   "lvrename  /dev/whatever/test_lv  /dev/whatever/whatvolume"
+   or by
+   "lvrename  whatever test_lv whatvolume"
+   and reactivate it again by
+   "lvchange -ay /dev/whatever/whatvolume"
+
+10. if you own Ted Tso's/Powerquest's resize2fs program, you are able to
+    resize the ext2 type filesystems contained in logical volumes without
+    destroyiing the data by
+    "e2fsadm -L+100 /dev/test_vg/another_test_lv"
+
diff -u --recursive --new-file v2.3.46/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.3.46/linux/Documentation/filesystems/devfs/ChangeLog	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/filesystems/devfs/ChangeLog	Sun Feb 20 20:23:20 2000
@@ -913,7 +913,7 @@
 Changes for patch v105
 
 - Unregister SCSI host from <scsi_host_no_list> in <scsi_unregister>
-  Thanks to Zoltan BOSZORMENYI <zboszor@mol.hu>
+  Thanks to Zoltán Böszörményi <zboszor@mail.externet.hu>
 
 - Don't save /dev/log in rc.devfs
 
@@ -1438,3 +1438,28 @@
 Work sponsored by SGI
 
 - Ported to kernel 2.3.46-pre2
+===============================================================================
+Changes for patch v159
+
+Work sponsored by SGI
+
+- Fixed drivers/block/md.c
+  Thanks to Mike Galbraith <mikeg@weiden.de>
+
+- Documentation fixes
+
+- Moved device registration from <lp_init> to <lp_register>
+  Thanks to Tim Waugh <twaugh@redhat.com>
+===============================================================================
+Changes for patch v160
+
+Work sponsored by SGI
+
+- Fixed drivers/char/joystick/joystick.c
+  Thanks to Vojtech Pavlik <vojtech@suse.cz>
+
+- Documentation updates
+
+- Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled
+
+- Fixed drivers/char/stallion.c
diff -u --recursive --new-file v2.3.46/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- v2.3.46/linux/Documentation/filesystems/devfs/README	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/filesystems/devfs/README	Sun Feb 20 20:23:20 2000
@@ -472,6 +472,29 @@
 will require this. Note that the kernel creates a compatibility entry
 for the root device, so you don't need initrd.
 
+Note that you no longer need to mount devpts if you use Unix98 PTYs,
+as devfs can manage /dev/pts itself. This saves you some RAM, as you
+don't need to compile and install devpts. Note that some versions of
+glibc have a bug with Unix98 pty handling on devfs systems. Contact
+the glibc maintainers for a fix.
+
+Note also that apart from editing /etc/fstab, other things will need
+to be changed if you *don't* install devfsd. Some software (like the X
+server) hard-wire device names in their source. It really is much
+easier to install devfsd so that compatibility entries are created.
+You can then slowly migrate your system to using the new device names
+(for example, by starting with /etc/fstab), and then limiting the
+compatibility entries that devfsd creates.
+MAKE SURE YOU INSTALL DEVFSD BEFORE YOU BOOT A DEVFS-ENABLED KERNEL!
+
+Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of
+reports back. Many of these are because people are trying to run
+without devfsd, and hence some things break. Please just run devfsd if
+things break. I want to concentrate on real bugs rather than
+misconfiguration problems at the moment. If people are willing to fix
+bugs/false assumptions in other code (i.e. glibc, X server) and submit
+that to the respective maintainers, that would be great.
+
 Fail-safe Approach with real /dev inodes                           <subsection>
 ----------------------------------------
 This method involves more work, and is no longer recommended now that
@@ -614,25 +637,25 @@
 - TTY devices (console, serial ports, terminals and pseudo-terminals)
   Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
 
-- SCSI tapes (/dev/st*)
+- SCSI tapes (/dev/scsi and /dev/tapes)
 
-- SCSI CD-ROMs (/dev/sr*)
+- SCSI CD-ROMs (/dev/scsi and /dev/cdroms)
 
-- SCSI generic devices (/dev/sg*)
+- SCSI generic devices (/dev/scsi)
 
 - RAMDISCS (/dev/ram?)
 
 - Meta Devices (/dev/md*)
 
-- Floppy discs (/dev/fd?*)
+- Floppy discs (/dev/floppy)
 
-- Parallel port printers (/dev/lp*)
+- Parallel port printers (/dev/printers)
 
-- Sound devices
+- Sound devices (/dev/sound)
   Thanks to Eric Dumas <dumas@linux.eu.org> and
   C. Scott Ananian <cananian@alumni.princeton.edu>
 
-- Joysticks (/dev/js*)
+- Joysticks (/dev/joysticks)
 
 - Sparc keyboard (/dev/kbd)
 
@@ -642,12 +665,12 @@
 
 - Coda network file system (/dev/cfs*)
 
-- Virtual console capture devices (/dev/vcs*)
+- Virtual console capture devices (/dev/vcc)
   Thanks to Dennis Hou <smilax@mindmeld.yi.org>
 
-- Frame buffer devices (/dev/fb*)
+- Frame buffer devices (/dev/fb)
 
-- Video capture devices (/dev/video? /dev/vbi?)
+- Video capture devices (/dev/v4l)
 
 
 Naming Scheme                                                         <section>
@@ -751,6 +774,7 @@
   /dev/tts/{0,1,...}         /dev/ttyS{0,1,...}         Serial ports
   /dev/cua/{0,1,...}         /dev/cua{0,1,...}          Call out devices
   /dev/vc/{0,1,...}          /dev/tty{1...63}           Virtual consoles
+  /dev/vcc/{0,1,...}         /dev/vcs{1...63}           Virtual consoles
   /dev/pty/m{0,1,...}        /dev/ptyp??                PTY masters
   /dev/pty/s{0,1,...}        /dev/ttyp??                PTY slaves
 
@@ -848,6 +872,13 @@
 simultaneous xterms and remote logins).  Note that the device number
 is limited to the range 36864-61439 (majors 144-239), in order to
 avoid any possible conflicts with existing official allocations.
+
+Please note that using dynamically allocated block device numbers may
+break the NFS daemons (both user and kernel mode), which expect dev_t
+for a given device to be constant over reboots. A simple reboot, with
+no change in your hardware layout, would result in the same device
+numbers being allocated, and hence will not cause a problem for NFS
+daemons.
 
 A final note on this scheme: since it doesn't increase the size of
 device numbers, there are no compatibility issues with userspace.
diff -u --recursive --new-file v2.3.46/linux/Documentation/filesystems/devfs/ToDo linux/Documentation/filesystems/devfs/ToDo
--- v2.3.46/linux/Documentation/filesystems/devfs/ToDo	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/filesystems/devfs/ToDo	Thu Feb 17 15:24:52 2000
@@ -2,7 +2,7 @@
 
 		Richard Gooch <rgooch@atnf.csiro.au>
 
-			      5-DEC-1999
+			      18-FEB-2000
 
 This is a list of things to be done for better devfs support in the
 Linux kernel. If you'd like to contribute to the devfs, please have a
@@ -37,4 +37,6 @@
 - I2O block device (drivers/i2o/i2o_block.c)
 
 - ST-RAM device (arch/m68k/atari/stram.c)
+
+- Raw devices
 
diff -u --recursive --new-file v2.3.46/linux/Documentation/kbuild/config-language.txt linux/Documentation/kbuild/config-language.txt
--- v2.3.46/linux/Documentation/kbuild/config-language.txt	Wed Oct 27 16:34:12 1999
+++ linux/Documentation/kbuild/config-language.txt	Sun Feb 20 20:13:10 2000
@@ -120,6 +120,7 @@
     Dependent statements:
 
         dep_bool        /prompt/ /symbol/ /dep/ ...
+        dep_mbool       /prompt/ /symbol/ /dep/ ...
         dep_hex         /prompt/ /symbol/ /word/ /dep/ ...
         dep_int         /prompt/ /symbol/ /word/ /dep/ ...
         dep_string      /prompt/ /symbol/ /word/ /dep/ ...
@@ -386,8 +387,8 @@
 
 Example:
 
-    # Not from the corpus
-    define_int CONFIG_UID_TORVALDS 2026
+    # drivers/char/ftape/Config.in
+    define_int CONFIG_FT_ALPHA_CLOCK 0
 
 
 
@@ -424,10 +425,15 @@
 
 Example:
 
-    # not from the corpus
-    if [ "$CONFIG_ZFTAPE" != "n" ]; then
-      comment 'The compressor will be built as a module only!'
-      define_tristate CONFIG_ZFT_COMPRESSOR m
+    # drivers/video/Config.in
+    if [ "$CONFIG_FB_AMIGA" = "y" ]; then
+       define_tristate CONFIG_FBCON_AFB y
+       define_tristate CONFIG_FBCON_ILBM y
+    else
+       if [ "$CONFIG_FB_AMIGA" = "m" ]; then
+          define_tristate CONFIG_FBCON_AFB m
+          define_tristate CONFIG_FBCON_ILBM m
+       fi
     fi
 
 
@@ -438,6 +444,36 @@
 Any dependency which has a value of "y" does not restrict the input
 range.  Any dependency which has an empty value is ignored.
 Any dependency which has a value of "n", or which has some other value,
+(like "m") restricts the input range to "n".  Quoting dependencies is not
+allowed. Using dependencies with an empty value possible is not
+recommended.  See also dep_mbool below.
+
+If the input range is restricted to the single choice "n", dep_bool
+silently assigns "n" to /symbol/.  If the input range has more than
+one choice, dep_bool displays /prompt/ to the user, accepts a value
+from the user, and assigns that value to /symbol/.
+
+Configure:  implemented
+Menuconfig: implemented
+XConfig:    implemented
+mconfig:    implemented
+
+Example:
+
+    # drivers/net/Config.in
+    dep_bool 'Aironet 4500/4800 PCI support 'CONFIG_AIRONET4500_PCI $CONFIG_PCI
+
+Known bugs:
+- Xconfig does not write "# foo is not set" to .config (as well as
+  "#unset foo" to autoconf.h) if command is disabled by its dependencies.
+
+
+=== dep_mbool /prompt/ /symbol/ /dep/ ...
+
+This verb evaluates all of the dependencies in the dependency list.
+Any dependency which has a value of "y" or "m" does not restrict the
+input range.  Any dependency which has an empty value is ignored.
+Any dependency which has a value of "n", or which has some other value,
 restricts the input range to "n".  Quoting dependencies is not allowed.
 Using dependencies with an empty value possible is not recommended.
 
@@ -446,13 +482,18 @@
 one choice, dep_bool displays /prompt/ to the user, accepts a value
 from the user, and assigns that value to /symbol/.
 
+Notice that the only difference between dep_bool and dep_mbool
+is in the way of treating the "m" value as a dependency.
+
 Configure:  implemented
 Menuconfig: implemented
 XConfig:    implemented
-mconfig:    implemented
+mconfig:    not implemented
 
-    # not from the corpus
-    dep_bool 'RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_PCI
+Example:
+
+    # Not from the corpus
+    dep_mbool 'Packet socket: mmapped IO' CONFIG_PACKET_MMAP $CONFIG_PACKET
 
 Known bugs:
 - Xconfig does not write "# foo is not set" to .config (as well as
@@ -492,6 +533,11 @@
 Xconfig:    implemented
 mconfig:    implemented
 
+Example:
+
+    # drivers/char/Config.in
+    dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+
 Known bugs:
 - Xconfig does not write "# foo is not set" to .config (as well as
   "#unset foo" to autoconf.h) if command is disabled by its dependencies.
@@ -508,6 +554,13 @@
 Xconfig:    implemented (with bugs)
 mconfig:    implemented
 
+Example:
+
+    # arch/mips/config.in
+    unset CONFIG_PCI
+    unset CONFIG_MIPS_JAZZ
+    unset CONFIG_VIDEO_G364
+
 
 
 === choice /prompt/ /word/ /word/
@@ -538,6 +591,14 @@
 Xconfig:    implemented
 mconfig:    implemented
 
+Example:
+
+    # arch/i386/config.in
+    choice '  PCI access mode' \
+        "BIOS           CONFIG_PCI_GOBIOS       \
+         Direct         CONFIG_PCI_GODIRECT     \
+         Any            CONFIG_PCI_GOANY"       Any
+
 
 
 === nchoice /prompt/ /symbol/ /prompt/ /symbol/ ...
@@ -602,9 +663,6 @@
 Xconfig has some known bugs, and probably some unknown bugs too:
 
 - literals with an empty "" value are not properly handled.
-
-- tkparse gives the wrong precedence to -o, -a, and !.  Don't use both
-  -o and -a in an expression.  Don't use ! at all.
 
 
 
diff -u --recursive --new-file v2.3.46/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt
--- v2.3.46/linux/Documentation/magic-number.txt	Sun Aug  9 12:15:49 1998
+++ linux/Documentation/magic-number.txt	Sun Feb 20 20:37:09 2000
@@ -48,7 +48,7 @@
 PG_MAGIC	      'P'	  pg_{read,write}_hdr include/linux/pg.h
 MKISS_DRIVER_MAGIC    0x04bf      mkiss_channel     drivers/net/mkiss.h
 RISCOM8_MAGIC         0x0907      riscom_port       drivers/char/riscom8.h
-APM_BIOS_MAGIC        0x4101      apm_bios_struct   include/linux/apm_bios.h
+APM_BIOS_MAGIC        0x4101      apm_user          arch/i386/kernel/apm.c
 CYCLADES_MAGIC        0x4359      cyclades_port     include/linux/cyclades.h
 FASYNC_MAGIC          0x4601      fasync_struct     include/linux/fs.h
 PTY_MAGIC	      0x5001	  (none at the moment)
diff -u --recursive --new-file v2.3.46/linux/Documentation/networking/bridge.txt linux/Documentation/networking/bridge.txt
--- v2.3.46/linux/Documentation/networking/bridge.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/bridge.txt	Fri Feb 18 14:51:22 2000
@@ -0,0 +1,11 @@
+In order to use the ethernet bridging functionality you'll need the
+userspace tools available at ftp://openrock.net/bridge. The tarball
+available there contains extensive documentation, but if you still have
+questions, don't hesitate to post to the mailing list (more info at
+http://openrock.net/mailman/listinfo/bridge). You can also mail me at
+buytenh@openrock.net.
+
+
+
+Lennert Buytenhek
+<buytenh@openrock.net>
diff -u --recursive --new-file v2.3.46/linux/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt
--- v2.3.46/linux/Documentation/networking/decnet.txt	Thu Feb 10 17:11:02 2000
+++ linux/Documentation/networking/decnet.txt	Thu Feb 17 17:26:36 2000
@@ -24,7 +24,7 @@
 Be sure to turn on the following options:
 
     CONFIG_DECNET (obviously)
-    CONFIG_PROCFS (to see what's going on)
+    CONFIG_PROC_FS (to see what's going on)
     CONFIG_SYSCTL (for easy configuration)
 
 if you want to try out router support (not properly debugged yet)
diff -u --recursive --new-file v2.3.46/linux/Documentation/networking/skfp.txt linux/Documentation/networking/skfp.txt
--- v2.3.46/linux/Documentation/networking/skfp.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/skfp.txt	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,214 @@
+(C)Copyright 1998-2000 SysKonnect,
+===========================================================================
+
+skfp.txt created 17-Feb-2000
+
+Readme File for skfp.o v2.05
+
+
+This file contains
+(1) OVERVIEW
+(2) SUPPORTED ADAPTERS
+(3) GENERAL INFORMATION
+(4) INSTALLATION
+(5) INCLUSION OF THE ADAPTER IN SYSTEM START
+(6) TROUBLESHOOTING
+(7) FUNCTION OF THE ADAPTER LEDS
+(8) HISTORY
+
+===========================================================================
+
+
+
+(1) OVERVIEW
+============
+
+This README explains how to use the driver 'skfp' for Linux with your
+network adapter.
+
+Chapter 2: Contains a list of all network adapters that are supported by
+	   this driver.
+
+Chapter 3: Gives some general information.
+
+Chapter 4: Describes common problems and solutions.
+
+Chapter 5: Shows the changed functionality of the adapter LEDs.
+
+Chapter 6: History of development.
+
+***
+
+
+(2) SUPPORTED ADAPTERS
+======================
+
+The network driver 'skfp' supports the following network adapters:
+SysKonnect adapters:
+  - SK-5521 (SK-NET FDDI-UP)
+  - SK-5522 (SK-NET FDDI-UP DAS)
+  - SK-5541 (SK-NET FDDI-FP)
+  - SK-5543 (SK-NET FDDI-LP)
+  - SK-5544 (SK-NET FDDI-LP DAS)
+  - SK-5821 (SK-NET FDDI-UP64)
+  - SK-5822 (SK-NET FDDI-UP64 DAS)
+  - SK-5841 (SK-NET FDDI-FP64)
+  - SK-5843 (SK-NET FDDI-LP64)
+  - SK-5844 (SK-NET FDDI-LP64 DAS)
+Compaq adapters (not tested):
+  - Netelligent 100 FDDI DAS Fibre SC
+  - Netelligent 100 FDDI SAS Fibre SC
+  - Netelligent 100 FDDI DAS UTP
+  - Netelligent 100 FDDI SAS UTP
+  - Netelligent 100 FDDI SAS Fibre MIC
+***
+
+
+(3) GENERAL INFORMATION
+=======================
+
+From v2.01 on, the driver is integrated in the linux kernel sources.
+Therefor, the installation is the same as for any other adapter
+supported by the kernel.
+Refer to the manual of your distribution about the installation
+of network adapters.
+Makes my life much easier :-)
+***
+
+
+(4) TROUBLESHOOTING
+===================
+
+If you run into problems during installation, check those items:
+
+Problem:  The FDDI adapter can not be found by the driver.
+Reason:   Look in /proc/pci for the following entry:
+             'FDDI network controller: SysKonnect SK-FDDI-PCI ...'
+	  If this entry exists, then the FDDI adapter has been
+	  found by the system and should be able to be used.
+	  If this entry does not exist or if the file '/proc/pci'
+	  is not there, then you may have a hardware problem or PCI
+	  support may not be enabled in your kernel.
+	  The adapter can be checked using the diagnostic program
+	  which is available from the SysKonnect web site:
+	      www.syskonnect.de
+	  Some COMPAQ machines have a problem with PCI under
+	  Linux. This is described in the 'PCI howto' document
+	  (included in some distributions or available from the
+	  www, e.g. at 'www.linux.org') and no workaround is available.
+
+Problem:  You want to use your computer as a router between
+          multiple IP subnetworks (using multiple adapters), but
+	  you can not reach computers in other subnetworks.
+Reason:   Either the router's kernel is not configured for IP
+	  forwarding or there is a problem with the routing table
+	  and gateway configuration in at least one of the
+	  computers.
+
+If your problem is not listed here, please contact our
+technical support for help. 
+You can send email to:
+  linux@syskonnect.de
+When contacting our technical support,
+please ensure that the following information is available:
+- System Manufacturer and Model
+- Boards in your system
+- Distribution
+- Kernel version
+
+***
+
+
+(5) FUNCTION OF THE ADAPTER LEDS
+================================
+
+        The functionality of the LED's on the FDDI network adapters was
+        changed in SMT version v2.82. With this new SMT version, the yellow
+        LED works as a ring operational indicator. An active yellow LED
+        indicates that the ring is down. The green LED on the adapter now
+        works as a link indicator where an active GREEN LED indicates that
+        the respective port has a physical connection.
+
+        With versions of SMT prior to v2.82 a ring up was indicated if the
+        yellow LED was off while the green LED(s) showed the connection
+        status of the adapter. During a ring down the green LED was off and
+        the yellow LED was on.
+
+        All implementations indicate that a driver is not loaded if
+        all LEDs are off.
+
+***
+
+
+(6) HISTORY
+===========
+
+v2.05 (20000217) (In-Kernel version)
+    New features:
+	- Changes for 2.3.45 kernel
+
+v2.04 (20000207) (Standalone version)
+    New features:
+	- Added rx/tx byte counter
+
+v2.03 (20000111) (Standalone version)
+    Problems fixed:
+	- Fixed printk statements from v2.02
+
+v2.02 (991215) (Standalone version)
+    Problems fixed:
+	- Removed unnecessary output
+	- Fixed path for "printver.sh" in makefile
+
+v2.01 (991122) (In-Kernel version)
+    New features:
+	- Integration in Linux kernel sources
+	- Support for memory mapped I/O.
+
+v2.00 (991112)
+    New features:
+	- Full source released under GPL
+
+v1.05 (991023)
+    Problems fixed:
+	- Compilation with kernel version 2.2.13 failed
+
+v1.04 (990427)
+    Changes:
+	- New SMT module included, changing LED functionality
+    Problems fixed:
+	- Synchronization on SMP machines was buggy
+
+v1.03 (990325)
+    Problems fixed:
+	- Interrupt routing on SMP machines could be incorrect
+
+v1.02 (990310)
+    New features:
+	- Support for kernel versions 2.2.x added
+	- Kernel patch instead of private duplicate of kernel functions
+
+v1.01 (980812)
+    Problems fixed:
+	Connection hangup with telnet
+	Slow telnet connection
+
+v1.00 beta 01 (980507)
+    New features:
+	None.
+    Problems fixed:
+	None.
+    Known limitations:
+        - tar archive instead of standard package format (rpm).
+	- FDDI statistic is empty.
+	- not tested with 2.1.xx kernels
+	- integration in kernel not tested
+	- not tested simultaneously with FDDI adapters from other vendors.
+	- only X86 processors supported.
+	- SBA (Synchronous Bandwidth Allocator) parameters can
+	  not be configured.
+	- does not work on some COMPAQ machines. See the PCI howto
+	  document for details about this problem.
+	- data corruption with kernel versions below 2.0.33.
+
+*** End of information file ***
diff -u --recursive --new-file v2.3.46/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.46/linux/MAINTAINERS	Wed Feb 16 17:03:51 2000
+++ linux/MAINTAINERS	Fri Feb 18 14:51:22 2000
@@ -330,6 +330,13 @@
 L:	linux-net@vger.rutgers.edu
 S:	Maintained
 
+ETHERNET BRIDGE
+P:	Lennert Buytenhek
+M:	buytenh@openrock.net
+L:	bridge@openrock.net
+W:	http://openrock.net/bridge
+S:	Maintained
+
 ETHERTEAM 16I DRIVER
 P:      Mika Kuoppala
 M:      miku@iki.fi
@@ -397,6 +404,13 @@
 M:	oe1kib@oe1kib.ampr.org
 L:	linux-hams@vger.rutgers.edu
 S:	Maintained
+
+LOGICAL VOLUME MANAGER
+P:     Heinz Mauelshagen
+M:     linux-LVM@EZ-Darmstadt.Telekom.de
+L:     linux-LVM@msede.com
+W:     http://linux.msede.com/lvm
+S:     Maintained 
 
 HIPPI
 P:	Jes Sorensen
diff -u --recursive --new-file v2.3.46/linux/Makefile linux/Makefile
--- v2.3.46/linux/Makefile	Wed Feb 16 17:03:51 2000
+++ linux/Makefile	Sun Feb 20 20:14:55 2000
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 46
+SUBLEVEL = 47
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -206,6 +206,10 @@
 DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a
 endif
 
+ifdef CONFIG_MAC
+DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a
+endif
+
 ifeq ($(CONFIG_ISAPNP),y)
 DRIVERS := $(DRIVERS) drivers/pnp/pnp.o
 endif
@@ -267,8 +271,8 @@
 	$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
 		--start-group \
 		$(CORE_FILES) \
-		$(NETWORKS) \
 		$(DRIVERS) \
+		$(NETWORKS) \
 		$(LIBS) \
 		--end-group \
 		-o vmlinux
@@ -400,6 +404,7 @@
 	if [ -f FC4_MODULES   ]; then inst_mod FC4_MODULES   fc4;   fi; \
 	if [ -f IRDA_MODULES  ]; then inst_mod IRDA_MODULES  net;   fi; \
 	if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES  net;   fi; \
+	if [ -f SKFP_MODULES ]; then inst_mod SKFP_MODULES   net;   fi; \
 	if [ -f USB_MODULES   ]; then inst_mod USB_MODULES   usb;   fi; \
 	if [ -f IEEE1394_MODULES ]; then inst_mod IEEE1394_MODULES ieee1394; fi; \
 	if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.3.46/linux/arch/alpha/kernel/Makefile	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/Makefile	Sun Feb 20 08:13:56 2000
@@ -14,7 +14,7 @@
 
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
-	    ptrace.o time.o semaphore.o
+	    ptrace.o time.o semaphore.o i8259.o
 OX_OBJS  := alpha_ksyms.o
 
 
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.3.46/linux/arch/alpha/kernel/alpha_ksyms.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Fri Feb 18 10:01:32 2000
@@ -36,6 +36,7 @@
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+extern spinlock_t kernel_flag;
 
 /* these are C runtime functions with special calling conventions: */
 extern void __divl (void);
@@ -51,6 +52,7 @@
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(probe_irq_mask);
 EXPORT_SYMBOL(screen_info);
 EXPORT_SYMBOL(perf_irq);
 
@@ -96,6 +98,13 @@
 EXPORT_SYMBOL(__memsetw);
 EXPORT_SYMBOL(__constant_c_memset);
 
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_unmap_sg);
+
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(hwrpb);
@@ -158,13 +167,16 @@
  */
 
 #ifdef __SMP__
+EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(synchronize_irq);
 EXPORT_SYMBOL(flush_tlb_all);
 EXPORT_SYMBOL(flush_tlb_mm);
 EXPORT_SYMBOL(flush_tlb_page);
 EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(smp_imb);
 EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL(__cpu_number_map);
+EXPORT_SYMBOL(smp_num_cpus);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c
--- v2.3.46/linux/arch/alpha/kernel/core_mcpcia.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/core_mcpcia.c	Sun Feb 20 08:13:56 2000
@@ -45,12 +45,6 @@
 
 #define MCPCIA_MAX_HOSES 4
 
-/* Dodge has PCI0 and PCI1 at MID 4 and 5 respectively.  Durango adds
-   PCI2 and PCI3 at MID 6 and 7 respectively.  */
-
-#define hose2mid(h)	((h) + 4)
-
-
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address and setup the MCPCIA_HAXR2 register
@@ -98,7 +92,7 @@
 	  struct pci_controler *hose)
 {
 	unsigned long flags;
-	unsigned long mid = hose2mid(hose->index);
+	unsigned long mid = MCPCIA_HOSE2MID(hose->index);
 	unsigned int stat0, value, temp, cpu;
 
 	cpu = smp_processor_id();
@@ -146,7 +140,7 @@
 	   struct pci_controler *hose)
 {
 	unsigned long flags;
-	unsigned long mid = hose2mid(hose->index);
+	unsigned long mid = MCPCIA_HOSE2MID(hose->index);
 	unsigned int stat0, temp, cpu;
 
 	cpu = smp_processor_id();
@@ -297,7 +291,7 @@
 mcpcia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
 {
 	wmb();
-	BUG();
+	*(vuip)MCPCIA_SG_TBIA(MCPCIA_HOSE2MID(hose->index)) = 0;
 	mb();
 }
 
@@ -305,7 +299,7 @@
 mcpcia_probe_hose(int h)
 {
 	int cpu = smp_processor_id();
-	int mid = hose2mid(h);
+	int mid = MCPCIA_HOSE2MID(h);
 	unsigned int pci_rev;
 
 	/* Gotta be REAL careful.  If hose is absent, we get an mcheck.  */
@@ -340,7 +334,7 @@
 {
 	struct pci_controler *hose;
 	struct resource *io, *mem, *hae_mem;
-	int mid = hose2mid(h);
+	int mid = MCPCIA_HOSE2MID(h);
 
 	hose = alloc_pci_controler();
 	io = alloc_resource();
@@ -387,7 +381,7 @@
 static void __init
 mcpcia_startup_hose(struct pci_controler *hose)
 {
-	int mid = hose2mid(hose->index);
+	int mid = MCPCIA_HOSE2MID(hose->index);
 	unsigned int tmp;
 
 	mcpcia_pci_clr_err(mid);
@@ -578,7 +572,7 @@
 		   error was on?  */	
 		struct pci_controler *hose;
 		for (hose = hose_head; hose; hose = hose->next)
-			mcpcia_pci_clr_err(hose2mid(hose->index));
+			mcpcia_pci_clr_err(MCPCIA_HOSE2MID(hose->index));
 		break;
 	    }
 	case 1:
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c
--- v2.3.46/linux/arch/alpha/kernel/core_polaris.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/core_polaris.c	Sun Feb 20 08:13:56 2000
@@ -107,7 +107,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int
+int
 polaris_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
 	unsigned long pci_addr;
@@ -150,7 +150,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int 
+int 
 polaris_write_config_dword(struct pci_dev *dev, int where, u32 value)
 {
 	unsigned long pci_addr;
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c
--- v2.3.46/linux/arch/alpha/kernel/core_pyxis.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/core_pyxis.c	Sun Feb 20 08:13:56 2000
@@ -23,6 +23,7 @@
 #include <asm/system.h>
 
 #include "proto.h"
+#include "irq_impl.h"
 #include "pci_impl.h"
 
 
@@ -286,6 +287,108 @@
 	write_dword:	pyxis_write_config_dword
 };
 
+/* Note mask bit is true for ENABLED irqs.  */
+static unsigned long cached_irq_mask;
+
+static inline void
+pyxis_update_irq_hw(unsigned long mask)
+{
+	*(vulp)PYXIS_INT_MASK = mask;
+	mb();
+	*(vulp)PYXIS_INT_MASK;
+}
+
+static inline void
+pyxis_enable_irq(unsigned int irq)
+{
+	pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+}
+
+static inline void
+pyxis_disable_irq(unsigned int irq)
+{
+	pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+}
+
+static unsigned int
+pyxis_startup_irq(unsigned int irq)
+{
+	pyxis_enable_irq(irq);
+	return 0;
+}
+
+static void
+pyxis_mask_and_ack_irq(unsigned int irq)
+{
+	unsigned long bit = 1UL << (irq - 16);
+	unsigned long mask = cached_irq_mask &= ~bit;
+
+	/* Disable the interrupt.  */
+	*(vulp)PYXIS_INT_MASK = mask;
+	wmb();
+	/* Ack PYXIS PCI interrupt.  */
+	*(vulp)PYXIS_INT_REQ = bit;
+	mb();
+	/* Re-read to force both writes.  */
+	*(vulp)PYXIS_INT_MASK;
+}
+
+static struct hw_interrupt_type pyxis_irq_type = {
+	typename:	"PYXIS",
+	startup:	pyxis_startup_irq,
+	shutdown:	pyxis_disable_irq,
+	enable:		pyxis_enable_irq,
+	disable:	pyxis_disable_irq,
+	ack:		pyxis_mask_and_ack_irq,
+	end:		pyxis_enable_irq,
+};
+
+void 
+pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+	unsigned long pld;
+	unsigned int i;
+
+	/* Read the interrupt summary register of PYXIS */
+	pld = *(vulp)PYXIS_INT_REQ;
+	pld &= cached_irq_mask;
+
+	/*
+	 * 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
+			handle_irq(16+i, regs);
+	}
+}
+
+void __init
+init_pyxis_irqs(unsigned long ignore_mask)
+{
+	long i;
+
+	*(vulp)PYXIS_INT_MASK = 0;		/* disable all */
+	*(vulp)PYXIS_INT_REQ  = -1;		/* flush all */
+	mb();
+
+	/* Send -INTA pulses to clear any pending interrupts ...*/
+	*(vuip) PYXIS_IACK_SC;
+
+	for (i = 16; i < 48; ++i) {
+		if ((ignore_mask >> i) & 1)
+			continue;
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &pyxis_irq_type;
+	}
+
+	setup_irq(16+7, &isa_cascade_irqaction);
+}
+
 void
 pyxis_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
 {
@@ -342,7 +445,7 @@
 	__restore_flags(flags);
 }
 
-static void
+static void __init
 pyxis_enable_broken_tbi(struct pci_iommu_arena *arena)
 {
 	void *page;
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c
--- v2.3.46/linux/arch/alpha/kernel/core_tsunami.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/core_tsunami.c	Sun Feb 20 08:13:56 2000
@@ -224,7 +224,7 @@
 }
 
 #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
-static long
+static long __init
 tsunami_probe_read(volatile unsigned long *vaddr)
 {
 	long dont_care, probe_result;
@@ -246,7 +246,7 @@
 	return probe_result;
 }
 
-static long
+static long __init
 tsunami_probe_write(volatile unsigned long *vaddr)
 {
 	long true_contents, probe_result = 1;
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/i8259.c linux/arch/alpha/kernel/i8259.c
--- v2.3.46/linux/arch/alpha/kernel/i8259.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/kernel/i8259.c	Sun Feb 20 08:13:56 2000
@@ -0,0 +1,95 @@
+/*
+ *      linux/arch/alpha/kernel/i8259.c
+ *
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+ * present in the majority of PC/AT boxes.
+ *
+ * Started hacking from linux-2.3.30pre6/arch/i386/kernel/i8259.c.
+ */
+
+#include <linux/init.h>
+#include <linux/cache.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+
+#include "proto.h"
+#include "irq_impl.h"
+
+
+/* Note mask bit is true for DISABLED irqs.  */
+static unsigned int cached_irq_mask = 0xffff;
+
+static inline void
+i8259_update_irq_hw(unsigned int irq, unsigned long mask)
+{
+	int port = 0x21;
+	if (irq & 8) mask >>= 8;
+	if (irq & 8) port = 0xA1;
+	outb(mask, port);
+}
+
+inline void
+i8259a_enable_irq(unsigned int irq)
+{
+	i8259_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+}
+
+inline void
+i8259a_disable_irq(unsigned int irq)
+{
+	i8259_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
+}
+
+void
+i8259a_mask_and_ack_irq(unsigned int irq)
+{
+	i8259a_disable_irq(irq);
+
+	/* Ack the interrupt making it the lowest priority.  */
+	if (irq >= 8) {
+		outb(0xE0 | (irq - 8), 0xa0);   /* ack the slave */
+		irq = 2;
+	}
+	outb(0xE0 | irq, 0x20);			/* ack the master */
+}
+
+unsigned int
+i8259a_startup_irq(unsigned int irq)
+{
+	i8259a_enable_irq(irq);
+	return 0; /* never anything pending */
+}
+
+struct hw_interrupt_type i8259a_irq_type = {
+	typename:	"XT-PIC",
+	startup:	i8259a_startup_irq,
+	shutdown:	i8259a_disable_irq,
+	enable:		i8259a_enable_irq,
+	disable:	i8259a_disable_irq,
+	ack:		i8259a_mask_and_ack_irq,
+	end:		i8259a_enable_irq,
+};
+
+void __init
+init_i8259a_irqs(void)
+{
+	static struct irqaction cascade = {
+		handler:	no_action,
+		name:		"cascade",
+	};
+
+	long i;
+
+	outb(0xff, 0x21);	/* mask all of 8259A-1 */
+	outb(0xff, 0xA1);	/* mask all of 8259A-2 */
+
+	for (i = 0; i < 16; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &i8259a_irq_type;
+	}
+
+	setup_irq(2, &cascade);
+}
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.3.46/linux/arch/alpha/kernel/irq.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/irq.c	Sun Feb 20 08:13:56 2000
@@ -17,32 +17,29 @@
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/interrupt.h>
 #include <linux/malloc.h>
 #include <linux/random.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/irq.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/dma.h>
 #include <asm/bitops.h>
 #include <asm/machvec.h>
 
 #include "proto.h"
+#include "irq_impl.h"
 
 #define vulp	volatile unsigned long *
 #define vuip	volatile unsigned int *
 
 /* Only uniprocessor needs this IRQ/BH locking depth, on SMP it lives
    in the per-cpu structure for cache reasons.  */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 int __local_irq_count;
 int __local_bh_count;
-#endif
-
-#if NR_IRQS > 128
-#  error Unable to handle more than 128 irq levels.
+unsigned long __irq_attempt[NR_IRQS];
 #endif
 
 #ifdef CONFIG_ALPHA_GENERIC
@@ -51,39 +48,13 @@
 #define ACTUAL_NR_IRQS	NR_IRQS
 #endif
 
-/* Reserved interrupts.  These must NEVER be requested by any driver!
-   IRQ 2 used by hw cascade */
-#define	IS_RESERVED_IRQ(irq)	((irq)==2)
-
-
 /*
- * Shadow-copy of masked interrupts.
+ * Performance counter hook.  A module can override this to
+ * do something useful.
  */
 
-unsigned long _alpha_irq_masks[2] = { ~0UL, ~0UL };
-
-/*
- * The ack_irq routine used by 80% of the systems.
- */
-
-void
-common_ack_irq(unsigned long irq)
-{
-	if (irq < 16) {
-		/* Ack the interrupt making it the lowest priority */
-		/*  First the slave .. */
-		if (irq > 7) {
-			outb(0xE0 | (irq - 8), 0xa0);
-			irq = 2;
-		}
-		/* .. then the master */
-		outb(0xE0 | irq, 0x20);
-	}
-}
-
-
-
-static void dummy_perf(unsigned long vector, struct pt_regs *regs)
+static void
+dummy_perf(unsigned long vector, struct pt_regs *regs)
 {
         printk(KERN_CRIT "Performance counter interrupt!\n");
 }
@@ -94,7 +65,9 @@
  * Dispatch device interrupts.
  */
 
-/* Handle ISA interrupt via the PICs. */
+/*
+ * Handle ISA interrupt via the PICs.
+ */
 
 #if defined(CONFIG_ALPHA_GENERIC)
 # define IACK_SC	alpha_mv.iack_sc
@@ -112,15 +85,12 @@
 # define IACK_SC	POLARIS_IACK_SC
 #elif defined(CONFIG_ALPHA_IRONGATE)
 # define IACK_SC        IRONGATE_IACK_SC
-#else
-  /* This is bogus but necessary to get it to compile on all platforms. */
-# define IACK_SC	1L
 #endif
 
+#if defined(IACK_SC)
 void
-isa_device_interrupt(unsigned long vector, struct pt_regs * regs)
+isa_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
-#if 1
 	/*
 	 * Generate a PCI interrupt acknowledge cycle.  The PIC will
 	 * respond with the interrupt vector of the highest priority
@@ -135,8 +105,13 @@
 			return;
 		}
 	}
-	handle_irq(j, j, regs);
-#else
+	handle_irq(j, regs);
+}
+#endif
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
+void
+isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
 	unsigned long pic;
 
 	/*
@@ -153,131 +128,341 @@
 	 *  write only.  This is not true.
 	 */
 	pic = inb(0x20) | (inb(0xA0) << 8);	/* read isr */
-	pic &= ~alpha_irq_mask;			/* apply mask */
 	pic &= 0xFFFB;				/* mask out cascade & hibits */
 
 	while (pic) {
 		int j = ffz(~pic);
 		pic &= pic - 1;
-		handle_irq(j, j, regs);
+		handle_irq(j, regs);
 	}
+}
 #endif
+
+/*
+ * Handle interrupts from the SRM, assuming no additional weirdness.
+ */
+
+static inline void
+srm_enable_irq(unsigned int irq)
+{
+	cserve_ena(irq - 16);
 }
 
-/* Handle interrupts from the SRM, assuming no additional weirdness.  */
+static void
+srm_disable_irq(unsigned int irq)
+{
+	cserve_dis(irq - 16);
+}
+
+static unsigned int
+srm_startup_irq(unsigned int irq)
+{
+	srm_enable_irq(irq);
+	return 0;
+}
+
+static struct hw_interrupt_type srm_irq_type = {
+	typename:	"SRM",
+	startup:	srm_startup_irq,
+	shutdown:	srm_disable_irq,
+	enable:		srm_enable_irq,
+	disable:	srm_disable_irq,
+	ack:		srm_disable_irq,
+	end:		srm_enable_irq,
+};
 
 void 
 srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	int irq, ack;
+	int irq = (vector - 0x800) >> 4;
+	handle_irq(irq, regs);
+}
+
+void __init
+init_srm_irqs(long max, unsigned long ignore_mask)
+{
+	long i;
+
+	for (i = 16; i < max; ++i) {
+		if (i < 64 && ((ignore_mask >> i) & 1))
+			continue;
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &srm_irq_type;
+	}
+}
+
+/*
+ * The not-handled irq handler.
+ */
+
+static void
+noirq_enable_disable(unsigned int irq)
+{
+}
+
+static unsigned int
+noirq_startup(unsigned int irq)
+{
+	return 0;
+}
 
-	ack = irq = (vector - 0x800) >> 4;
-	handle_irq(irq, ack, regs);
+static void
+noirq_ack(unsigned int irq)
+{
+	printk(KERN_CRIT "Unexpected IRQ %u\n", irq);
 }
 
+static struct hw_interrupt_type no_irq_type = {
+	typename:	"none",
+	startup:	noirq_startup,
+	shutdown:	noirq_enable_disable,
+	enable:		noirq_enable_disable,
+	disable:	noirq_enable_disable,
+	ack:		noirq_ack,
+	end:		noirq_enable_disable,
+};
 
 /*
- * Initial irq handlers.
+ * The special RTC interrupt type.  The interrupt itself was
+ * processed by PALcode, and comes in via entInt vector 1.
  */
 
-static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
-spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = {0,} };
+static struct hw_interrupt_type rtc_irq_type = {
+	typename:	"RTC",
+	startup:	noirq_startup,
+	shutdown:	noirq_enable_disable,
+	enable:		noirq_enable_disable,
+	disable:	noirq_enable_disable,
+	ack:		noirq_enable_disable,
+	end:		noirq_enable_disable,
+};
+
+void __init
+init_rtc_irq(void)
+{
+	irq_desc[RTC_IRQ].status = IRQ_DISABLED;
+	irq_desc[RTC_IRQ].handler = &rtc_irq_type;
+}
 
+/*
+ * Special irq handlers.
+ */
 
-static inline void
-mask_irq(unsigned long irq)
+void
+no_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
-	set_bit(irq, _alpha_irq_masks);
-	alpha_mv.update_irq_hw(irq, alpha_irq_mask, 0);
 }
 
-static inline void
-unmask_irq(unsigned long irq)
+/* 
+ * Common irq handlers.
+ */
+
+struct irqaction isa_cascade_irqaction = {
+	handler:	no_action,
+	name:		"isa-cascade"
+};
+
+struct irqaction timer_cascade_irqaction = {
+	handler:	no_action,
+	name:		"timer-cascade"
+};
+
+struct irqaction halt_switch_irqaction = {
+	handler:	no_action,
+	name:		"halt-switch"
+};
+
+
+spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+	[0 ... NR_IRQS-1] = { 0, &no_irq_type, }
+};
+
+int
+handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+		 struct irqaction *action)
 {
-	clear_bit(irq, _alpha_irq_masks);
-	alpha_mv.update_irq_hw(irq, alpha_irq_mask, 1);
+	int status, cpu = smp_processor_id();
+	unsigned long ipl;
+
+	kstat.irqs[cpu][irq]++;
+	irq_enter(cpu, irq);
+
+	status = 1;	/* Force the "do bottom halves" bit */
+	ipl = rdps() & 7;
+
+	do {
+		unsigned long newipl = (action->flags & SA_INTERRUPT ? 7 : 0);
+		if (newipl != ipl) {
+			swpipl(newipl);
+			ipl = newipl;
+		}
+
+		status |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+	if (ipl == 0)
+		__cli();
+
+	irq_exit(cpu, irq);
+
+	return status;
 }
 
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock. 
+ */
 void
-disable_irq_nosync(unsigned int irq_nr)
+disable_irq_nosync(unsigned int irq)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
-	mask_irq(irq_nr);
-	restore_flags(flags);
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	if (!irq_desc[irq].depth++) {
+		irq_desc[irq].status |= IRQ_DISABLED;
+		irq_desc[irq].handler->disable(irq);
+	}
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
+/*
+ * Synchronous version of the above, making sure the IRQ is
+ * no longer running on any other IRQ..
+ */
 void
-disable_irq(unsigned int irq_nr)
+disable_irq(unsigned int irq)
 {
-	/* This works non-SMP, and SMP until we write code to distribute
-	   interrupts to more that cpu 0.  */
-	disable_irq_nosync(irq_nr);
+	disable_irq_nosync(irq);
+
+	if (!local_irq_count(smp_processor_id())) {
+		do {
+			barrier();
+		} while (irq_desc[irq].status & IRQ_INPROGRESS);
+	}
 }
 
 void
-enable_irq(unsigned int irq_nr)
+enable_irq(unsigned int irq)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
-	unmask_irq(irq_nr);
-	restore_flags(flags);
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	switch (irq_desc[irq].depth) {
+	case 1:
+	  {
+		unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
+		irq_desc[irq].status = status;
+		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+			irq_desc[irq].status = status | IRQ_REPLAY;
+
+			/* ??? We can't re-send on (most?) alpha hw.
+			   hw_resend_irq(irq_desc[irq].handler,irq); */
+		}
+		irq_desc[irq].handler->enable(irq);
+		/* fall-through */
+	  }
+	default:
+		irq_desc[irq].depth--;
+		break;
+	case 0:
+		printk(KERN_ERR "enable_irq() unbalanced from %p\n",
+		       __builtin_return_address(0));
+	}
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 int
-check_irq(unsigned int irq)
+setup_irq(unsigned int irq, struct irqaction * new)
 {
-	return irq_desc[irq].action ? -EBUSY : 0;
+	int shared = 0;
+	struct irqaction *old, **p;
+	unsigned long flags;
+
+	/*
+	 * Some drivers like serial.c use request_irq() heavily,
+	 * so we have to be careful not to interfere with a
+	 * running system.
+	 */
+	if (new->flags & SA_SAMPLE_RANDOM) {
+		/*
+		 * This function might sleep, we want to call it first,
+		 * outside of the atomic block.
+		 * Yes, this might clear the entropy pool if the wrong
+		 * driver is attempted to be loaded, without actually
+		 * installing a new handler, but is this really a problem,
+		 * only the sysadmin is able to do this.
+		 */
+		rand_initialize_irq(irq);
+	}
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	spin_lock_irqsave(&irq_controller_lock,flags);
+	p = &irq_desc[irq].action;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&irq_controller_lock,flags);
+			return -EBUSY;
+		}
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	*p = new;
+
+	if (!shared) {
+		irq_desc[irq].depth = 0;
+		irq_desc[irq].status &= ~IRQ_DISABLED;
+		irq_desc[irq].handler->startup(irq);
+	}
+	spin_unlock_irqrestore(&irq_controller_lock,flags);
+	return 0;
 }
 
 int
 request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 	    unsigned long irqflags, const char * devname, void *dev_id)
 {
-	int shared = 0;
-	struct irqaction * action, **p;
-	unsigned long flags;
+	int retval;
+	struct irqaction * action;
 
 	if (irq >= ACTUAL_NR_IRQS)
 		return -EINVAL;
-	if (IS_RESERVED_IRQ(irq))
-		return -EINVAL;
 	if (!handler)
 		return -EINVAL;
 
-	p = &irq_desc[irq].action;
-	action = *p;
-	if (action) {
-		/* Can't share interrupts unless both agree to */
-		if (!(action->flags & irqflags & SA_SHIRQ))
-			return -EBUSY;
-
-		/* Can't share interrupts unless both are same type */
-		if ((action->flags ^ irqflags) & SA_INTERRUPT)
-			return -EBUSY;
-
-		/* Add new interrupt at end of irq queue */
-		do {
-			p = &action->next;
-			action = *p;
-		} while (action);
-		shared = 1;
+#if 1
+	/*
+	 * Sanity-check: shared interrupts should REALLY pass in
+	 * a real dev-ID, otherwise we'll have trouble later trying
+	 * to figure out which interrupt is which (messes up the
+	 * interrupt freeing logic etc).
+	 */
+	if ((irqflags & SA_SHIRQ) && !dev_id) {
+		printk(KERN_ERR
+		       "Bad boy: %s (at %p) called us without a dev_id!\n",
+		       devname, __builtin_return_address(0));
 	}
+#endif
 
-	action = &timer_irq;
-	if (irq != TIMER_IRQ) {
-		action = (struct irqaction *)
+	action = (struct irqaction *)
 			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
-	}
 	if (!action)
 		return -ENOMEM;
 
-	if (irqflags & SA_SAMPLE_RANDOM)
-		rand_initialize_irq(irq);
-
 	action->handler = handler;
 	action->flags = irqflags;
 	action->mask = 0;
@@ -285,56 +470,66 @@
 	action->next = NULL;
 	action->dev_id = dev_id;
 
-	save_and_cli(flags);
-	*p = action;
-
-	if (!shared)
-		unmask_irq(irq);
-
-	restore_flags(flags);
-	return 0;
+	retval = setup_irq(irq, action);
+	if (retval)
+		kfree(action);
+	return retval;
 }
-		
+
 void
 free_irq(unsigned int irq, void *dev_id)
 {
-	struct irqaction * action, **p;
+	struct irqaction **p;
 	unsigned long flags;
 
 	if (irq >= ACTUAL_NR_IRQS) {
-		printk("Trying to free IRQ%d\n",irq);
-		return;
-	}
-	if (IS_RESERVED_IRQ(irq)) {
-		printk("Trying to free reserved IRQ %d\n", irq);
+		printk(KERN_CRIT "Trying to free IRQ%d\n", irq);
 		return;
 	}
-	for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
-		if (action->dev_id != dev_id)
-			continue;
 
-		/* Found it - now free it */
-		save_and_cli(flags);
-		*p = action->next;
-		if (!irq_desc[irq].action)
-			mask_irq(irq);
-		restore_flags(flags);
-		kfree(action);
+	spin_lock_irqsave(&irq_controller_lock,flags);
+	p = &irq_desc[irq].action;
+	for (;;) {
+		struct irqaction * action = *p;
+		if (action) {
+			struct irqaction **pp = p;
+			p = &action->next;
+			if (action->dev_id != dev_id)
+				continue;
+
+			/* Found - now remove it from the list of entries.  */
+			*pp = action->next;
+			if (!irq_desc[irq].action) {
+				irq_desc[irq].status |= IRQ_DISABLED;
+				irq_desc[irq].handler->shutdown(irq);
+			}
+			spin_unlock_irqrestore(&irq_controller_lock,flags);
+
+			/* Wait to make sure it's not being used on
+			   another CPU.  */
+			while (irq_desc[irq].status & IRQ_INPROGRESS)
+				barrier();
+			kfree(action);
+			return;
+		}
+		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+		spin_unlock_irqrestore(&irq_controller_lock,flags);
 		return;
 	}
-	printk("Trying to free free IRQ%d\n",irq);
 }
 
 int get_irq_list(char *buf)
 {
-	int i;
+	int i, j;
 	struct irqaction * action;
 	char *p = buf;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	p += sprintf(p, "           ");
 	for (i = 0; i < smp_num_cpus; i++)
 		p += sprintf(p, "CPU%d       ", i);
+	for (i = 0; i < smp_num_cpus; i++)
+		p += sprintf(p, "TRY%d       ", i);
 	*p++ = '\n';
 #endif
 
@@ -343,16 +538,17 @@
 		if (!action) 
 			continue;
 		p += sprintf(p, "%3d: ",i);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		p += sprintf(p, "%10u ", kstat_irqs(i));
 #else
-		{
-		  int j;
-		  for (j = 0; j < smp_num_cpus; j++)
-			  p += sprintf(p, "%10u ",
-				       kstat.irqs[cpu_logical_map(j)][i]);
-		}
+		for (j = 0; j < smp_num_cpus; j++)
+			p += sprintf(p, "%10u ",
+				     kstat.irqs[cpu_logical_map(j)][i]);
+		for (j = 0; j < smp_num_cpus; j++)
+			p += sprintf(p, "%10lu ",
+				     irq_attempt(cpu_logical_map(j), i));
 #endif
+		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
 		p += sprintf(p, "  %c%s",
 			     (action->flags & SA_INTERRUPT)?'+':' ',
 			     action->name);
@@ -364,10 +560,17 @@
 		}
 		*p++ = '\n';
 	}
+#if CONFIG_SMP
+	p += sprintf(p, "LOC: ");
+	for (j = 0; j < smp_num_cpus; j++)
+		p += sprintf(p, "%10lu ",
+			     cpu_data[cpu_logical_map(j)].smp_local_irq_count);
+	p += sprintf(p, "\n");
+#endif
 	return p - buf;
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /* Who has global_irq_lock. */
 int global_irq_holder = NO_PROC_ID;
 
@@ -527,7 +730,7 @@
                 __sti();
                 break;
         default:
-                printk("global_restore_flags: %08lx (%p)\n",
+                printk(KERN_ERR "global_restore_flags: %08lx (%p)\n",
                         flags, __builtin_return_address(0));
         }
 }
@@ -603,141 +806,195 @@
 	}
 #endif
 }
-#endif /* __SMP__ */
-
-static void
-unexpected_irq(int irq, struct pt_regs * regs)
-{
-#if 0
-#if 1
-	printk("device_interrupt: unexpected interrupt %d\n", irq);
-#else
-	struct irqaction *action;
-	int i;
-
-	printk("IO device interrupt, irq = %d\n", irq);
-	printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
-	printk("Expecting: ");
-	for (i = 0; i < ACTUAL_NR_IRQS; i++)
-		if ((action = irq_desc[i].action))
-			while (action->handler) {
-				printk("[%s:%d] ", action->name, i);
-				action = action->next;
-			}
-	printk("\n");
-#endif
-#endif
-
-#if defined(CONFIG_ALPHA_JENSEN)
-	/* ??? Is all this just debugging, or are the inb's and outb's
-	   necessary to make things work?  */
-	printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
-	       inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
-	outb(0x0c, 0x3fc);
-	outb(0x0c, 0x2fc);
-	outb(0,0x61);
-	outb(0,0x461);
-#endif
-}
+#endif /* CONFIG_SMP */
 
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
 void
-handle_irq(int irq, int ack, struct pt_regs * regs)
-{
-	struct irqaction * action;
+handle_irq(int irq, struct pt_regs * regs)
+{	
+	/* 
+	 * We ack quickly, we don't want the irq controller
+	 * thinking we're snobs just because some other CPU has
+	 * disabled global interrupts (we have already done the
+	 * INT_ACK cycles, it's too late to try to pretend to the
+	 * controller that we aren't taking the interrupt).
+	 *
+	 * 0 return value means that this irq is already being
+	 * handled by some other CPU. (or is disabled)
+	 */
 	int cpu = smp_processor_id();
+	irq_desc_t *desc;
+	struct irqaction * action;
+	unsigned int status;
 
 	if ((unsigned) irq > ACTUAL_NR_IRQS) {
-		printk("device_interrupt: illegal interrupt %d\n", irq);
+		printk(KERN_CRIT "device_interrupt: illegal interrupt %d\n",
+		       irq);
 		return;
 	}
 
-#if 0
-	/* A useful bit of code to find out if an interrupt is going wild.  */
-	{
-	  static unsigned int last_msg, last_cc;
-	  static int last_irq, count;
-	  unsigned int cc;
-
-	  __asm __volatile("rpcc %0" : "=r"(cc));
-	  ++count;
-	  if (cc - last_msg > 150000000 || irq != last_irq) {
-		printk("handle_irq: irq %d count %d cc %u @ %p\n",
-		       irq, count, cc-last_cc, regs->pc);
-		count = 0;
-		last_msg = cc;
-		last_irq = irq;
-	  }
-	  last_cc = cc;
+	irq_attempt(cpu, irq)++;
+	desc = irq_desc + irq;
+	spin_lock_irq(&irq_controller_lock); /* mask also the RTC */
+	desc->handler->ack(irq);
+
+	/*
+	 * REPLAY is when Linux resends an IRQ that was dropped earlier.
+	 * WAITING is used by probe to mark irqs that are being tested.
+	 */
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+	status |= IRQ_PENDING; /* we _want_ to handle it */
+
+	/*
+	 * If the IRQ is disabled for whatever reason, we cannot
+	 * use the action we have.
+	 */
+	action = NULL;
+	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		action = desc->action;
+		status &= ~IRQ_PENDING; /* we commit to handling */
+		status |= IRQ_INPROGRESS; /* we are handling it */
 	}
-#endif
+	desc->status = status;
+	spin_unlock(&irq_controller_lock);
 
-	irq_enter(cpu, irq);
-	kstat.irqs[cpu][irq] += 1;
-	action = irq_desc[irq].action;
+	/*
+	 * If there is no IRQ handler or it was disabled, exit early.
+	 * Since we set PENDING, if another processor is handling
+	 * a different instance of this same irq, the other processor
+	 * will take care of it.
+	 */
+	if (!action)
+		return;
 
 	/*
-	 * 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! 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).
-	 */
-	if (ack >= 0) {
-		mask_irq(ack);
-		alpha_mv.ack_irq(ack);
-	}
-	if (action) {
-		if (action->flags & SA_SAMPLE_RANDOM)
-			add_interrupt_randomness(irq);
-		do {
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while (action);
-		if (ack >= 0)
-			unmask_irq(ack);
-	} else {
-		unexpected_irq(irq, regs);
+	 * Edge triggered interrupts need to remember pending events.
+	 * This applies to any hw interrupts that allow a second
+	 * instance of the same irq to arrive while we are in do_IRQ
+	 * or in the handler. But the code here only handles the _second_
+	 * instance of the irq, not the third or fourth. So it is mostly
+	 * useful for irq hardware that does not mask cleanly in an
+	 * SMP environment.
+	 */
+	for (;;) {
+		handle_IRQ_event(irq, regs, action);
+		spin_lock(&irq_controller_lock);
+		
+		if (!(desc->status & IRQ_PENDING)
+		    || (desc->status & IRQ_LEVEL))
+			break;
+		desc->status &= ~IRQ_PENDING;
+		spin_unlock(&irq_controller_lock);
 	}
-	irq_exit(cpu, irq);
+	desc->status &= ~IRQ_INPROGRESS;
+	if (!(desc->status & IRQ_DISABLED))
+		desc->handler->end(irq);
+	spin_unlock(&irq_controller_lock);
 }
 
-
 /*
- * Start listening for interrupts..
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
  */
-
 unsigned long
 probe_irq_on(void)
 {
-	struct irqaction * action;
-	unsigned long irqs = 0;
+	int i;
 	unsigned long delay;
-	unsigned int i;
+	unsigned long val;
 
-	/* Handle only the first 64 IRQs here.  This is enough for
-	   [E]ISA, which is the only thing that needs probing anyway.  */
-	for (i = (ACTUAL_NR_IRQS - 1) & 63; i > 0; i--) {
-		if (!(PROBE_MASK & (1UL << i))) {
-			continue;
-		}
-		action = irq_desc[i].action;
-		if (!action) {
-			enable_irq(i);
-			irqs |= (1UL << i);
+	/* Something may have generated an irq long ago and we want to
+	   flush such a longstanding irq before considering it as spurious. */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = NR_IRQS-1; i >= 0; i--)
+		if (!irq_desc[i].action) 
+			if(irq_desc[i].handler->startup(i))
+				irq_desc[i].status |= IRQ_PENDING;
+	spin_unlock_irq(&irq_controller_lock);
+
+	/* Wait for longstanding interrupts to trigger. */
+	for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+		/* about 20ms delay */ synchronize_irq();
+
+	/* enable any unassigned irqs (we must startup again here because
+	   if a longstanding irq happened in the previous stage, it may have
+	   masked itself) first, enable any unassigned irqs. */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = NR_IRQS-1; i >= 0; i--) {
+		if (!irq_desc[i].action) {
+			irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
+			if(irq_desc[i].handler->startup(i))
+				irq_desc[i].status |= IRQ_PENDING;
 		}
 	}
+	spin_unlock_irq(&irq_controller_lock);
 
 	/*
-	 * Wait about 100ms for spurious interrupts to mask themselves
-	 * out again...
+	 * Wait for spurious interrupts to trigger
 	 */
-	for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
-		barrier();
+	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+		/* about 100ms delay */ synchronize_irq();
+
+	/*
+	 * Now filter out any obviously spurious interrupts
+	 */
+	val = 0;
+	spin_lock_irq(&irq_controller_lock);
+	for (i=0; i<NR_IRQS; i++) {
+		unsigned int status = irq_desc[i].status;
+
+		if (!(status & IRQ_AUTODETECT))
+			continue;
+		
+		/* It triggered already - consider it spurious. */
+		if (!(status & IRQ_WAITING)) {
+			irq_desc[i].status = status & ~IRQ_AUTODETECT;
+			irq_desc[i].handler->shutdown(i);
+			continue;
+		}
+
+		if (i < 64)
+			val |= 1 << i;
+	}
+	spin_unlock_irq(&irq_controller_lock);
+
+	return val;
+}
+
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+unsigned int probe_irq_mask(unsigned long val)
+{
+	int i;
+	unsigned int mask;
+
+	mask = 0;
+	spin_lock_irq(&irq_controller_lock);
+	for (i = 0; i < 16; i++) {
+		unsigned int status = irq_desc[i].status;
+
+		if (!(status & IRQ_AUTODETECT))
+			continue;
 
-	/* Now filter out any obviously spurious interrupts.  */
-	return irqs & ~alpha_irq_mask;
+		if (!(status & IRQ_WAITING))
+			mask |= 1 << i;
+
+		irq_desc[i].status = status & ~IRQ_AUTODETECT;
+		irq_desc[i].handler->shutdown(i);
+	}
+	spin_unlock_irq(&irq_controller_lock);
+
+	return mask & val;
 }
 
 /*
@@ -747,19 +1004,32 @@
  */
 
 int
-probe_irq_off(unsigned long irqs)
+probe_irq_off(unsigned long val)
 {
-	int i;
-	
-	/* Handle only the first 64 IRQs here.  This is enough for
-	   [E]ISA, which is the only thing that needs probing anyway.  */
-        irqs &= alpha_irq_mask;
-	if (!irqs)
-		return 0;
-	i = ffz(~irqs);
-	if (irqs != (1UL << i))
-		i = -i;
-	return i;
+	int i, irq_found, nr_irqs;
+
+	nr_irqs = 0;
+	irq_found = 0;
+	spin_lock_irq(&irq_controller_lock);
+	for (i=0; i<NR_IRQS; i++) {
+		unsigned int status = irq_desc[i].status;
+
+		if (!(status & IRQ_AUTODETECT))
+			continue;
+
+		if (!(status & IRQ_WAITING)) {
+			if (!nr_irqs)
+				irq_found = i;
+			nr_irqs++;
+		}
+		irq_desc[i].status = status & ~IRQ_AUTODETECT;
+		irq_desc[i].handler->shutdown(i);
+	}
+	spin_unlock_irq(&irq_controller_lock);
+
+	if (nr_irqs > 1)
+		irq_found = -irq_found;
+	return irq_found;
 }
 
 
@@ -774,15 +1044,21 @@
 {
 	switch (type) {
 	case 0:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		handle_ipi(&regs);
 		return;
 #else
-		printk("Interprocessor interrupt? You must be kidding\n");
+		printk(KERN_CRIT "Interprocessor interrupt? "
+		       "You must be kidding!\n");
 #endif
 		break;
 	case 1:
-		handle_irq(RTC_IRQ, -1, &regs);
+#ifdef CONFIG_SMP
+		cpu_data[smp_processor_id()].smp_local_irq_count++;
+		smp_percpu_timer_interrupt(&regs);
+		if (smp_processor_id() == smp_boot_cpuid)
+#endif
+			handle_irq(RTC_IRQ, &regs);
 		return;
 	case 2:
 		alpha_mv.machine_check(vector, la_ptr, &regs);
@@ -794,12 +1070,22 @@
 		perf_irq(vector, &regs);
 		return;
 	default:
-		printk("Hardware intr %ld %lx? Huh?\n", type, vector);
+		printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n",
+		       type, vector);
 	}
 	printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
 }
 
 void __init
+common_init_isa_dma(void)
+{
+	outb(0, DMA1_RESET_REG);
+	outb(0, DMA2_RESET_REG);
+	outb(0, DMA1_CLR_MASK_REG);
+	outb(0, DMA2_CLR_MASK_REG);
+}
+
+void __init
 init_IRQ(void)
 {
 	wrent(entInt, 0);
@@ -817,7 +1103,7 @@
 #define MCHK_K_OS_BUGCHECK     0x008A
 #define MCHK_K_PAL_BUGCHECK    0x0090
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 struct mcheck_info __mcheck_info;
 #endif
 
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/irq_impl.h linux/arch/alpha/kernel/irq_impl.h
--- v2.3.46/linux/arch/alpha/kernel/irq_impl.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/kernel/irq_impl.h	Sun Feb 20 08:13:56 2000
@@ -0,0 +1,59 @@
+/*
+ *	linux/arch/alpha/kernel/irq_impl.h
+ *
+ *	Copyright (C) 1995 Linus Torvalds
+ *	Copyright (C) 1998, 2000 Richard Henderson
+ *
+ * This file contains declarations and inline functions for interfacing
+ * with the IRQ handling routines in irq.c.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+
+#define RTC_IRQ    8
+
+extern void isa_device_interrupt(unsigned long, struct pt_regs *);
+extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *);
+extern void srm_device_interrupt(unsigned long, struct pt_regs *);
+extern void pyxis_device_interrupt(unsigned long, struct pt_regs *);
+
+extern struct irqaction isa_cascade_irqaction;
+extern struct irqaction timer_cascade_irqaction;
+extern struct irqaction halt_switch_irqaction;
+
+extern void init_srm_irqs(long, unsigned long);
+extern void init_pyxis_irqs(unsigned long);
+extern void init_rtc_irq(void);
+
+extern void common_init_isa_dma(void);
+
+extern void i8259a_enable_irq(unsigned int);
+extern void i8259a_disable_irq(unsigned int);
+extern void i8259a_mask_and_ack_irq(unsigned int);
+extern unsigned int i8259a_startup_irq(unsigned int);
+extern struct hw_interrupt_type i8259a_irq_type;
+extern void init_i8259a_irqs(void);
+
+extern void no_action(int cpl, void *dev_id, struct pt_regs *regs);
+extern void handle_irq(int irq, struct pt_regs * regs);
+
+static inline void
+alpha_do_profile(unsigned long pc)
+{
+	if (prof_buffer && current->pid) {
+		extern char _stext;
+
+		pc -= (unsigned long) &_stext;
+		pc >>= prof_shift;
+		/*
+		 * Don't ignore out-of-bounds PC values silently,
+		 * put them into the last histogram slot, so if
+		 * present, they will show up as a sharp peak.
+		 */
+		if (pc > prof_len - 1)
+			pc = prof_len - 1;
+		atomic_inc((atomic_t *)&prof_buffer[pc]);
+	}
+}
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- v2.3.46/linux/arch/alpha/kernel/pci.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/pci.c	Sun Feb 20 08:13:56 2000
@@ -109,7 +109,7 @@
 void
 pcibios_align_resource(void *data, struct resource *res, unsigned long size)
 {
-	struct pci_dev * dev = data;
+	struct pci_dev *dev = data;
 	unsigned long alignto;
 	unsigned long start = res->start;
 
@@ -325,10 +325,10 @@
 	ranges->mem_end -= bus->resource[1]->start;
 }
 
-int __init
+int
 pcibios_enable_device(struct pci_dev *dev)
 {
-	/* Not needed, since we enable all devices at startup.  */
+	/* Nothing to do, since we enable all devices at startup.  */
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c
--- v2.3.46/linux/arch/alpha/kernel/pci_iommu.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/alpha/kernel/pci_iommu.c	Fri Feb 18 15:07:20 2000
@@ -121,10 +121,10 @@
 /* Map a single buffer of the indicate size for PCI DMA in streaming
    mode.  The 32-bit PCI bus mastering address to use is returned.
    Once the device is given the dma address, the device owns this memory
-   until either pci_unmap_single or pci_sync_single is performed.  */
+   until either pci_unmap_single or pci_dma_sync_single is performed.  */
 
 dma_addr_t
-pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size)
+pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
 {
 	struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
 	dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
@@ -186,7 +186,7 @@
    wrote there.  */
 
 void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size)
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction)
 {
 	struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
 	struct pci_iommu_arena *arena;
@@ -247,7 +247,7 @@
 	}
 	memset(cpu_addr, 0, size);
 
-	*dma_addrp = pci_map_single(pdev, cpu_addr, size);
+	*dma_addrp = pci_map_single(pdev, cpu_addr, size, PCI_DMA_BIDIRECTIONAL);
 	if (*dma_addrp == 0) {
 		free_pages((unsigned long)cpu_addr, order);
 		return NULL;
@@ -270,7 +270,7 @@
 pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr,
 		    dma_addr_t dma_addr)
 {
-	pci_unmap_single(pdev, dma_addr, size);
+	pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
 	free_pages((unsigned long)cpu_addr, get_order(size));
 
 	DBGA2("pci_free_consistent: [%x,%lx] from %p\n",
@@ -424,7 +424,7 @@
 }
 
 int
-pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
+pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
 {
 	struct scatterlist *start, *end, *out;
 	struct pci_controler *hose;
@@ -435,7 +435,7 @@
 	if (nents == 1) {
 		sg->dma_length = sg->length;
 		sg->dma_address
-		  = pci_map_single(pdev, sg->address, sg->length);
+		  = pci_map_single(pdev, sg->address, sg->length, direction);
 		return sg->dma_address != 0;
 	}
 
@@ -472,6 +472,10 @@
 		out++;
 	}
 
+	/* Mark the end of the list for pci_unmap_sg.  */
+	if (out < end)
+		out->dma_length = 0;
+
 	if (out - start == 0)
 		printk(KERN_INFO "pci_map_sg failed: no entries?\n");
 	DBGA("pci_map_sg: %ld entries\n", out - start);
@@ -485,7 +489,7 @@
 	/* Some allocation failed while mapping the scatterlist
 	   entries.  Unmap them now.  */
 	if (out > start)
-		pci_unmap_sg(pdev, start, out - start);
+		pci_unmap_sg(pdev, start, out - start, direction);
 	return 0;
 }
 
@@ -495,7 +499,7 @@
    above.  */
 
 void
-pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
+pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
 {
 	struct pci_controler *hose;
 	struct pci_iommu_arena *arena;
@@ -512,8 +516,6 @@
 	if (!arena || arena->dma_base + arena->size > max_dma)
 		arena = hose->sg_isa;
 
-	DBGA("pci_unmap_sg: %d entries\n", nents);
-
 	fstart = -1;
 	fend = 0;
 	for (end = sg + nents; sg < end; ++sg) {
@@ -522,6 +524,9 @@
 		addr = sg->dma_address;
 		size = sg->dma_length;
 
+		if (!size)
+			break;
+
 		if (addr >= __direct_map_base
 		    && addr < __direct_map_base + __direct_map_size) {
 			/* Nothing to do.  */
@@ -531,6 +536,9 @@
 			long npages, ofs;
 			dma_addr_t tend;
 
+			DBGA("    (%ld) sg [%lx,%lx]\n",
+			      sg - end + nents, addr, size);
+
 			npages = calc_npages((addr & ~PAGE_MASK) + size);
 			ofs = (addr - arena->dma_base) >> PAGE_SHIFT;
 			iommu_arena_free(arena, ofs, npages);
@@ -540,11 +548,10 @@
 				fstart = addr;
 			if (fend < tend)
 				fend = tend;
-
-			DBGA("    (%ld) sg [%lx,%lx]\n",
-			      sg - end + nents, addr, size);
 		}
 	}
 	if (fend)
 		alpha_mv.mv_pci_tbi(hose, fstart, fend);
+
+	DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg));
 }
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.3.46/linux/arch/alpha/kernel/process.c	Tue Dec  7 09:32:39 1999
+++ linux/arch/alpha/kernel/process.c	Sun Feb 20 08:13:56 2000
@@ -30,10 +30,6 @@
 #include <linux/reboot.h>
 #include <linux/console.h>
 
-#ifdef CONFIG_RTC
-#include <linux/mc146818rtc.h>
-#endif
-
 #include <asm/reg.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -138,11 +134,6 @@
 		take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
 #endif
 	}
-
-#ifdef CONFIG_RTC
-	/* Reset rtc to defaults.  */
-	rtc_kill_pit();
-#endif
 
 	if (alpha_mv.kill_arch)
 		alpha_mv.kill_arch(mode);
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.3.46/linux/arch/alpha/kernel/proto.h	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/proto.h	Sun Feb 20 08:13:56 2000
@@ -10,6 +10,7 @@
 struct task_struct;
 struct pci_dev;
 struct pci_controler;
+struct irqaction;
 
 /* core_apecs.c */
 extern struct pci_ops apecs_pci_ops;
@@ -46,6 +47,8 @@
 
 /* core_polaris.c */
 extern struct pci_ops polaris_pci_ops;
+extern int polaris_read_config_dword(struct pci_dev *, int, u32 *);
+extern int polaris_write_config_dword(struct pci_dev *, int, u32);
 extern void polaris_init_arch(void);
 extern void polaris_machine_check(u64, u64, struct pt_regs *);
 #define polaris_pci_tbi ((void *)0)
@@ -84,9 +87,7 @@
 
 /* time.c */
 extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs);
-extern void rtc_init_pit(void);
-extern void rtc_kill_pit(void);
-extern void common_init_pit(void);
+extern void common_init_rtc(struct irqaction *);
 extern unsigned long est_cycle_freq;
 
 /* smc37c93x.c */
@@ -101,7 +102,7 @@
 /* ns87312.c */
 extern void ns87312_enable_ide(long ide_base);
 
-/* fpregs.c */
+/* ../lib/fpreg.c */
 extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
 extern unsigned long alpha_read_fp_reg (unsigned long reg);
 
@@ -134,7 +135,7 @@
 /* ../mm/init.c */
 void srm_paging_stop(void);
 
-/* irq.h */
+/* irq.c */
 
 #ifdef __SMP__
 #define mcheck_expected(cpu)	(cpu_data[cpu].mcheck_expected)
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.3.46/linux/arch/alpha/kernel/setup.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/setup.c	Sun Feb 20 08:13:56 2000
@@ -30,9 +30,6 @@
 #include <linux/ioport.h>
 #include <linux/bootmem.h>
 
-#ifdef CONFIG_RTC
-#include <linux/timex.h>
-#endif
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
 #endif
@@ -452,16 +449,6 @@
 
 	/* Reserve standard resources.  */
 	reserve_std_resources();
-
-	/* Initialize the timers.  */
-	/* ??? There is some circumstantial evidence that this needs
-	   to be done now rather than later in time_init, which would
-	   be more natural.  Someone please explain or refute.  */
-#if defined(CONFIG_RTC)
-	rtc_init_pit();
-#else
-	alpha_mv.init_pit();
-#endif
 
 	/* 
 	 * Give us a default console.  TGA users will see nothing until
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.3.46/linux/arch/alpha/kernel/smp.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/smp.c	Sun Feb 20 08:13:56 2000
@@ -33,6 +33,7 @@
 #include <asm/unistd.h>
 
 #include "proto.h"
+#include "irq_impl.h"
 
 
 #define DEBUG_SMP 0
@@ -62,6 +63,7 @@
 static unsigned long smp_secondary_alive;
 
 unsigned long cpu_present_mask;	/* Which cpus ids came online.  */
+static unsigned long __cpu_present_mask __initdata = 0; /* cpu reported in the hwrpb */
 
 static int max_cpus = -1;	/* Command-line limitation.  */
 int smp_boot_cpuid;		/* Which processor we booted from.  */
@@ -506,7 +508,7 @@
 			if ((cpu->flags & 0x1cc) == 0x1cc) {
 				smp_num_probed++;
 				/* Assume here that "whami" == index */
-				cpu_present_mask |= (1L << i);
+				__cpu_present_mask |= (1L << i);
 				cpu->pal_revision = boot_cpu_palrev;
 			}
 
@@ -517,11 +519,12 @@
 		}
 	} else {
 		smp_num_probed = 1;
-		cpu_present_mask = (1L << smp_boot_cpuid);
+		__cpu_present_mask = (1L << smp_boot_cpuid);
 	}
+	cpu_present_mask = 1L << smp_boot_cpuid;
 
 	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
-	       smp_num_probed, cpu_present_mask);
+	       smp_num_probed, __cpu_present_mask);
 }
 
 /*
@@ -565,12 +568,13 @@
 		if (i == smp_boot_cpuid)
 			continue;
 
-		if (((cpu_present_mask >> i) & 1) == 0)
+		if (((__cpu_present_mask >> i) & 1) == 0)
 			continue;
 
 		if (smp_boot_one_cpu(i, cpu_count))
 			continue;
 
+		cpu_present_mask |= 1L << i;
 		cpu_count++;
 	}
 
@@ -623,7 +627,7 @@
 		/* We need to make like a normal interrupt -- otherwise
 		   timer interrupts ignore the global interrupt lock,
 		   which would be a Bad Thing.  */
-		irq_enter(cpu, TIMER_IRQ);
+		irq_enter(cpu, RTC_IRQ);
 
 		update_one_process(current, 1, user, !user, cpu);
 		if (current->pid) {
@@ -647,7 +651,7 @@
 		}
 
 		data->prof_counter = data->prof_multiplier;
-		irq_exit(cpu, TIMER_IRQ);
+		irq_exit(cpu, RTC_IRQ);
 	}
 }
 
@@ -865,6 +869,22 @@
 	}
 
 	return 0;
+}
+
+static void
+ipi_imb(void *ignored)
+{
+	imb();
+}
+
+void
+smp_imb(void)
+{
+	/* Must wait other processors to flush their icache before continue. */
+	if (smp_call_function(ipi_imb, NULL, 1, 1))
+		printk(KERN_CRIT "smp_imb: timed out\n");
+
+	imb();
 }
 
 static void
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_alcor.c linux/arch/alpha/kernel/sys_alcor.c
--- v2.3.46/linux/arch/alpha/kernel/sys_alcor.c	Tue Dec  7 09:32:39 1999
+++ linux/arch/alpha/kernel/sys_alcor.c	Sun Feb 20 08:13:56 2000
@@ -27,50 +27,71 @@
 #include <asm/core_cia.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
-static void 
-alcor_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for ENABLED irqs.  */
+static unsigned long cached_irq_mask;
+
+static inline void
+alcor_update_irq_hw(unsigned long mask)
 {
-	if (irq >= 16) {
-		/* On Alcor, at least, lines 20..30 are not connected and can
-		   generate spurrious interrupts if we turn them on while IRQ
-		   probing.  So explicitly mask them out. */
-		mask |= 0x7ff000000000UL;
+	*(vuip)GRU_INT_MASK = mask;
+	mb();
+}
 
-		/* Note inverted sense of mask bits: */
-		*(vuip)GRU_INT_MASK = ~(mask >> 16);
-		mb();
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
+static inline void
+alcor_enable_irq(unsigned int irq)
+{
+	alcor_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+}
+
+static inline void
+alcor_disable_irq(unsigned int irq)
+{
+	alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
 }
 
 static void
-alcor_ack_irq(unsigned long irq)
+alcor_mask_and_ack_irq(unsigned int irq)
 {
-	if (irq < 16) {
-		/* Ack the interrupt making it the lowest priority */
-		/*  First the slave .. */
-		if (irq > 7) {
-			outb(0xE0 | (irq - 8), 0xa0);
-			irq = 2;
-		}
-		/* .. then the master */
-		outb(0xE0 | irq, 0x20);
+	alcor_disable_irq(irq);
 
-		/* On ALCOR/XLT, need to dismiss interrupt via GRU. */
-		*(vuip)GRU_INT_CLEAR = 0x80000000; mb();
-		*(vuip)GRU_INT_CLEAR = 0x00000000; mb();
-	}
+	/* On ALCOR/XLT, need to dismiss interrupt via GRU. */
+	*(vuip)GRU_INT_CLEAR = 1 << (irq - 16); mb();
+	*(vuip)GRU_INT_CLEAR = 0; mb();
+}
+
+static unsigned int
+alcor_startup_irq(unsigned int irq)
+{
+	alcor_enable_irq(irq);
+	return 0;
 }
 
 static void
+alcor_isa_mask_and_ack_irq(unsigned int irq)
+{
+	i8259a_mask_and_ack_irq(irq);
+
+	/* On ALCOR/XLT, need to dismiss interrupt via GRU. */
+	*(vuip)GRU_INT_CLEAR = 0x80000000; mb();
+	*(vuip)GRU_INT_CLEAR = 0; mb();
+}
+
+static struct hw_interrupt_type alcor_irq_type = {
+	typename:	"ALCOR",
+	startup:	alcor_startup_irq,
+	shutdown:	alcor_disable_irq,
+	enable:		alcor_enable_irq,
+	disable:	alcor_disable_irq,
+	ack:		alcor_mask_and_ack_irq,
+	end:		alcor_enable_irq,
+};
+
+static void
 alcor_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
 	unsigned long pld;
@@ -89,26 +110,40 @@
 		if (i == 31) {
 			isa_device_interrupt(vector, regs);
 		} else {
-			handle_irq(16 + i, 16 + i, regs);
+			handle_irq(16 + i, regs);
 		}
 	}
 }
 
-static void
+static void __init
 alcor_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	long i;
 
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = srm_device_interrupt;
 
-	*(vuip)GRU_INT_MASK  = ~(alpha_irq_mask >> 16); mb(); /* invert */
-	*(vuip)GRU_INT_EDGE  = 0U; mb();		/* all are level */
+	*(vuip)GRU_INT_MASK  = 0; mb();			/* all disabled */
+	*(vuip)GRU_INT_EDGE  = 0; mb();			/* all are level */
 	*(vuip)GRU_INT_HILO  = 0x80000000U; mb();	/* ISA only HI */
-	*(vuip)GRU_INT_CLEAR = 0UL; mb();		/* all clear */
+	*(vuip)GRU_INT_CLEAR = 0; mb();			/* all clear */
+
+	for (i = 16; i < 48; ++i) {
+		/* On Alcor, at least, lines 20..30 are not connected
+		   and can generate spurrious interrupts if we turn them
+		   on while IRQ probing.  */
+		if (i >= 16+20 && i <= 16+30)
+			continue;
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &alcor_irq_type;
+	}
+	i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;
+
+	init_i8259a_irqs();
+	init_rtc_irq();
+	common_init_isa_dma();
 
-	enable_irq(16 + 31);		/* enable (E)ISA PIC cascade */
-	enable_irq(2);			/* enable cascade */
+	setup_irq(16+31, &isa_cascade_irqaction);
 }
 
 
@@ -203,14 +238,11 @@
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		48,
-	irq_probe_mask:		ALCOR_PROBE_MASK,
-	update_irq_hw:		alcor_update_irq_hw,
-	ack_irq:		alcor_ack_irq,
 	device_interrupt:	alcor_device_interrupt,
 
 	init_arch:		cia_init_arch,
 	init_irq:		alcor_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		alcor_kill_arch,
 	pci_map_irq:		alcor_map_irq,
@@ -236,14 +268,11 @@
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		48,
-	irq_probe_mask:		ALCOR_PROBE_MASK,
-	update_irq_hw:		alcor_update_irq_hw,
-	ack_irq:		alcor_ack_irq,
 	device_interrupt:	alcor_device_interrupt,
 
 	init_arch:		cia_init_arch,
 	init_irq:		alcor_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		alcor_kill_arch,
 	pci_map_irq:		alcor_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_cabriolet.c linux/arch/alpha/kernel/sys_cabriolet.c
--- v2.3.46/linux/arch/alpha/kernel/sys_cabriolet.c	Tue Dec  7 09:32:39 1999
+++ linux/arch/alpha/kernel/sys_cabriolet.c	Sun Feb 20 08:13:56 2000
@@ -31,42 +31,50 @@
 #include <asm/core_pyxis.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
-static void
-cabriolet_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for DISABLED irqs.  */
+static unsigned long cached_irq_mask = ~0UL;
+
+static inline void
+cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
 {
-	if (irq >= 16)
-		outl(alpha_irq_mask >> 16, 0x804);
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);
-	else
-		outb(mask, 0x21);
+	int ofs = (irq - 16) / 8;
+	outb(mask >> (16 + ofs*3), 0x804 + ofs);
 }
 
-
-/* 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.  */
+static inline void
+cabriolet_enable_irq(unsigned int irq)
+{
+	cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq));
+}
 
 static void
-cabriolet_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmaskp)
+cabriolet_disable_irq(unsigned int irq)
 {
-	if (irq >= 16) {
-		if (unmaskp)
-			cserve_ena(irq - 16);
-		else
-			cserve_dis(irq - 16);
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);
-	else
-		outb(mask, 0x21);
+	cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
 }
 
+static unsigned int
+cabriolet_startup_irq(unsigned int irq)
+{ 
+	cabriolet_enable_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type cabriolet_irq_type = {
+	typename:	"CABRIOLET",
+	startup:	cabriolet_startup_irq,
+	shutdown:	cabriolet_disable_irq,
+	enable:		cabriolet_enable_irq,
+	disable:	cabriolet_disable_irq,
+	ack:		cabriolet_disable_irq,
+	end:		cabriolet_enable_irq,
+};
+
 static void 
 cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
 {
@@ -86,26 +94,36 @@
 		if (i == 4) {
 			isa_device_interrupt(v, r);
 		} else {
-			handle_irq(16 + i, 16 + i, r);
+			handle_irq(16 + i, r);
 		}
 	}
 }
 
-static void
+static void __init
 cabriolet_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	init_i8259a_irqs();
+	init_rtc_irq();
 
 	if (alpha_using_srm) {
-		alpha_mv.update_irq_hw = cabriolet_srm_update_irq_hw;
 		alpha_mv.device_interrupt = srm_device_interrupt;
+		init_srm_irqs(35, 0);
 	}
 	else {
-		outl(alpha_irq_mask >> 16, 0x804);
+		long i;
+
+		outb(0xff, 0x804);
+		outb(0xff, 0x805);
+		outb(0xff, 0x806);
+
+		for (i = 16; i < 35; ++i) {
+			irq_desc[i].status = IRQ_DISABLED;
+			irq_desc[i].handler = &cabriolet_irq_type;
+		}
 	}
 
-	enable_irq(16 + 4);		/* enable SIO cascade */
-	enable_irq(2);			/* enable cascade */
+	common_init_isa_dma();
+	setup_irq(16+4, &isa_cascade_irqaction);
 }
 
 
@@ -260,14 +278,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		35,
-	irq_probe_mask:		_PROBE_MASK(35),
-	update_irq_hw:		cabriolet_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	cabriolet_device_interrupt,
 
 	init_arch:		apecs_init_arch,
 	init_irq:		cabriolet_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		cabriolet_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		cabriolet_map_irq,
@@ -289,14 +304,11 @@
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		35,
-	irq_probe_mask:		_PROBE_MASK(35),
-	update_irq_hw:		cabriolet_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	cabriolet_device_interrupt,
 
 	init_arch:		cia_init_arch,
 	init_irq:		cabriolet_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		cabriolet_init_pci,
 	pci_map_irq:		cabriolet_map_irq,
 	pci_swizzle:		common_swizzle,
@@ -317,14 +329,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		35,
-	irq_probe_mask:		_PROBE_MASK(35),
-	update_irq_hw:		cabriolet_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	cabriolet_device_interrupt,
 
 	init_arch:		lca_init_arch,
 	init_irq:		cabriolet_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		cabriolet_init_pci,
 	pci_map_irq:		eb66p_map_irq,
 	pci_swizzle:		common_swizzle,
@@ -345,14 +354,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		35,
-	irq_probe_mask:		_PROBE_MASK(35),
-	update_irq_hw:		cabriolet_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	cabriolet_device_interrupt,
 
 	init_arch:		pyxis_init_arch,
 	init_irq:		cabriolet_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
@@ -373,14 +379,11 @@
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		35,
-	irq_probe_mask:		_PROBE_MASK(35),
-	update_irq_hw:		cabriolet_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	cabriolet_device_interrupt,
 
 	init_arch:		cia_init_arch,
 	init_irq:		cabriolet_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.3.46/linux/arch/alpha/kernel/sys_dp264.c	Tue Dec  7 09:32:39 1999
+++ linux/arch/alpha/kernel/sys_dp264.c	Sun Feb 20 08:13:56 2000
@@ -8,6 +8,7 @@
  * Code supporting the DP264 (EV6+TSUNAMI).
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/mm.h>
@@ -27,72 +28,150 @@
 #include <asm/hwrpb.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
-/*
- * HACK ALERT! only the boot cpu is used for interrupts.
- */
+static unsigned long cached_irq_mask;
+
+
+#define TSUNAMI_SET_IRQ_MASK(cpu, value)	\
+do {						\
+	volatile unsigned long *csr;		\
+	csr = &TSUNAMI_cchip->dim##cpu##.csr;	\
+	*csr = (value);				\
+	mb();					\
+	*csr;					\
+} while(0)
+
+static inline void
+do_flush_irq_mask(unsigned long value)
+{
+	switch (TSUNAMI_bootcpu) {
+	case 0:
+		TSUNAMI_SET_IRQ_MASK(0, value);
+		break;
+	case 1:
+		TSUNAMI_SET_IRQ_MASK(1, value);
+		break;
+	case 2:
+		TSUNAMI_SET_IRQ_MASK(2, value);
+		break;
+	case 3:
+		TSUNAMI_SET_IRQ_MASK(3, value);
+		break;
+	}
+}
+
+#ifdef CONFIG_SMP
+static inline void
+do_flush_smp_irq_mask(unsigned long value)
+{
+	extern unsigned long cpu_present_mask;
+	unsigned long other_cpus = cpu_present_mask & ~(1L << TSUNAMI_bootcpu);
+
+	if (other_cpus & 1)
+		TSUNAMI_SET_IRQ_MASK(0, value);
+	if (other_cpus & 2)
+		TSUNAMI_SET_IRQ_MASK(1, value);
+	if (other_cpus & 4)
+		TSUNAMI_SET_IRQ_MASK(2, value);
+	if (other_cpus & 8)
+		TSUNAMI_SET_IRQ_MASK(3, value);
+}
+#endif
 
 static void
-dp264_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+dp264_flush_irq_mask(unsigned long mask)
 {
-	volatile unsigned long *csr;
+	unsigned long value;
 
-	if (TSUNAMI_bootcpu < 2) {
-		if (!TSUNAMI_bootcpu)
-			csr = &TSUNAMI_cchip->dim0.csr;
-		else
-			csr = &TSUNAMI_cchip->dim1.csr;
-	} else {
-		if (TSUNAMI_bootcpu == 2)
-			csr = &TSUNAMI_cchip->dim2.csr;
-		else
-			csr = &TSUNAMI_cchip->dim3.csr;
-	}
+#ifdef CONFIG_SMP
+	do_flush_smp_irq_mask(mask);
+#endif
 
-	*csr = ~mask;
-	mb();
-	*csr;
-
-	if (irq < 16) {
-		if (irq >= 8)
-			outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-		else
-			outb(mask, 0x21);	/* ISA PIC1 */
-	}
+	value = mask | (1UL << 55) | 0xffff; /* isa irqs always enabled */
+	do_flush_irq_mask(value);
 }
 
 static void
-clipper_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+clipper_flush_irq_mask(unsigned long mask)
 {
-	if (irq >= 16) {
-		volatile unsigned long *csr;
+	unsigned long value;
 
-		if (TSUNAMI_bootcpu < 2)
-			if (!TSUNAMI_bootcpu)
-				csr = &TSUNAMI_cchip->dim0.csr;
-			else
-				csr = &TSUNAMI_cchip->dim1.csr;
-		else
-			if (TSUNAMI_bootcpu == 2)
-				csr = &TSUNAMI_cchip->dim2.csr;
-			else
-				csr = &TSUNAMI_cchip->dim3.csr;
-		
-		*csr = (~mask >> 16) | (1UL << 55); /* master ISA enable */
-		mb();
-		*csr;
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
+	value = mask >> 16;
+#ifdef CONFIG_SMP
+	do_flush_smp_irq_mask(value);
+#endif
+
+	value = value | (1UL << 55); /* master ISA enable */
+	do_flush_irq_mask(value);
+}
+
+static inline void
+dp264_enable_irq(unsigned int irq)
+{
+	cached_irq_mask |= 1UL << irq;
+	dp264_flush_irq_mask(cached_irq_mask);
 }
 
 static void
+dp264_disable_irq(unsigned int irq)
+{
+	cached_irq_mask &= ~(1UL << irq);
+	dp264_flush_irq_mask(cached_irq_mask);
+}
+
+static unsigned int
+dp264_startup_irq(unsigned int irq)
+{ 
+	dp264_enable_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static inline void
+clipper_enable_irq(unsigned int irq)
+{
+	cached_irq_mask |= 1UL << irq;
+	clipper_flush_irq_mask(cached_irq_mask);
+}
+
+static void
+clipper_disable_irq(unsigned int irq)
+{
+	cached_irq_mask &= ~(1UL << irq);
+	clipper_flush_irq_mask(cached_irq_mask);
+}
+
+static unsigned int
+clipper_startup_irq(unsigned int irq)
+{ 
+	clipper_enable_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type dp264_irq_type = {
+	typename:	"DP264",
+	startup:	dp264_startup_irq,
+	shutdown:	dp264_disable_irq,
+	enable:		dp264_enable_irq,
+	disable:	dp264_disable_irq,
+	ack:		dp264_disable_irq,
+	end:		dp264_enable_irq,
+};
+
+static struct hw_interrupt_type clipper_irq_type = {
+	typename:	"CLIPPER",
+	startup:	clipper_startup_irq,
+	shutdown:	clipper_disable_irq,
+	enable:		clipper_enable_irq,
+	disable:	clipper_disable_irq,
+	ack:		clipper_disable_irq,
+	end:		clipper_enable_irq,
+};
+
+static void
 dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 #if 1
@@ -126,9 +205,9 @@
 static void 
 dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	int irq, ack;
+	int irq;
 
-	ack = irq = (vector - 0x800) >> 4;
+	irq = (vector - 0x800) >> 4;
 
 	/*
 	 * The SRM console reports PCI interrupts with a vector calculated by:
@@ -142,17 +221,17 @@
 	 * so we don't count them.
 	 */
 	if (irq >= 32)
-		ack = irq = irq - 16;
+		irq -= 16;
 
-	handle_irq(irq, ack, regs);
+	handle_irq(irq, regs);
 }
 
 static void 
 clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	int irq, ack;
+	int irq;
 
-	ack = irq = (vector - 0x800) >> 4;
+	irq = (vector - 0x800) >> 4;
 
 	/*
 	 * The SRM console reports PCI interrupts with a vector calculated by:
@@ -166,7 +245,19 @@
 	 *
 	 * Eg IRQ 24 is DRIR bit 8, etc, etc
 	 */
-	handle_irq(irq, ack, regs);
+	handle_irq(irq, regs);
+}
+
+static void __init
+init_tsunami_irqs(struct hw_interrupt_type * ops)
+{
+	long i;
+
+	/* Only irqs between 16 and 47 are tsunami irqs.  */
+	for (i = 16; i < 48; ++i) {
+		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
+		irq_desc[i].handler = ops;
+	}
 }
 
 static void __init
@@ -180,10 +271,11 @@
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = dp264_srm_device_interrupt;
 
-	dp264_update_irq_hw(16, alpha_irq_mask, 0);
+	dp264_flush_irq_mask(0UL);
 
-        enable_irq(55);     /* Enable ISA interrupt controller.  */
-	enable_irq(2);
+	init_i8259a_irqs();
+	init_rtc_irq();
+	init_tsunami_irqs(&dp264_irq_type);
 }
 
 static void __init
@@ -197,10 +289,11 @@
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = clipper_srm_device_interrupt;
 
-	clipper_update_irq_hw(16, alpha_irq_mask, 0);
+	clipper_flush_irq_mask(0UL);
 
-        enable_irq(55);     /* Enable ISA interrupt controller.  */
-	enable_irq(2);
+	init_i8259a_irqs();
+	init_rtc_irq();
+	init_tsunami_irqs(&clipper_irq_type);
 }
 
 
@@ -431,14 +524,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		64,
-	irq_probe_mask:		TSUNAMI_PROBE_MASK,
-	update_irq_hw:		dp264_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
 
 	init_arch:		tsunami_init_arch,
 	init_irq:		dp264_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		dp264_init_pci,
 	kill_arch:		tsunami_kill_arch,
 	pci_map_irq:		dp264_map_irq,
@@ -458,14 +548,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		64,
-	irq_probe_mask:		TSUNAMI_PROBE_MASK,
-	update_irq_hw:		dp264_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
 
 	init_arch:		tsunami_init_arch,
 	init_irq:		dp264_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		monet_init_pci,
 	kill_arch:		tsunami_kill_arch,
 	pci_map_irq:		monet_map_irq,
@@ -484,14 +571,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		64,
-	irq_probe_mask:		TSUNAMI_PROBE_MASK,
-	update_irq_hw:		dp264_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
 
 	init_arch:		tsunami_init_arch,
 	init_irq:		dp264_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		tsunami_kill_arch,
 	pci_map_irq:		webbrick_map_irq,
@@ -510,14 +594,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		64,
-	irq_probe_mask:		TSUNAMI_PROBE_MASK,
-	update_irq_hw:		clipper_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
 
 	init_arch:		tsunami_init_arch,
 	init_irq:		clipper_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		tsunami_kill_arch,
 	pci_map_irq:		clipper_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_eb64p.c linux/arch/alpha/kernel/sys_eb64p.c
--- v2.3.46/linux/arch/alpha/kernel/sys_eb64p.c	Tue Dec  7 09:32:39 1999
+++ linux/arch/alpha/kernel/sys_eb64p.c	Sun Feb 20 08:13:56 2000
@@ -28,25 +28,49 @@
 #include <asm/core_lca.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
-static void
-eb64p_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for DISABLED irqs.  */
+static unsigned int cached_irq_mask = -1;
+
+static inline void
+eb64p_update_irq_hw(unsigned int irq, unsigned long mask)
 {
-	if (irq >= 16)
-		if (irq >= 24)
-			outb(mask >> 24, 0x27);
-		else
-			outb(mask >> 16, 0x26);
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);
-	else
-		outb(mask, 0x21);
+	outb(mask >> (irq >= 24 ? 24 : 16), (irq >= 24 ? 0x27 : 0x26));
 }
 
+static inline void
+eb64p_enable_irq(unsigned int irq)
+{
+	eb64p_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+}
+
+static inline void
+eb64p_disable_irq(unsigned int irq)
+{
+	eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
+}
+
+static unsigned int
+eb64p_startup_irq(unsigned int irq)
+{
+	eb64p_enable_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type eb64p_irq_type = {
+	typename:	"EB64P",
+	startup:	eb64p_startup_irq,
+	shutdown:	eb64p_disable_irq,
+	enable:		eb64p_enable_irq,
+	disable:	eb64p_disable_irq,
+	ack:		eb64p_disable_irq,
+	end:		eb64p_enable_irq,
+};
+
 static void 
 eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
@@ -55,6 +79,7 @@
 
 	/* Read the interrupt summary registers */
 	pld = inb(0x26) | (inb(0x27) << 8);
+
 	/*
 	 * Now, for every possible bit set, work through
 	 * them and call the appropriate interrupt handler.
@@ -66,7 +91,7 @@
 		if (i == 5) {
 			isa_device_interrupt(vector, regs);
 		} else {
-			handle_irq(16 + i, 16 + i, regs);
+			handle_irq(16 + i, regs);
 		}
 	}
 }
@@ -74,6 +99,8 @@
 static void __init
 eb64p_init_irq(void)
 {
+	long i;
+
 #ifdef CONFIG_ALPHA_GENERIC
 	/*
 	 * CABRIO SRM may not set variation correctly, so here we test
@@ -82,21 +109,25 @@
 	 */
 	if (inw(0x806) != 0xffff) {
 		extern struct alpha_machine_vector cabriolet_mv;
-#if 1
-		printk("eb64p_init_irq: resetting for CABRIO\n");
-#endif
 		alpha_mv = cabriolet_mv;
 		alpha_mv.init_irq();
 		return;
 	}
 #endif /* GENERIC */
 
-	STANDARD_INIT_IRQ_PROLOG;
+	outb(0xff, 0x26);
+	outb(0xff, 0x27);
+
+	init_i8259a_irqs();
+	init_rtc_irq();
+
+	for (i = 16; i < 32; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &eb64p_irq_type;
+	}		
 
-	outb(alpha_irq_mask >> 16, 0x26);
-	outb(alpha_irq_mask >> 24, 0x27);
-	enable_irq(16 + 5);		/* enable SIO cascade */
-	enable_irq(2);			/* enable cascade */
+	common_init_isa_dma();
+	setup_irq(16+5, &isa_cascade_irqaction);
 }
 
 /*
@@ -112,7 +143,7 @@
  * 3        Interrupt Line B from slot 1
  * 4        Interrupt Line C from slot 0
  * 5        Interrupt line from the two ISA PICs
- * 6        Tulip (slot 
+ * 6        Tulip
  * 7        NCR SCSI
  *
  * Summary @ 0x27
@@ -174,14 +205,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		32,
-	irq_probe_mask:		_PROBE_MASK(32),
-	update_irq_hw:		eb64p_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	eb64p_device_interrupt,
 
 	init_arch:		apecs_init_arch,
 	init_irq:		eb64p_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		eb64p_map_irq,
@@ -203,14 +231,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		32,
-	irq_probe_mask:		_PROBE_MASK(32),
-	update_irq_hw:		eb64p_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	eb64p_device_interrupt,
 
 	init_arch:		lca_init_arch,
 	init_irq:		eb64p_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	pci_map_irq:		eb64p_map_irq,
 	pci_swizzle:		common_swizzle,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_eiger.c linux/arch/alpha/kernel/sys_eiger.c
--- v2.3.46/linux/arch/alpha/kernel/sys_eiger.c	Tue Dec  7 09:32:39 1999
+++ linux/arch/alpha/kernel/sys_eiger.c	Sun Feb 20 08:13:56 2000
@@ -29,7 +29,7 @@
 #include <asm/hwrpb.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
@@ -38,29 +38,54 @@
  * HACK ALERT! only the boot cpu is used for interrupts.
  */
 
-static void
-eiger_update_irq_hw(unsigned long irq, unsigned long unused, int unmask_p)
+/* Note that this interrupt code is identical to TAKARA.  */
+
+/* Note mask bit is true for DISABLED irqs.  */
+static unsigned long cached_irq_mask[2] = { -1, -1 };
+
+static inline void
+eiger_update_irq_hw(unsigned long irq, unsigned long mask)
 {
-	unsigned int regaddr;
-	unsigned long mask;
+	int regaddr;
 
-	if (irq <= 15) {
-		if (irq <= 7)
-			outb(alpha_irq_mask, 0x21);		/* ISA PIC1 */
-		else
-			outb(alpha_irq_mask >> 8, 0xA1);	/* ISA PIC2 */
-	} else {
-		if (irq > 63)
-			mask = _alpha_irq_masks[1] << 16;
-		else
-			mask = _alpha_irq_masks[0] >> ((irq - 16) & 0x30);
+	mask = (irq >= 64 ? mask << 16 : mask >> ((irq - 16) & 0x30));
+	regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+	outl(mask & 0xffff0000UL, regaddr);
+}
 
-		regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+static inline void
+eiger_enable_irq(unsigned int irq)
+{
+	unsigned long mask;
+	mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
+	eiger_update_irq_hw(irq, mask);
+}
 
-		outl(mask & 0xffff0000UL, regaddr);
-	}
+static void
+eiger_disable_irq(unsigned int irq)
+{
+	unsigned long mask;
+	mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
+	eiger_update_irq_hw(irq, mask);
 }
 
+static unsigned int
+eiger_startup_irq(unsigned int irq)
+{
+	eiger_enable_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type eiger_irq_type = {
+	typename:	"EIGER",
+	startup:	eiger_startup_irq,
+	shutdown:	eiger_disable_irq,
+	enable:		eiger_enable_irq,
+	disable:	eiger_disable_irq,
+	ack:		eiger_disable_irq,
+	end:		eiger_enable_irq,
+};
+
 static void
 eiger_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
@@ -89,25 +114,27 @@
 		 * despatch an interrupt if it's set.
 		 */
 
-		if (intstatus & 8) handle_irq(16+3, 16+3, regs);
-		if (intstatus & 4) handle_irq(16+2, 16+2, regs);
-		if (intstatus & 2) handle_irq(16+1, 16+1, regs);
-		if (intstatus & 1) handle_irq(16+0, 16+0, regs);
+		if (intstatus & 8) handle_irq(16+3, regs);
+		if (intstatus & 4) handle_irq(16+2, regs);
+		if (intstatus & 2) handle_irq(16+1, regs);
+		if (intstatus & 1) handle_irq(16+0, regs);
 	} else {
-		isa_device_interrupt (vector, regs);
+		isa_device_interrupt(vector, regs);
 	}
 }
 
 static void
 eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-   int irq = (vector - 0x800) >> 4;
-   handle_irq(irq, irq, regs);
+	int irq = (vector - 0x800) >> 4;
+	handle_irq(irq, regs);
 }
 
 static void __init
 eiger_init_irq(void)
 {
+	long i;
+
 	outb(0, DMA1_RESET_REG);
 	outb(0, DMA2_RESET_REG);
 	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
@@ -116,9 +143,16 @@
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = eiger_srm_device_interrupt;
 
-	eiger_update_irq_hw(16, alpha_irq_mask, 0);
+	for (i = 16; i < 128; i += 16)
+		eiger_update_irq_hw(i, -1);
 
-	enable_irq(2);
+	init_i8259a_irqs();
+	init_rtc_irq();
+
+	for (i = 16; i < 128; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &eiger_irq_type;
+	}
 }
 
 static int __init
@@ -199,14 +233,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		128,
-	irq_probe_mask:		TSUNAMI_PROBE_MASK,
-	update_irq_hw:		eiger_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	eiger_device_interrupt,
 
 	init_arch:		tsunami_init_arch,
 	init_irq:		eiger_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		tsunami_kill_arch,
 	pci_map_irq:		eiger_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c
--- v2.3.46/linux/arch/alpha/kernel/sys_jensen.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/sys_jensen.c	Sun Feb 20 08:13:56 2000
@@ -28,19 +28,10 @@
 #include <asm/pgtable.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "machvec_impl.h"
 
 
-static void
-jensen_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
-	if (irq >= 8)
-		outb(mask >> 8, 0xA1);
-	else
-		outb(mask, 0x21);
-}
-
 /*
  * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
  * 0x9X0 for the local motherboard interrupts..
@@ -66,51 +57,71 @@
  */
 
 static void
-handle_nmi(struct pt_regs * regs)
+jensen_local_ack(unsigned int irq)
 {
-	printk("Whee.. NMI received. Probable hardware error\n");
-	printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
-}
+	/* irq1 is supposed to be the keyboard, silly Jensen.  */
+	if (irq == 7)
+		i8259a_mask_and_ack_irq(1);
+}
+
+static struct hw_interrupt_type jensen_local_irq_type = {
+	typename:	"LOCAL",
+	startup:	i8259a_startup_irq,
+	shutdown:	i8259a_disable_irq,
+	enable:		i8259a_enable_irq,
+	disable:	i8259a_disable_irq,
+	ack:		jensen_local_ack,
+	end:		i8259a_enable_irq,
+};
 
 static void 
 jensen_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	int irq, ack;
-
-	ack = irq = (vector - 0x800) >> 4;
+	int irq;
 
 	switch (vector) {
-	case 0x660: handle_nmi(regs); return;
+	case 0x660:
+		printk("Whee.. NMI received. Probable hardware error\n");
+		printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
+		return;
 
 	/* local device interrupts: */
-	case 0x900: irq = 4, ack = -1; break;		/* com1 -> irq 4 */
-	case 0x920: irq = 3, ack = -1; break;		/* com2 -> irq 3 */
-	case 0x980: irq = 1, ack = -1; break;		/* kbd -> irq 1 */
-	case 0x990: irq = 9, ack = -1; break;		/* mouse -> irq 9 */
+	case 0x900: irq = 4; break;		/* com1 -> irq 4 */
+	case 0x920: irq = 3; break;		/* com2 -> irq 3 */
+	case 0x980: irq = 1; break;		/* kbd -> irq 1 */
+	case 0x990: irq = 9; break;		/* mouse -> irq 9 */
+
 	default:
 		if (vector > 0x900) {
 			printk("Unknown local interrupt %lx\n", vector);
+			return;
 		}
 
-		/* irq1 is supposed to be the keyboard, silly Jensen
-		   (is this really needed??) */
+		irq = (vector - 0x800) >> 4;
 		if (irq == 1)
 			irq = 7;
 		break;
 	}
 
-	handle_irq(irq, ack, regs);
+	handle_irq(irq, regs);
 }
 
-static void
+static void __init
 jensen_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	init_i8259a_irqs();
+	init_rtc_irq();
 
-	enable_irq(2);			/* enable cascade */
+	irq_desc[1].handler = &jensen_local_irq_type;
+	irq_desc[4].handler = &jensen_local_irq_type;
+	irq_desc[3].handler = &jensen_local_irq_type;
+	irq_desc[7].handler = &jensen_local_irq_type;
+	irq_desc[9].handler = &jensen_local_irq_type;
+
+	common_init_isa_dma();
 }
 
-static void
+static void __init
 jensen_init_arch(void)
 {
 	__direct_map_base = 0;
@@ -140,14 +151,11 @@
 	rtc_port: 0x170,
 
 	nr_irqs:		16,
-	irq_probe_mask:		_PROBE_MASK(16),
-	update_irq_hw:		jensen_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	jensen_device_interrupt,
 
 	init_arch:		jensen_init_arch,
 	init_irq:		jensen_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		NULL,
 	kill_arch:		NULL,
 };
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c
--- v2.3.46/linux/arch/alpha/kernel/sys_miata.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_miata.c	Sun Feb 20 08:13:56 2000
@@ -25,71 +25,17 @@
 #include <asm/core_pyxis.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
 static void 
-miata_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
-	if (irq >= 16) {
-		/* Make CERTAIN none of the bogus ints get enabled... */
-		*(vulp)PYXIS_INT_MASK =
-			~((long)mask >> 16) & ~0x400000000000063bUL;
-		mb();
-		/* ... and read it back to make sure it got written.  */
-		*(vulp)PYXIS_INT_MASK;
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
-}
-
-static void 
-miata_device_interrupt(unsigned long vector, struct pt_regs *regs)
-{
-	unsigned long pld, tmp;
-	unsigned int i;
-
-	/* Read the interrupt summary register of PYXIS */
-	pld = *(vulp)PYXIS_INT_REQ;
-
-	/*
-	 * For now, AND off any bits we are not interested in:
-	 *   HALT (2), timer (6), ISA Bridge (7), 21142/3 (8)
-	 * then all the PCI slots/INTXs (12-31).
-	 */
-	/* Maybe HALT should only be used for SRM console boots? */
-	pld &= 0x00000000fffff9c4UL;
-
-	/*
-	 * 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 */
-			handle_irq(16 + i, 16 + i, regs);
-		}
-		*(vulp)PYXIS_INT_REQ = 1UL << i; mb();
-		tmp = *(vulp)PYXIS_INT_REQ;
-	}
-}
-
-static void 
 miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	int irq, ack;
+	int irq;
 
-	ack = irq = (vector - 0x800) >> 4;
+	irq = (vector - 0x800) >> 4;
 
 	/*
 	 * I really hate to do this, but the MIATA SRM console ignores the
@@ -106,34 +52,36 @@
 	 * So, here's this grotty hack... :-(
 	 */
 	if (irq >= 16)
-		ack = irq = irq + 8;
+		irq = irq + 8;
 
-	handle_irq(irq, ack, regs);
+	handle_irq(irq, regs);
 }
 
 static void __init
 miata_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
-
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = miata_srm_device_interrupt;
 
-	/* Note invert on MASK bits.  */
-	*(vulp)PYXIS_INT_MASK =
-	  ~((long)alpha_irq_mask >> 16) & ~0x400000000000063bUL; mb();
 #if 0
 	/* These break on MiataGL so we'll try not to do it at all.  */
 	*(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb();	/* ISA/NMI HI */
 	*(vulp)PYXIS_RT_COUNT = 0UL; mb();		/* clear count */
 #endif
-	/* Clear upper timer.  */
-	*(vulp)PYXIS_INT_REQ  = 0x4000000000000180UL; mb();
 
-	enable_irq(16 + 2);	/* enable HALT switch - SRM only? */
-	enable_irq(16 + 6);     /* enable timer */
-	enable_irq(16 + 7);     /* enable ISA PIC cascade */
-	enable_irq(2);		/* enable cascade */
+	init_i8259a_irqs();
+	init_rtc_irq();
+
+	/* Not interested in the bogus interrupts (3,10), Fan Fault (0),
+           NMI (1), or EIDE (9).
+
+	   We also disable the risers (4,5), since we don't know how to
+	   route the interrupts behind the bridge.  */
+	init_pyxis_irqs(0x63b0000);
+
+	common_init_isa_dma();
+	setup_irq(16+2, &halt_switch_irqaction);	/* SRM only? */
+	setup_irq(16+6, &timer_cascade_irqaction);
 }
 
 
@@ -300,14 +248,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		48,
-	irq_probe_mask:		_PROBE_MASK(48),
-	update_irq_hw:		miata_update_irq_hw,
-	ack_irq:		common_ack_irq,
-	device_interrupt:	miata_device_interrupt,
+	device_interrupt:	pyxis_device_interrupt,
 
 	init_arch:		pyxis_init_arch,
 	init_irq:		miata_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		miata_init_pci,
 	kill_arch:		miata_kill_arch,
 	pci_map_irq:		miata_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_mikasa.c linux/arch/alpha/kernel/sys_mikasa.c
--- v2.3.46/linux/arch/alpha/kernel/sys_mikasa.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_mikasa.c	Sun Feb 20 08:13:56 2000
@@ -28,21 +28,49 @@
 #include <asm/core_cia.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
-static void
-mikasa_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+
+/* Note mask bit is true for ENABLED irqs.  */
+static int cached_irq_mask;
+
+static inline void
+mikasa_update_irq_hw(int mask)
+{
+	outw(mask, 0x536);
+}
+
+static inline void
+mikasa_enable_irq(unsigned int irq)
+{
+	mikasa_update_irq_hw(cached_irq_mask |= 1 << (irq - 16));
+}
+
+static inline void
+mikasa_disable_irq(unsigned int irq)
 {
-	if (irq >= 16)
-		outw(~(mask >> 16), 0x536); /* note invert */
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);
-	else
-		outb(mask, 0x21);
+	mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16)));
 }
 
+static unsigned int
+mikasa_startup_irq(unsigned int irq)
+{
+	mikasa_enable_irq(irq);
+	return 0;
+}
+
+static struct hw_interrupt_type mikasa_irq_type = {
+	typename:	"MIKASA",
+	startup:	mikasa_startup_irq,
+	shutdown:	mikasa_disable_irq,
+	enable:		mikasa_enable_irq,
+	disable:	mikasa_disable_irq,
+	ack:		mikasa_disable_irq,
+	end:		mikasa_enable_irq,
+};
+
 static void 
 mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
@@ -50,9 +78,9 @@
 	unsigned int i;
 
 	/* Read the interrupt summary registers */
-	pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
-		(((unsigned long) inb(0xa0))  <<  8) |
-		((unsigned long) inb(0x20));
+	pld = (((~inw(0x534) & 0x0000ffffUL) << 16)
+	       | (((unsigned long) inb(0xa0)) << 8)
+	       | inb(0x20));
 
 	/*
 	 * Now for every possible bit set, work through them and call
@@ -64,7 +92,7 @@
 		if (i < 16) {
 			isa_device_interrupt(vector, regs);
 		} else {
-			handle_irq(i, i, regs);
+			handle_irq(i, regs);
 		}
 	}
 }
@@ -72,13 +100,21 @@
 static void __init
 mikasa_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	long i;
 
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = srm_device_interrupt;
 
-	outw(~(alpha_irq_mask >> 16), 0x536);	/* note invert */
-	enable_irq(2);				/* enable cascade */
+	mikasa_update_irq_hw(0);
+
+	for (i = 16; i < 32; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &mikasa_irq_type;
+	}
+
+	init_i8259a_irqs();
+	init_rtc_irq();
+	common_init_isa_dma();
 }
 
 
@@ -185,14 +221,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		32,
-	irq_probe_mask:		_PROBE_MASK(32),
-	update_irq_hw:		mikasa_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	mikasa_device_interrupt,
 
 	init_arch:		apecs_init_arch,
 	init_irq:		mikasa_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		mikasa_map_irq,
@@ -214,14 +247,11 @@
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		32,
-	irq_probe_mask:		_PROBE_MASK(32),
-	update_irq_hw:		mikasa_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	mikasa_device_interrupt,
 
 	init_arch:		cia_init_arch,
 	init_irq:		mikasa_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	pci_map_irq:		mikasa_map_irq,
 	pci_swizzle:		common_swizzle,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_nautilus.c linux/arch/alpha/kernel/sys_nautilus.c
--- v2.3.46/linux/arch/alpha/kernel/sys_nautilus.c	Wed Dec 15 10:43:16 1999
+++ linux/arch/alpha/kernel/sys_nautilus.c	Sun Feb 20 08:13:56 2000
@@ -45,34 +45,17 @@
 #include <asm/hwrpb.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
-#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index)
-
-static void
-nautilus_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
-	/* The timer is connected to PIC interrupt line also on Nautilus.
-	   The timer interrupt handler enables the PIC line, so in order
-	   not to get multiple timer interrupt sources, we mask it out
-	   at all times.  */
-
-	mask |= 0x100;
-	if (irq >= 8)
-		outb(mask >> 8, 0xA1);
-	else
-		outb(mask, 0x21);
-}
 
 static void __init
 nautilus_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
-
-	enable_irq(2);			/* enable cascade */
-	disable_irq(8);
+	init_i8259a_irqs();
+	init_rtc_irq();
+	common_init_isa_dma();
 }
 
 static int __init
@@ -534,14 +517,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		16,
-	irq_probe_mask:		(_PROBE_MASK(16) & ~0x101UL),
-	update_irq_hw:		nautilus_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	isa_device_interrupt,
 
 	init_arch:		irongate_init_arch,
 	init_irq:		nautilus_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		nautilus_kill_arch,
 	pci_map_irq:		nautilus_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_noritake.c linux/arch/alpha/kernel/sys_noritake.c
--- v2.3.46/linux/arch/alpha/kernel/sys_noritake.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_noritake.c	Sun Feb 20 08:13:56 2000
@@ -29,25 +29,51 @@
 #include <asm/core_cia.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
+/* Note mask bit is true for ENABLED irqs.  */
+static int cached_irq_mask;
 
-static void 
-noritake_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+static inline void
+noritake_update_irq_hw(int irq, int mask)
 {
-	if (irq <= 15)
-		if (irq <= 7)
-			outb(mask, 0x21);	/* ISA PIC1 */
-		else
-			outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else if (irq <= 31)
-		outw(~(mask >> 16), 0x54a);
-	else
-		outw(~(mask >> 32), 0x54c);
+	int port = 0x54a;
+	if (irq >= 16) mask >>= 16;
+	if (irq >= 16) port = 0x54c;
+	outw(mask, port);
+}
+
+static inline void
+noritake_enable_irq(unsigned int irq)
+{
+	noritake_update_irq_hw(irq, cached_irq_mask |= 1 << (irq - 16));
+}
+
+static inline void
+noritake_disable_irq(unsigned int irq)
+{
+	noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16)));
 }
 
+static unsigned int
+noritake_startup_irq(unsigned int irq)
+{
+	noritake_enable_irq(irq);
+	return 0;
+}
+
+static struct hw_interrupt_type noritake_irq_type = {
+	typename:	"NORITAKE",
+	startup:	noritake_startup_irq,
+	shutdown:	noritake_disable_irq,
+	enable:		noritake_enable_irq,
+	disable:	noritake_disable_irq,
+	ack:		noritake_disable_irq,
+	end:		noritake_enable_irq,
+};
+
 static void 
 noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
@@ -55,10 +81,10 @@
 	unsigned int i;
 
 	/* Read the interrupt summary registers of NORITAKE */
-	pld = ((unsigned long) inw(0x54c) << 32) |
-		((unsigned long) inw(0x54a) << 16) |
-		((unsigned long) inb(0xa0)  <<  8) |
-		((unsigned long) inb(0x20));
+	pld = (((unsigned long) inw(0x54c) << 32)
+	       | ((unsigned long) inw(0x54a) << 16)
+	       | ((unsigned long) inb(0xa0) << 8)
+	       | inb(0x20));
 
 	/*
 	 * Now for every possible bit set, work through them and call
@@ -70,7 +96,7 @@
 		if (i < 16) {
 			isa_device_interrupt(vector, regs);
 		} else {
-			handle_irq(i, i, regs);
+			handle_irq(i, regs);
 		}
 	}
 }
@@ -78,36 +104,44 @@
 static void 
 noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	int irq, ack;
+	int irq;
 
-	ack = irq = (vector - 0x800) >> 4;
+	irq = (vector - 0x800) >> 4;
 
 	/*
 	 * I really hate to do this, too, but the NORITAKE SRM console also
-	 *  reports PCI vectors *lower* than I expected from the bit numbers
-	 *  in the documentation.
+	 * reports PCI vectors *lower* than I expected from the bit numbers
+	 * in the documentation.
 	 * But I really don't want to change the fixup code for allocation
-	 *  of IRQs, nor the alpha_irq_mask maintenance stuff, both of which
-	 *  look nice and clean now.
+	 * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which
+	 * look nice and clean now.
 	 * So, here's this additional grotty hack... :-(
 	 */
 	if (irq >= 16)
-		ack = irq = irq + 1;
+		irq = irq + 1;
 
-	handle_irq(irq, ack, regs);
+	handle_irq(irq, regs);
 }
 
 static void __init
 noritake_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	long i;
 
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = noritake_srm_device_interrupt;
 
-	outw(~(alpha_irq_mask >> 16), 0x54a); /* note invert */
-	outw(~(alpha_irq_mask >> 32), 0x54c); /* note invert */
-	enable_irq(2);			/* enable cascade */
+	outw(0, 0x54a);
+	outw(0, 0x54c);
+
+	for (i = 16; i < 48; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &noritake_irq_type;
+	}
+
+	init_i8259a_irqs();
+	init_rtc_irq();
+	common_init_isa_dma();
 }
 
 
@@ -245,14 +279,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		48,
-	irq_probe_mask:		_PROBE_MASK(48),
-	update_irq_hw:		noritake_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	noritake_device_interrupt,
 
 	init_arch:		apecs_init_arch,
 	init_irq:		noritake_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		noritake_map_irq,
@@ -274,14 +305,11 @@
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		48,
-	irq_probe_mask:		_PROBE_MASK(48),
-	update_irq_hw:		noritake_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	noritake_device_interrupt,
 
 	init_arch:		cia_init_arch,
 	init_irq:		noritake_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	pci_map_irq:		noritake_map_irq,
 	pci_swizzle:		noritake_swizzle,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c
--- v2.3.46/linux/arch/alpha/kernel/sys_rawhide.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_rawhide.c	Sun Feb 20 08:13:56 2000
@@ -25,53 +25,77 @@
 #include <asm/core_mcpcia.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
+
+/*
+ * HACK ALERT! only the boot cpu is used for interrupts.
+ */
+
+
+/* Note mask bit is true for ENABLED irqs.  */
+
 static unsigned int hose_irq_masks[4] = {
 	0xff0000, 0xfe0000, 0xff0000, 0xff0000
 };
+static unsigned int cached_irq_masks[4];
 
+static inline void
+rawhide_update_irq_hw(int hose, int mask)
+{
+	*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)) = mask;
+	mb();
+	*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose));
+}
 
-/* Note that `mask' initially contains only the low 64 bits.  */
-
-static void
-rawhide_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+static void 
+rawhide_enable_irq(unsigned int irq)
 {
-	unsigned int saddle, hose, new_irq;
+	unsigned int mask, hose;
 
-	if (irq < 16) {
-		if (irq < 8)
-			outb(mask, 0x21);		/* ISA PIC1 */
-		else
-			outb(mask >> 8, 0xA1);		/* ISA PIC2 */
-		return;
-	}
+	irq -= 16;
+	hose = irq / 24;
+	irq -= hose * 24;
+
+	mask = cached_irq_masks[hose] |= 1 << irq;
+	mask |= hose_irq_masks[hose];
+	rawhide_update_irq_hw(hose, mask);
+}
 
-	saddle = (irq > 63);
-	mask = _alpha_irq_masks[saddle];
+static void 
+rawhide_disable_irq(unsigned int irq)
+{
+	unsigned int mask, hose;
 
-	if (saddle == 0) {
-		/* Saddle 0 includes EISA interrupts.  */
-		mask >>= 16;
-		new_irq = irq - 16;
-	} else {
-		new_irq = irq - 64;
-	}
+	irq -= 16;
+	hose = irq / 24;
+	irq -= hose * 24;
+
+	mask = cached_irq_masks[hose] &= ~(1 << irq);
+	mask |= hose_irq_masks[hose];
+	rawhide_update_irq_hw(hose, mask);
+}
 
-	hose = saddle << 1;
-	if (new_irq >= 24) {
-		mask >>= 24;
-		hose += 1;
-	}
 
-	*(vuip)MCPCIA_INT_MASK0(hose) =
-		(~mask & 0x00ffffff) | hose_irq_masks[hose];
-	mb();
-	*(vuip)MCPCIA_INT_MASK0(hose);
+static unsigned int
+rawhide_startup_irq(unsigned int irq)
+{
+	rawhide_enable_irq(irq);
+	return 0;
 }
 
+static struct hw_interrupt_type rawhide_irq_type = {
+	typename:	"RAWHIDE",
+	startup:	rawhide_startup_irq,
+	shutdown:	rawhide_disable_irq,
+	enable:		rawhide_enable_irq,
+	disable:	rawhide_disable_irq,
+	ack:		rawhide_disable_irq,
+	end:		rawhide_enable_irq,
+};
+
 static void 
 rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
@@ -97,28 +121,30 @@
 	/* Adjust by which hose it is from.  */
 	irq -= ((irq + 16) >> 2) & 0x38;
 
-	handle_irq(irq, irq, regs);
+	handle_irq(irq, regs);
 }
 
 static void __init
 rawhide_init_irq(void)
 {
 	struct pci_controler *hose;
+	long i;
 
 	mcpcia_init_hoses();
 
-	STANDARD_INIT_IRQ_PROLOG;
-
-	/* HACK ALERT! Routing is only to CPU #0.  */
 	for (hose = hose_head; hose; hose = hose->next) {
 		int h = hose->index;
+		rawhide_update_irq_hw(h, hose_irq_masks[h]);
+	}
 
-		*(vuip)MCPCIA_INT_MASK0(h) = hose_irq_masks[h];
-		mb();
-		*(vuip)MCPCIA_INT_MASK0(h);
+	for (i = 16; i < 128; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &rawhide_irq_type;
 	}
 
-	enable_irq(2);
+	init_i8259a_irqs();
+	init_rtc_irq();
+	common_init_isa_dma();
 }
 
 /*
@@ -191,14 +217,11 @@
 	min_mem_address:	MCPCIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		128,
-	irq_probe_mask:		_PROBE_MASK(128),
-	update_irq_hw:		rawhide_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	rawhide_srm_device_interrupt,
 
 	init_arch:		mcpcia_init_arch,
 	init_irq:		rawhide_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		rawhide_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c
--- v2.3.46/linux/arch/alpha/kernel/sys_ruffian.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_ruffian.c	Sun Feb 20 08:13:56 2000
@@ -26,117 +26,17 @@
 #include <asm/core_pyxis.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
-static void
-ruffian_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
-	if (irq >= 16) {
-		/* Note inverted sense of mask bits: */
-		/* Make CERTAIN none of the bogus ints get enabled... */
-		*(vulp)PYXIS_INT_MASK =
-			~((long)mask >> 16) & 0x00000000ffffffbfUL;
-		mb();
-		/* ... and read it back to make sure it got written.  */
-		*(vulp)PYXIS_INT_MASK;
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
-}
-
-static void
-ruffian_ack_irq(unsigned long irq)
-{
-	if (irq < 16) {
-		/* Ack PYXIS ISA interrupt.  */
-		*(vulp)PYXIS_INT_REQ = 1L << 7; mb();
-		/* ... and read it back to make sure it got written.  */
-		*(vulp)PYXIS_INT_REQ;
-		if (irq > 7) {
-			outb(0x20, 0xa0);
-		}
-		outb(0x20, 0x20);
-	} else {
-		/* Ack PYXIS PCI interrupt.  */
-		*(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); mb();
-		/* ... and read it back to make sure it got written.  */
-		*(vulp)PYXIS_INT_REQ;
-	}
-}
-
-static void
-ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs)
-{
-	unsigned long pld;
-	unsigned int i;
-
-	/* Read the interrupt summary register of PYXIS */
-	pld = *(vulp)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) { /* if ISA int */
-			/* Ruffian does not have the RTC connected to 
-			   the CPU timer interrupt.  Instead, it uses the
-			   PIT connected to IRQ 0.  So we must detect that
-			   and route that specifically to where we expected
-			   to find the timer interrupt come in.  */
-
-			/* Copy this code from isa_device_interrupt because
-			   we need to hook into int 0 for the timer.  I
-			   refuse to soil device_interrupt with ifdefs.  */
-
-			/* Generate a PCI interrupt acknowledge cycle.
-			   The PIC will respond with the interrupt
-			   vector of the highest priority interrupt
-			   that is pending.  The PALcode sets up the
-			   interrupts vectors such that irq level L
-			   generates vector L.  */
-
-			unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff;
-			if (j == 7 && !(inb(0x20) & 0x80)) {
-				/* It's only a passive release... */
-			} else if (j == 0) {
-			  	handle_irq(TIMER_IRQ, -1, regs);
-				ruffian_ack_irq(0);
-			} else {
-				handle_irq(j, j, regs);
-			}
-		} else { /* if not an ISA int */
-			handle_irq(16 + i, 16 + i, regs);
-		}
-
-		*(vulp)PYXIS_INT_REQ = 1UL << i; mb();
-		*(vulp)PYXIS_INT_REQ; /* read to force the write */
-	}
-}
 
 static void __init
 ruffian_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
-
 	/* Invert 6&7 for i82371 */
 	*(vulp)PYXIS_INT_HILO  = 0x000000c0UL; mb();
 	*(vulp)PYXIS_INT_CNFG  = 0x00002064UL; mb();	 /* all clear */
-	*(vulp)PYXIS_INT_MASK  = 0x00000000UL; mb();
-	*(vulp)PYXIS_INT_REQ   = 0xffffffffUL; mb();
 
 	outb(0x11,0xA0);
 	outb(0x08,0xA1);
@@ -150,17 +50,54 @@
 	outb(0x01,0x21);
 	outb(0xFF,0x21);
 	
-	/* Send -INTA pulses to clear any pending interrupts ...*/
-	*(vuip) PYXIS_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 */
-	enable_irq(2);		/* enable 2nd PIC cascade */
+	init_i8259a_irqs();
+
+	/* Not interested in the bogus interrupts (0,3,4,6), 
+	   NMI (1), HALT (2), flash (5), or 21142 (8).  */
+	init_pyxis_irqs(0x17f0000);
+
+	common_init_isa_dma();
+}
+
+static void __init
+ruffian_init_rtc(struct irqaction *action)
+{
+	/* Ruffian does not have the RTC connected to the CPU timer
+	   interrupt.  Instead, it uses the PIT connected to IRQ 0.  */
+
+	/* Setup interval timer.  */
+	outb(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb(LATCH & 0xff, 0x40);	/* LSB */
+	outb(LATCH >> 8, 0x40);		/* MSB */
+
+	outb(0xb6, 0x43);		/* pit counter 2: speaker */
+	outb(0x31, 0x42);
+	outb(0x13, 0x42);
+
+	setup_irq(0, action);
+}
+
+static void
+ruffian_kill_arch (int mode)
+{
+#if 0
+	/* This only causes re-entry to ARCSBIOS */
+	/* Perhaps this works for other PYXIS as well?  */
+	*(vuip) PYXIS_RESET = 0x0000dead;
+	mb();
+#endif
+}
+
+static int __init
+ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	/* We don't know anything about the PCI routing, so leave
+	   the IRQ unchanged.  */
+	return dev->irq;
 }
 
 
@@ -203,34 +140,6 @@
 }
 #endif /* BUILDING_FOR_MILO */
 
-static void
-ruffian_init_pit (void)
-{
-	outb(0xb6, 0x43);       /* pit counter 2: speaker */
-	outb(0x31, 0x42);
-	outb(0x13, 0x42);
-}
-
-static void
-ruffian_kill_arch (int mode)
-{
-#if 0
-	/* This only causes re-entry to ARCSBIOS */
-	/* Perhaps this works for other PYXIS as well?  */
-	*(vuip) PYXIS_RESET = 0x0000dead;
-	mb();
-#endif
-}
-
-static int __init
-ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-	/* We don't know anything about the PCI routing, so leave
-	   the IRQ unchanged.  */
-	return dev->irq;
-}
-
-
 /*
  * The System Vector
  */
@@ -247,14 +156,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		48,
-	irq_probe_mask:		RUFFIAN_PROBE_MASK,
-	update_irq_hw:		ruffian_update_irq_hw,
-	ack_irq:		ruffian_ack_irq,
-	device_interrupt:	ruffian_device_interrupt,
+	device_interrupt:	pyxis_device_interrupt,
 
 	init_arch:		pyxis_init_arch,
 	init_irq:		ruffian_init_irq,
-	init_pit:		ruffian_init_pit,
+	init_rtc:		ruffian_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		ruffian_kill_arch,
 	pci_map_irq:		ruffian_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_rx164.c linux/arch/alpha/kernel/sys_rx164.c
--- v2.3.46/linux/arch/alpha/kernel/sys_rx164.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_rx164.c	Sun Feb 20 08:13:56 2000
@@ -26,121 +26,103 @@
 #include <asm/core_polaris.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
-static void
-rx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for ENABLED irqs.  */
+static unsigned long cached_irq_mask;
+
+/* Bus 0, Device 0.  Nothing else matters, since we invoke the
+   POLARIS routines directly.  */
+static struct pci_dev rx164_system;
+
+static inline void
+rx164_update_irq_hw(unsigned long mask)
 {
-	if (irq >= 16) {
-		unsigned int temp;
-		pcibios_write_config_dword(0, 0, 0x74, ~mask >> 16);
-		pcibios_read_config_dword(0, 0, 0x74, &temp);
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
+	unsigned int temp;
+	polaris_write_config_dword(&rx164_system, 0x74, mask);
+	polaris_read_config_dword(&rx164_system, 0x74, &temp);
 }
 
-#if 0
-static void
-rx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+static inline void
+rx164_enable_irq(unsigned int irq)
 {
-	if (irq >= 16) {
-		if (unmask_p)
-			cserve_ena(irq - 16);
-		else
-			cserve_dis(irq - 16);
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
+	rx164_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
 }
-#endif
 
 static void
-rx164_isa_device_interrupt(unsigned long vector, struct pt_regs * regs)
+rx164_disable_irq(unsigned int irq)
 {
-        unsigned long pic;
+	rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+}
 
-        /*
-         * It seems to me that the probability of two or more *device*
-         * interrupts occurring at almost exactly the same time is
-         * pretty low.  So why pay the price of checking for
-         * additional interrupts here if the common case can be
-         * handled so much easier?
-         */
-        /* 
-         *  The first read of the PIC gives you *all* interrupting lines.
-         *  Therefore, read the mask register and and out those lines
-         *  not enabled.  Note that some documentation has 21 and a1 
-         *  write only.  This is not true.
-         */
-        pic = inb(0x20) | (inb(0xA0) << 8);     /* read isr */
-        pic &= ~alpha_irq_mask;                 /* apply mask */
-        pic &= 0xFFFB;                          /* mask out cascade & hibits */
-
-        while (pic) {
-                int j = ffz(~pic);
-                pic &= pic - 1;
-                handle_irq(j, j, regs);
-        }
+static unsigned int
+rx164_startup_irq(unsigned int irq)
+{
+	rx164_enable_irq(irq);
+	return 0;
 }
 
+static struct hw_interrupt_type rx164_irq_type = {
+	typename:	"RX164",
+	startup:	rx164_startup_irq,
+	shutdown:	rx164_disable_irq,
+	enable:		rx164_enable_irq,
+	disable:	rx164_disable_irq,
+	ack:		rx164_disable_irq,
+	end:		rx164_enable_irq,
+};
+
 static void 
 rx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
+	unsigned int temp;
 	unsigned long pld;
-	int i;
-
-        /* Read the interrupt summary register.  On Polaris,
-         * this is the DIRR register in PCI config space (offset 0x84)
-         */
-        pld = 0;
-        pcibios_read_config_dword(0, 0, 0x84, (unsigned int *)&pld);
-
-#if 0
-        printk("PLD 0x%lx\n", pld);
-#endif
-
-        if (pld & 0xffffffff00000000UL)
-		pld &= 0x00000000ffffffffUL;
+	long i;
 
-        /*
-         * 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 == 20) {
-                        rx164_isa_device_interrupt(vector, regs);
-                } else {
-                        handle_irq(16+i, 16+i, regs);
-                }
-        }
+	/* Read the interrupt summary register.  On Polaris, this is
+	   the DIRR register in PCI config space (offset 0x84).  */
+	polaris_read_config_dword(&rx164_system, 0x84, &temp);
+	pld = temp;
+
+	/*
+	 * 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 == 20) {
+			isa_no_iack_sc_device_interrupt(vector, regs);
+		} else {
+			handle_irq(16+i, regs);
+		}
+	}
 }
 
-static void
+static void __init
 rx164_init_irq(void)
 {
-	unsigned int temp;
+	long i;
 
-        STANDARD_INIT_IRQ_PROLOG;
+	rx164_update_irq_hw(0);
+	for (i = 16; i < 40; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &rx164_irq_type;
+	}
 
-        pcibios_write_config_dword(0, 0, 0x74, (~alpha_irq_mask >> 16));
-        pcibios_read_config_dword(0, 0, 0x74, &temp);
+	init_i8259a_irqs();
+	init_rtc_irq();
+	common_init_isa_dma();
 
-        enable_irq(16 + 20);    /* enable ISA interrupts */
-	enable_irq(2);		/* enable cascade */
+	setup_irq(16+20, &isa_cascade_irqaction);
 }
 
 
-/* The RX164 changed its interrupt routing between pass1 and pass2...
+/*
+ * The RX164 changed its interrupt routing between pass1 and pass2...
  *
  * PASS1:
  *
@@ -176,29 +158,29 @@
 rx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
 #if 0
-        char irq_tab_pass1[6][5] = {
-          /*INT   INTA  INTB  INTC   INTD */
-          { 16+3, 16+3, 16+8, 16+13, 16+18},      /* IdSel 5,  slot 2 */
-          { 16+5, 16+5, 16+10, 16+15, 16+20},     /* IdSel 6,  slot 0 */
-          { 16+4, 16+4, 16+9, 16+14, 16+19},      /* IdSel 7,  slot 1 */
-          { -1,     -1,    -1,    -1,   -1},      /* IdSel 8, PCI/ISA bridge */
-          { 16+2, 16+2, 16+7, 16+12, 16+17},      /* IdSel 9,  slot 3 */
-          { 16+1, 16+1, 16+6, 16+11, 16+16},      /* IdSel 10, slot 4 */
-        };
+	static char irq_tab_pass1[6][5] __initlocaldata = {
+	  /*INT   INTA  INTB  INTC   INTD */
+	  { 16+3, 16+3, 16+8, 16+13, 16+18},      /* IdSel 5,  slot 2 */
+	  { 16+5, 16+5, 16+10, 16+15, 16+20},     /* IdSel 6,  slot 0 */
+	  { 16+4, 16+4, 16+9, 16+14, 16+19},      /* IdSel 7,  slot 1 */
+	  { -1,     -1,    -1,    -1,   -1},      /* IdSel 8, PCI/ISA bridge */
+	  { 16+2, 16+2, 16+7, 16+12, 16+17},      /* IdSel 9,  slot 3 */
+	  { 16+1, 16+1, 16+6, 16+11, 16+16},      /* IdSel 10, slot 4 */
+	};
 #else
-        char irq_tab[6][5] = {
-          /*INT   INTA  INTB  INTC   INTD */
-          { 16+0, 16+0, 16+6, 16+11, 16+16},      /* IdSel 5,  slot 0 */
-          { 16+1, 16+1, 16+7, 16+12, 16+17},      /* IdSel 6,  slot 1 */
-          { -1,     -1,    -1,    -1,   -1},      /* IdSel 7, PCI/ISA bridge */
-          { 16+2, 16+2, 16+8, 16+13, 16+18},      /* IdSel 8,  slot 2 */
-          { 16+3, 16+3, 16+9, 16+14, 16+19},      /* IdSel 9,  slot 3 */
-          { 16+4, 16+4, 16+10, 16+15, 16+5},      /* IdSel 10, PCI-PCI */
-        };
+	static char irq_tab[6][5] __initlocaldata = {
+	  /*INT   INTA  INTB  INTC   INTD */
+	  { 16+0, 16+0, 16+6, 16+11, 16+16},      /* IdSel 5,  slot 0 */
+	  { 16+1, 16+1, 16+7, 16+12, 16+17},      /* IdSel 6,  slot 1 */
+	  { -1,     -1,    -1,    -1,   -1},      /* IdSel 7, PCI/ISA bridge */
+	  { 16+2, 16+2, 16+8, 16+13, 16+18},      /* IdSel 8,  slot 2 */
+	  { 16+3, 16+3, 16+9, 16+14, 16+19},      /* IdSel 9,  slot 3 */
+	  { 16+4, 16+4, 16+10, 16+15, 16+5},      /* IdSel 10, PCI-PCI */
+	};
 #endif
 	const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5;
 
-        /* JRP - Need to figure out how to distinguish pass1 from pass2,
+	/* JRP - Need to figure out how to distinguish pass1 from pass2,
 	   and use the correct table.  */
 	return COMMON_TABLE_LOOKUP;
 }
@@ -220,14 +202,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
-	irq_probe_mask:		_PROBE_MASK(40),
-	update_irq_hw:		rx164_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	rx164_device_interrupt,
 
 	init_arch:		polaris_init_arch,
 	init_irq:		rx164_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		rx164_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_sable.c linux/arch/alpha/kernel/sys_sable.c
--- v2.3.46/linux/arch/alpha/kernel/sys_sable.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_sable.c	Sun Feb 20 08:13:56 2000
@@ -26,7 +26,7 @@
 #include <asm/core_t2.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
@@ -38,15 +38,43 @@
  *	 0-7  (char at 536)
  *	 8-15 (char at 53a)
  *	16-23 (char at 53c)
+ *
+ * Summary Registers (536/53a/53c):
+ *
+ * Bit      Meaning               Kernel IRQ
+ *------------------------------------------
+ * 0        PCI slot 0			34
+ * 1        NCR810 (builtin)		33
+ * 2        TULIP (builtin)		32
+ * 3        mouse			12
+ * 4        PCI slot 1			35
+ * 5        PCI slot 2			36
+ * 6        keyboard			1
+ * 7        floppy			6
+ * 8        COM2			3
+ * 9        parallel port		7
+ *10        EISA irq 3			-
+ *11        EISA irq 4			-
+ *12        EISA irq 5			5
+ *13        EISA irq 6			-
+ *14        EISA irq 7			-
+ *15        COM1			4
+ *16        EISA irq 9			9
+ *17        EISA irq 10			10
+ *18        EISA irq 11			11
+ *19        EISA irq 12			-
+ *20        EISA irq 13			-
+ *21        EISA irq 14			14
+ *22        NC				15
+ *23        IIC				-
  */
 
-/* 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 struct 
 {
 	char irq_to_mask[40];
 	char mask_to_irq[40];
+
+	/* Note mask bit is true for DISABLED irqs.  */
 	unsigned long shadow_mask;
 } sable_irq_swizzle = {
 	{
@@ -54,61 +82,103 @@
 		-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 */
+		 2,  1,  0,  4,  5, -1, -1, -1,	/* pseudo PCI */
 	},
 	{
 		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  */
+		 3,  7, -1, -1,  5, -1, -1,  4,	/* mask 8-15  */
+		 9, 10, 11, -1, -1, 14, 15, -1,	/* mask 16-23  */
 	},
-	0
+	-1
 };
 
+static inline void
+sable_update_irq_hw(unsigned long bit, unsigned long mask)
+{
+	int port = 0x536;
 
-static void 
-sable_update_irq_hw(unsigned long irq, unsigned long unused_mask, int unmask_p)
+	if (bit >= 16) {
+		port = 0x53d;
+		mask >>= 16;
+	} else if (bit >= 8) {
+		port = 0x53b;
+		mask >>= 8;
+	}
+
+	outb(mask, port);
+}
+
+static inline void
+sable_ack_irq_hw(unsigned long bit)
+{
+	int port, val1, val2;
+
+	if (bit >= 16) {
+		port = 0x53c;
+		val1 = 0xE0 | (bit - 16);
+		val2 = 0xE0 | 4;
+	} else if (bit >= 8) {
+		port = 0x53a;
+		val1 = 0xE0 | (bit - 8);
+		val2 = 0xE0 | 2;
+	} else {
+		port = 0x536;
+		val1 = 0xE0 | (bit - 0);
+		val2 = 0xE0 | 1;
+	}
+
+	outb(val1, port);	/* ack the slave */
+	outb(val2, 0x534);	/* ack the master */
+}
+
+static inline void
+sable_enable_irq(unsigned int irq)
+{
+	unsigned long bit, mask;
+
+	bit = sable_irq_swizzle.irq_to_mask[irq];
+	mask = sable_irq_swizzle.shadow_mask &= ~(1UL << bit);
+	sable_update_irq_hw(bit, mask);
+}
+
+static void
+sable_disable_irq(unsigned int irq)
 {
 	unsigned long bit, mask;
 
-	/* The "irq" argument is really the irq, but we need it to
-	   be the mask bit number.  Convert it now.  */
+	bit = sable_irq_swizzle.irq_to_mask[irq];
+	mask = sable_irq_swizzle.shadow_mask |= 1UL << bit;
+	sable_update_irq_hw(bit, mask);
+}
 
-	irq = sable_irq_swizzle.irq_to_mask[irq];
-	bit = 1UL << irq;
-	mask = sable_irq_swizzle.shadow_mask | bit;
-	if (unmask_p)
-		mask &= ~bit;
-	sable_irq_swizzle.shadow_mask = mask;
-
-	/* The "irq" argument is now really the mask bit number.  */
-	if (irq <= 7)
-		outb(mask, 0x537);
-	else if (irq <= 15)
-		outb(mask >> 8, 0x53b);
-	else
-		outb(mask >> 16, 0x53d);
+static unsigned int
+sable_startup_irq(unsigned int irq)
+{
+	sable_enable_irq(irq);
+	return 0;
 }
 
 static void
-sable_ack_irq(unsigned long irq)
+sable_mask_and_ack_irq(unsigned int irq)
 {
-	/* 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;
-	}
+	unsigned long bit, mask;
+
+	bit = sable_irq_swizzle.irq_to_mask[irq];
+	mask = sable_irq_swizzle.shadow_mask |= 1UL << bit;
+	sable_update_irq_hw(bit, mask);
+	sable_ack_irq_hw(bit);
 }
 
+static struct hw_interrupt_type sable_irq_type = {
+	typename:	"SABLE",
+	startup:	sable_startup_irq,
+	shutdown:	sable_disable_irq,
+	enable:		sable_enable_irq,
+	disable:	sable_disable_irq,
+	ack:		sable_mask_and_ack_irq,
+	end:		sable_enable_irq,
+};
+
 static void 
 sable_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
@@ -116,64 +186,36 @@
 	   to the interrupt mask bits, but we have to manage via more
 	   normal IRQs.  */
 
-	int irq, ack;
+	int bit, irq;
 
-	ack = irq = (vector - 0x800) >> 4;
-
-	irq = sable_irq_swizzle.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
-
-	handle_irq(irq, ack, regs);
+	bit = (vector - 0x800) >> 4;
+	irq = sable_irq_swizzle.mask_to_irq[bit];
+	handle_irq(irq, regs);
 }
 
 static void __init
 sable_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	long i;
 
-	outb(alpha_irq_mask      , 0x537);	/* slave 0 */
-	outb(alpha_irq_mask >>  8, 0x53b);	/* slave 1 */
-	outb(alpha_irq_mask >> 16, 0x53d);	/* slave 2 */
-	outb(0x44, 0x535);		/* enable cascades in master */
+	outb(-1, 0x537);	/* slave 0 */
+	outb(-1, 0x53b);	/* slave 1 */
+	outb(-1, 0x53d);	/* slave 2 */
+	outb(0x44, 0x535);	/* enable cascades in master */
+
+	for (i = 0; i < 40; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &sable_irq_type;
+	}
+	
+	init_rtc_irq();
+	common_init_isa_dma();
 }
 
 
 /*
  * PCI 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
@@ -239,14 +281,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
-	irq_probe_mask:		_PROBE_MASK(40),
-	update_irq_hw:		sable_update_irq_hw,
-	ack_irq:		sable_ack_irq,
 	device_interrupt:	sable_srm_device_interrupt,
 
 	init_arch:		t2_init_arch,
 	init_irq:		sable_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		sable_map_irq,
@@ -274,14 +313,11 @@
 	min_mem_address:	DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
-	irq_probe_mask:		_PROBE_MASK(40),
-	update_irq_hw:		sable_update_irq_hw,
-	ack_irq:		sable_ack_irq,
 	device_interrupt:	sable_srm_device_interrupt,
 
 	init_arch:		t2_init_arch,
 	init_irq:		sable_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		common_init_pci,
 	pci_map_irq:		sable_map_irq,
 	pci_swizzle:		common_swizzle,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c
--- v2.3.46/linux/arch/alpha/kernel/sys_sio.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/sys_sio.c	Sun Feb 20 08:13:56 2000
@@ -30,28 +30,20 @@
 #include <asm/core_lca.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
-static void
-sio_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
-	if (irq >= 8)
-		outb(mask >> 8, 0xA1);
-	else
-		outb(mask, 0x21);
-}
 
 static void __init
 sio_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
-
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = srm_device_interrupt;
-		
-	enable_irq(2);			/* enable cascade */
+
+	init_i8259a_irqs();
+	init_rtc_irq();
+	common_init_isa_dma();
 }
 
 static inline void __init
@@ -270,14 +262,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		16,
-	irq_probe_mask:		_PROBE_MASK(16),
-	update_irq_hw:		sio_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	isa_device_interrupt,
 
 	init_arch:		alphabook1_init_arch,
 	init_irq:		sio_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		alphabook1_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		noname_map_irq,
@@ -304,14 +293,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		16,
-	irq_probe_mask:		_PROBE_MASK(16),
-	update_irq_hw:		sio_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	isa_device_interrupt,
 
 	init_arch:		apecs_init_arch,
 	init_irq:		sio_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		noname_init_pci,
 	pci_map_irq:		noname_map_irq,
 	pci_swizzle:		common_swizzle,
@@ -336,14 +322,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		16,
-	irq_probe_mask:		_PROBE_MASK(16),
-	update_irq_hw:		sio_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	srm_device_interrupt,
 
 	init_arch:		lca_init_arch,
 	init_irq:		sio_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		noname_init_pci,
 	pci_map_irq:		noname_map_irq,
 	pci_swizzle:		common_swizzle,
@@ -377,14 +360,11 @@
 	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		16,
-	irq_probe_mask:		P2K_PROBE_MASK,
-	update_irq_hw:		sio_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	srm_device_interrupt,
 
 	init_arch:		lca_init_arch,
 	init_irq:		sio_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		noname_init_pci,
 	pci_map_irq:		p2k_map_irq,
 	pci_swizzle:		common_swizzle,
@@ -409,14 +389,11 @@
 	min_mem_address:	XL_DEFAULT_MEM_BASE,
 
 	nr_irqs:		16,
-	irq_probe_mask:		_PROBE_MASK(16),
-	update_irq_hw:		sio_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	isa_device_interrupt,
 
 	init_arch:		lca_init_arch,
 	init_irq:		sio_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		noname_init_pci,
 	pci_map_irq:		noname_map_irq,
 	pci_swizzle:		common_swizzle,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_sx164.c linux/arch/alpha/kernel/sys_sx164.c
--- v2.3.46/linux/arch/alpha/kernel/sys_sx164.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_sx164.c	Sun Feb 20 08:13:56 2000
@@ -26,81 +26,12 @@
 #include <asm/core_pyxis.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
-static void
-sx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
-	if (irq >= 16) {
-		/* Make CERTAIN none of the bogus ints get enabled */
-		*(vulp)PYXIS_INT_MASK =
-			~((long)mask >> 16) & ~0x000000000000003bUL;
-		mb();
-		/* ... and read it back to make sure it got written.  */
-		*(vulp)PYXIS_INT_MASK;
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
-}
-
-static void
-sx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
-	if (irq >= 16) {
-		if (unmask_p)
-			cserve_ena(irq - 16);
-		else
-			cserve_dis(irq - 16);
-	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
-}
-
-static void 
-sx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
-{
-	unsigned long pld, tmp;
-	unsigned int i;
-
-	/* Read the interrupt summary register of PYXIS */
-	pld = *(vulp)PYXIS_INT_REQ;
-
-	/*
-	 * 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)
-	 */
-	/* Maybe HALT should only be used for SRM console boots? */
-	pld &= 0x0000000000ffffc0UL;
-
-	/*
-	 * 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 */
-			handle_irq(16 + i, 16 + i, regs);
-		}
-		*(vulp)PYXIS_INT_REQ = 1UL << i; mb();
-		tmp = *(vulp)PYXIS_INT_REQ;
-	}
-}
-
-static void
+static void __init
 sx164_init_irq(void)
 {
 	outb(0, DMA1_RESET_REG);
@@ -108,20 +39,20 @@
 	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
 	outb(0, DMA2_MASK_REG);
 
-	if (alpha_using_srm) {
-		alpha_mv.update_irq_hw = sx164_srm_update_irq_hw;
+	if (alpha_using_srm)
 		alpha_mv.device_interrupt = srm_device_interrupt;
-	}
-	else {
-		/* Note invert on MASK bits. */
-		*(vulp)PYXIS_INT_MASK  = ~((long)alpha_irq_mask >> 16);
-		mb();
-		*(vulp)PYXIS_INT_MASK;
-	}
-
-	enable_irq(16 + 6);	/* enable timer */
-	enable_irq(16 + 7);	/* enable ISA PIC cascade */
-	enable_irq(2);		/* enable cascade */
+
+	init_i8259a_irqs();
+	init_rtc_irq();
+
+	/* Not interested in the bogus interrupts (0,3,4,5,40-47),
+	   NMI (1), or HALT (2).  */
+	if (alpha_using_srm)
+		init_srm_irqs(40, 0x3f0000);
+	else
+		init_pyxis_irqs(0xff00003f0000);
+
+	setup_irq(16+6, &timer_cascade_irqaction);
 }
 
 /*
@@ -160,7 +91,6 @@
  *   7  64 bit PCI option slot 1
  *   8  Cypress I/O
  *   9  32 bit PCI option slot 3
- * 
  */
 
 static int __init
@@ -201,15 +131,12 @@
 	min_io_address:		DEFAULT_IO_BASE,
 	min_mem_address:	DEFAULT_MEM_BASE,
 
-	nr_irqs:		40,
-	irq_probe_mask:		_PROBE_MASK(40),
-	update_irq_hw:		sx164_update_irq_hw,
-	ack_irq:		common_ack_irq,
-	device_interrupt:	sx164_device_interrupt,
+	nr_irqs:		48,
+	device_interrupt:	pyxis_device_interrupt,
 
 	init_arch:		pyxis_init_arch,
 	init_irq:		sx164_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		sx164_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		sx164_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_takara.c linux/arch/alpha/kernel/sys_takara.c
--- v2.3.46/linux/arch/alpha/kernel/sys_takara.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_takara.c	Sun Feb 20 08:13:56 2000
@@ -25,31 +25,57 @@
 #include <asm/core_cia.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
-static void 
-takara_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for DISABLED irqs.  */
+static unsigned long cached_irq_mask[2] = { -1, -1 };
+
+static inline void
+takara_update_irq_hw(unsigned long irq, unsigned long mask)
 {
-	unsigned int regaddr;
+	int regaddr;
 
-	if (irq <= 15) {
-		if (irq <= 7)
-			outb(mask, 0x21);	/* ISA PIC1 */
-		else
-			outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	} else {
-		if (irq > 63)
-			mask = _alpha_irq_masks[1] << 16;
-		else
-			mask = mask >> ((irq - 16) & 0x30);
-		regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
-		outl(mask & 0xffff0000UL, regaddr);
-	}
+	mask = (irq >= 64 ? mask << 16 : mask >> ((irq - 16) & 0x30));
+	regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+	outl(mask & 0xffff0000UL, regaddr);
+}
+
+static inline void
+takara_enable_irq(unsigned int irq)
+{
+	unsigned long mask;
+	mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
+	takara_update_irq_hw(irq, mask);
+}
+
+static void
+takara_disable_irq(unsigned int irq)
+{
+	unsigned long mask;
+	mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
+	takara_update_irq_hw(irq, mask);
 }
 
+static unsigned int
+takara_startup_irq(unsigned int irq)
+{
+	takara_enable_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type takara_irq_type = {
+	typename:	"TAKARA",
+	startup:	takara_startup_irq,
+	shutdown:	takara_disable_irq,
+	enable:		takara_enable_irq,
+	disable:	takara_disable_irq,
+	ack:		takara_disable_irq,
+	end:		takara_enable_irq,
+};
+
 static void
 takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
@@ -78,10 +104,10 @@
 		 * despatch an interrupt if it's set.
 		 */
 
-		if (intstatus & 8) handle_irq(16+3, 16+3, regs);
-		if (intstatus & 4) handle_irq(16+2, 16+2, regs);
-		if (intstatus & 2) handle_irq(16+1, 16+1, regs);
-		if (intstatus & 1) handle_irq(16+0, 16+0, regs);
+		if (intstatus & 8) handle_irq(16+3, regs);
+		if (intstatus & 4) handle_irq(16+2, regs);
+		if (intstatus & 2) handle_irq(16+1, regs);
+		if (intstatus & 1) handle_irq(16+0, regs);
 	} else {
 		isa_device_interrupt (vector, regs);
 	}
@@ -91,13 +117,16 @@
 takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq = (vector - 0x800) >> 4;
-	handle_irq(irq, irq, regs);
+	handle_irq(irq, regs);
 }
 
 static void __init
 takara_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	long i;
+
+	init_i8259a_irqs();
+	init_rtc_irq();
 
 	if (alpha_using_srm) {
 		alpha_mv.device_interrupt = takara_srm_device_interrupt;
@@ -113,9 +142,18 @@
 		outl(ctlreg, 0x500);
 	}
 
-	enable_irq(2);
+	for (i = 16; i < 128; i += 16)
+		takara_update_irq_hw(i, -1);
+
+	for (i = 16; i < 128; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &takara_irq_type;
+	}
+
+	common_init_isa_dma();
 }
 
+
 /*
  * The Takara has PCI devices 1, 2, and 3 configured to slots 20,
  * 19, and 18 respectively, in the default configuration. They can
@@ -235,14 +273,11 @@
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
 	nr_irqs:		128,
-	irq_probe_mask:		_PROBE_MASK(48),
-	update_irq_hw:		takara_update_irq_hw,
-	ack_irq:		common_ack_irq,
 	device_interrupt:	takara_device_interrupt,
 
 	init_arch:		cia_init_arch,
 	init_irq:		takara_init_irq,
-	init_pit:		common_init_pit,
+	init_rtc:		common_init_rtc,
 	init_pci:		takara_init_pci,
 	kill_arch:		NULL,
 	pci_map_irq:		takara_map_irq,
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.3.46/linux/arch/alpha/kernel/time.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/time.c	Sun Feb 20 08:13:56 2000
@@ -31,6 +31,8 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -40,7 +42,7 @@
 #include <linux/timex.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
 
 extern rwlock_t xtime_lock;
 extern volatile unsigned long lost_ticks;	/* kernel/sched.c */
@@ -88,13 +90,7 @@
 	__u32 now;
 	long nticks;
 
-#ifdef __SMP__
-	/* When SMP, do this for *all* CPUs, but only do the rest for
-           the boot CPU.  */
-	smp_percpu_timer_interrupt(regs);
-	if (smp_processor_id() != smp_boot_cpuid)
-		return;
-#else
+#ifndef __SMP__
 	/* Not SMP, do kernel PC profiling here.  */
 	if (!user_mode(regs))
 		alpha_do_profile(regs->pc);
@@ -167,55 +163,8 @@
 	  )*60 + sec; /* finally seconds */
 }
 
-/*
- * Initialize Programmable Interval Timers with standard values.  Some
- * drivers depend on them being initialized (e.g., joystick driver).
- */
-
-#ifdef CONFIG_RTC
-void
-rtc_init_pit(void)
-{
-	unsigned char control;
-
-	/* Turn off RTC interrupts before /dev/rtc is initialized */
-	control = CMOS_READ(RTC_CONTROL);
-	control &= ~(RTC_PIE | RTC_AIE | RTC_UIE);
-	CMOS_WRITE(control, RTC_CONTROL);
-	(void) CMOS_READ(RTC_INTR_FLAGS);
-
-	/* Setup interval timer.  */
-	outb(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
-	outb(LATCH & 0xff, 0x40);	/* LSB */
-	outb(LATCH >> 8, 0x40);		/* MSB */
-
-	outb(0xb6, 0x43);	/* pit counter 2: speaker */
-	outb(0x31, 0x42);
-	outb(0x13, 0x42);
-}
-
 void
-rtc_kill_pit(void)
-{
-	unsigned char control;
-
-	cli();
-
-	/* Reset periodic interrupt frequency.  */
-	CMOS_WRITE(0x26, RTC_FREQ_SELECT);
-
-	/* Turn on periodic interrupts.  */
-	control = CMOS_READ(RTC_CONTROL);
-	control |= RTC_PIE;
-	CMOS_WRITE(control, RTC_CONTROL);	
-	CMOS_READ(RTC_INTR_FLAGS);
-
-	sti();
-}
-#endif
-
-void
-common_init_pit (void)
+common_init_rtc(struct irqaction *action)
 {
 	unsigned char x;
 
@@ -243,12 +192,19 @@
 	outb(0xb6, 0x43);	/* pit counter 2: speaker */
 	outb(0x31, 0x42);
 	outb(0x13, 0x42);
+
+	setup_irq(RTC_IRQ, action);
 }
 
 void
 time_init(void)
 {
-	void (*irq_handler)(int, void *, struct pt_regs *);
+	static struct irqaction timer_irqaction = {
+		handler:	timer_interrupt,
+		flags:		SA_INTERRUPT,
+		name:		"timer",
+	};
+
 	unsigned int year, mon, day, hour, min, sec, cc1, cc2;
 	unsigned long cycle_freq, one_percent;
 	long diff;
@@ -336,10 +292,8 @@
 	state.last_rtc_update = 0;
 	state.partial_tick = 0L;
 
-	/* setup timer */ 
-	irq_handler = timer_interrupt;
-	if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL))
-		panic("Could not allocate timer IRQ!");
+	/* Startup the timer source. */
+	alpha_mv.init_rtc(&timer_irqaction);
 }
 
 /*
diff -u --recursive --new-file v2.3.46/linux/arch/alpha/lib/csum_ipv6_magic.S linux/arch/alpha/lib/csum_ipv6_magic.S
--- v2.3.46/linux/arch/alpha/lib/csum_ipv6_magic.S	Tue Feb  1 01:35:43 2000
+++ linux/arch/alpha/lib/csum_ipv6_magic.S	Thu Feb 17 09:18:46 2000
@@ -18,7 +18,7 @@
 
 	ldq	$0,0($16)	# e0    : load src & dst addr words
 	zapnot	$20,15,$20	# .. e1 : zero extend incoming csum
-	extqh	$18,7,$4	# e0    : byte swap len & proto while we wait
+	extqh	$18,1,$4	# e0    : byte swap len & proto while we wait
 	ldq	$1,8($16)	# .. e1 :
 
 	extbl	$18,1,$5	# e0	:
diff -u --recursive --new-file v2.3.46/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.3.46/linux/arch/arm/mm/init.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/arm/mm/init.c	Thu Feb 17 23:34:46 2000
@@ -163,7 +163,7 @@
 void __init paging_init(void)
 {
 	void *zero_page, *bad_page, *bad_table;
-	unsigned int zone_size[MAX_NR_ZONES];
+	unsigned long zone_size[MAX_NR_ZONES];
 	int i;
 
 #ifdef CONFIG_CPU_32
diff -u --recursive --new-file v2.3.46/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.3.46/linux/arch/arm/mm/proc-arm6,7.S	Sun Feb 13 19:29:03 2000
+++ linux/arch/arm/mm/proc-arm6,7.S	Thu Feb 17 23:34:46 2000
@@ -30,6 +30,8 @@
 ENTRY(cpu_arm7_flush_cache_entry)
 ENTRY(cpu_arm6_flush_icache_area)
 ENTRY(cpu_arm7_flush_icache_area)
+ENTRY(cpu_arm6_flush_icache_page)
+ENTRY(cpu_arm7_flush_icache_page)
 ENTRY(cpu_arm6_cache_wback_area)
 ENTRY(cpu_arm7_cache_wback_area)
 ENTRY(cpu_arm6_cache_purge_area)
@@ -465,6 +467,7 @@
 		.word	cpu_arm6_cache_purge_area
 		.word	cpu_arm6_flush_tlb_page
 		.word	cpu_arm6_do_idle
+		.word	cpu_arm6_flush_icache_page
 		.size	arm6_processor_functions, . - arm6_processor_functions
 
 /*
@@ -493,6 +496,7 @@
 		.word	cpu_arm7_cache_purge_area
 		.word	cpu_arm7_flush_tlb_page
 		.word	cpu_arm7_do_idle
+		.word	cpu_arm7_flush_icache_page
 		.size	arm7_processor_functions, . - arm7_processor_functions
 
 		.type	cpu_arm6_info, #object
diff -u --recursive --new-file v2.3.46/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.3.46/linux/arch/arm/mm/proc-sa110.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/arm/mm/proc-sa110.S	Thu Feb 17 23:34:46 2000
@@ -287,6 +287,12 @@
 		mcr	p15, 0, r0, c7, c5, 0		@ flush I cache
 		mov	pc, lr
 
+		.align	5
+ENTRY(cpu_sa110_flush_icache_page)
+ENTRY(cpu_sa1100_flush_icache_page)
+		mcr	p15, 0, r0, c7, c5, 0		@ flush I cache
+		mov	pc, lr
+
 /*
  * Function: sa110_data_abort ()
  * Params  : r0 = address of aborted instruction
@@ -504,6 +510,7 @@
 		.word	cpu_sa110_cache_purge_area
 		.word	cpu_sa110_flush_tlb_page
 		.word	cpu_sa110_do_idle
+		.word	cpu_sa110_flush_icache_page
 		.size	sa110_processor_functions, . - sa110_processor_functions
 
 		.type	cpu_sa110_info, #object
@@ -535,6 +542,7 @@
 		.word	cpu_sa1100_cache_purge_area
 		.word	cpu_sa1100_flush_tlb_page
 		.word	cpu_sa1100_do_idle
+		.word	cpu_sa1100_flush_icache_page
 		.size	sa1100_processor_functions, . - sa1100_processor_functions
 
 cpu_sa1100_info:
diff -u --recursive --new-file v2.3.46/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.3.46/linux/arch/i386/boot/setup.S	Thu Jan  6 12:57:47 2000
+++ linux/arch/i386/boot/setup.S	Sun Feb 20 20:37:09 2000
@@ -436,7 +436,7 @@
 	movw	$0xAA, (0x1ff)			# device present
 no_psmouse:
 
-#ifdef CONFIG_APM
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 # Then check for an APM BIOS...
 						# %ds points to the bootsector
 	movw	$0, 0x40			# version = 0 means no APM BIOS
@@ -455,7 +455,11 @@
 	xorw	%bx, %bx
 	int	$0x15				# ignore return code
 	movw	$0x05303, %ax			# 32 bit connect
-	xorw	%bx, %bx
+	xorl	%ebx, %ebx
+	xorw	%cx, %cx			# paranoia :-)
+	xorw	%dx, %dx			#   ...
+	xorl	%esi, %esi			#   ...
+	xorw	%di, %di			#   ...
 	int	$0x15
 	jc	no_32_apm_bios			# Ack, error. 
 
@@ -463,12 +467,13 @@
 	movl	%ebx, (68)			# BIOS entry point offset
 	movw	%cx,  (72)			# BIOS 16 bit code segment
 	movw	%dx,  (74)			# BIOS data segment
-	movl	%esi, (78)			# BIOS code segment length
+	movl	%esi, (78)			# BIOS code segment lengths
 	movw	%di,  (82)			# BIOS data segment length
 # Redo the installation check as the 32 bit connect
 # modifies the flags returned on some BIOSs
 	movw	$0x05300, %ax			# APM BIOS installation check
 	xorw	%bx, %bx
+	xorw	%cx, %cx			# paranoia
 	int	$0x15
 	jc	apm_disconnect			# error -> shouldn't happen
 
diff -u --recursive --new-file v2.3.46/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.46/linux/arch/i386/config.in	Wed Feb 16 17:03:51 2000
+++ linux/arch/i386/config.in	Sun Feb 20 20:37:09 2000
@@ -49,7 +49,7 @@
    define_bool CONFIG_X86_USE_3DNOW y
 fi
 
-if [ "$CONFIG_M686" = "y" -a "$CONFIG_PROC_FS" = "y" ]; then
+if [ "$CONFIG_PROC_FS" = "y" ]; then
    tristate '/proc/driver/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
 fi
 
@@ -148,7 +148,7 @@
    fi
 fi
 
-bool 'Advanced Power Management BIOS support' CONFIG_APM
+tristate 'Advanced Power Management BIOS support' CONFIG_APM
 if [ "$CONFIG_APM" != "n" ]; then
    bool '  Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
    bool '  Enable PM at boot time' CONFIG_APM_DO_ENABLE
@@ -158,7 +158,6 @@
    bool '  Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
    bool '  RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
    bool '  Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
-   bool '  Entry point offset fix (some Acer laptops)' CONFIG_APM_BAD_ENTRY_OFFSET
    bool '  Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
 fi
 
diff -u --recursive --new-file v2.3.46/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.46/linux/arch/i386/defconfig	Wed Feb 16 17:03:51 2000
+++ linux/arch/i386/defconfig	Sun Feb 20 20:46:42 2000
@@ -281,7 +281,7 @@
 # CONFIG_DE4X5 is not set
 # CONFIG_TULIP is not set
 # CONFIG_DGRS is not set
-CONFIG_EEXPRESS_PRO100=y
+CONFIG_EEPRO100=y
 # CONFIG_NE2K_PCI is not set
 # CONFIG_8139TOO is not set
 # CONFIG_SIS900 is not set
@@ -427,7 +427,7 @@
 #
 
 #
-# Filesystems
+# File systems
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
@@ -446,19 +446,17 @@
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.3.46/linux/arch/i386/kernel/apm.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/i386/kernel/apm.c	Sun Feb 20 20:37:09 2000
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  * APM BIOS driver for Linux
- * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
+ * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com)
  *
  * Initial development of this driver was funded by NEC Australia P/L
  *	and NEC Corporation
@@ -35,6 +35,8 @@
  * Jan 1999, Version 1.9
  * Oct 1999, Version 1.10
  * Nov 1999, Version 1.11
+ * Jan 2000, Version 1.12
+ * Feb 2000, Version 1.13
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
@@ -54,7 +56,7 @@
  *         The new replacment for it is, but Linux doesn't yet support this.
  *         Alan Cox Linux 2.1.55
  *    1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
- *    1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by 
+ *    1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
  *         Dean Gaudet <dgaudet@arctic.org>.
  *         C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
  *    1.5: Fix segment register reloading (in case of bad segments saved
@@ -110,6 +112,26 @@
  *         (reported by Panos Katsaloulis <teras@writeme.com>).
  *         Real mode power off patch (Walter Hofmann
  *         <Walter.Hofmann@physik.stud.uni-erlangen.de>).
+ *   1.12: Remove CONFIG_SMP as the compiler will optimize
+ *         the code away anyway (smp_num_cpus == 1 in UP)
+ *         noted by Artur Skawina <skawina@geocities.com>.
+ *         Make power off under SMP work again.
+ *         Fix thinko with initial engaging of BIOS.
+ *         Make sure power off only happens on CPU 0
+ *         (Paul "Rusty" Russell <rusty@linuxcare.com>).
+ *         Do error notification to user mode if BIOS calls fail.
+ *         Move entrypoint offset fix to ...boot/setup.S
+ *         where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>).
+ *         Remove smp-power-off. SMP users must now specify
+ *         "apm=power-off" on the kernel command line. Suggested
+ *         by Jim Avera <jima@hal.com>, modified by Alan Cox
+ *         <alan@lxorguk.ukuu.org.uk>.
+ *         Register the /proc/apm entry even on SMP so that
+ *         scripts that check for it before doing power off
+ *         work (Jim Avera <jima@hal.com>).
+ *   1.13: Changes for new pm_ interfaces (Andy Henroid
+ *         <andy_henroid@yahoo.com>).
+ *         Modularize the code.
  *
  * APM 1.1 Reference:
  *
@@ -145,13 +167,12 @@
 #include <linux/apm_bios.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/pm.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/desc.h>
 
-#include <linux/pm.h>
-
 extern unsigned long get_cmos_time(void);
 extern void machine_real_restart(unsigned char *, int);
 
@@ -172,10 +193,10 @@
  * See Documentation/Config.help for the configuration options.
  *
  * Various options can be changed at boot time as follows:
+ * (We allow underscores for compatibility with the modules code)
  *	apm=on/off			enable/disable APM
  *	    [no-]debug			log some debugging messages
- *	    [no-]power-off		power off on shutdown
- *	    [no-]smp-power-off		allow power off even for SMP
+ *	    [no-]power[-_]off		power off on shutdown
  */
 
 /* KNOWN PROBLEM MACHINES:
@@ -219,8 +240,8 @@
 
 /*
  * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
- * This patched by Chad Miller <cmiller@surfsouth.com>, orig code by David 
- * Chen <chen@ctpa04.mit.edu>
+ * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
+ * David Chen <chen@ctpa04.mit.edu>
  */
 #undef INIT_TIMER_AFTER_SUSPEND
 
@@ -237,7 +258,7 @@
 
 /*
  * If CONFIG_APM_IGNORE_SUSPEND_BOUNCE is defined then
- * ignore suspend events for this amount of time
+ * ignore suspend events for this amount of time after a resume
  */
 #define BOUNCE_INTERVAL		(3 * HZ)
 
@@ -248,14 +269,40 @@
 		__asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
 
 /*
+ * Maximum number of events stored
+ */
+#define APM_MAX_EVENTS		20
+
+/*
+ * The per-file APM data
+ */
+struct apm_user {
+	int		magic;
+	struct apm_user *	next;
+	int		suser: 1;
+	int		suspend_wait: 1;
+	int		suspend_result;
+	int		suspends_pending;
+	int		standbys_pending;
+	int		suspends_read;
+	int		standbys_read;
+	int		event_head;
+	int		event_tail;
+	apm_event_t	events[APM_MAX_EVENTS];
+};
+
+/*
+ * The magic number in apm_user
+ */
+#define APM_BIOS_MAGIC		0x4101
+
+/*
  * Local variables
  */
 static struct {
 	unsigned long	offset;
 	unsigned short	segment;
 }				apm_bios_entry;
-static int			apm_enabled = 0;
-static int			smp_hack = 0;
 #ifdef CONFIG_APM_CPU_IDLE
 static int			clock_slowed = 0;
 #endif
@@ -274,12 +321,19 @@
 #endif
 static int			debug = 0;
 static int			apm_disabled = 0;
-static int			power_off_enabled = 1;
+#ifdef CONFIG_SMP
+static int			power_off = 0;
+#else
+static int			power_off = 1;
+#endif
+static int			exit_kapmd = 0;
+static int			kapmd_running = 0;
 
 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
-static struct apm_bios_struct *	user_list = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+static struct apm_user *	user_list = NULL;
 
-static char			driver_version[] = "1.11";	/* no spaces */
+static char			driver_version[] = "1.12";	/* no spaces */
 
 static char *	apm_event_name[] = {
 	"system standby",
@@ -380,6 +434,10 @@
 	__save_flags(flags);
 	APM_DO_CLI;
 	APM_DO_SAVE_SEGS;
+	/*
+	 * N.B. We do NOT need a cld after the BIOS call
+	 * because we always save and restore the flags.
+	 */
 	__asm__ __volatile__(APM_DO_ZERO_SEGS
 		"pushl %%edi\n\t"
 		"pushl %%ebp\n\t"
@@ -413,10 +471,14 @@
 	{
 		int	cx, dx, si;
 
+		/*
+		 * N.B. We do NOT need a cld after the BIOS call
+		 * because we always save and restore the flags.
+		 */
 		__asm__ __volatile__(APM_DO_ZERO_SEGS
 			"pushl %%edi\n\t"
 			"pushl %%ebp\n\t"
-			"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry)"\n\t"
+			"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
 			"setc %%bl\n\t"
 			"popl %%ebp\n\t"
 			"popl %%edi\n\t"
@@ -499,6 +561,7 @@
 	}
 }
 
+#if 0
 extern int hlt_counter;
 
 /*
@@ -543,48 +606,63 @@
 	}
 }
 #endif
+#endif
+
+#ifdef CONFIG_SMP
+static int apm_magic(void * unused)
+{
+	while (1)
+		schedule();
+}
+#endif
 
 static void apm_power_off(void)
 {
+#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
+	unsigned char	po_bios_call[] = {
+		0xb8, 0x00, 0x10,	/* movw  $0x1000,ax  */
+		0x8e, 0xd0,		/* movw  ax,ss       */
+		0xbc, 0x00, 0xf0,	/* movw  $0xf000,sp  */
+		0xb8, 0x07, 0x53,	/* movw  $0x5307,ax  */
+		0xbb, 0x01, 0x00,	/* movw  $0x0001,bx  */
+		0xb9, 0x03, 0x00,	/* movw  $0x0003,cx  */
+		0xcd, 0x15		/* int   $0x15       */
+	};
+#endif
+
 	/*
-	 * smp_hack == 2 means that we would have enabled APM support
-	 * except there is more than one processor and so most of
-	 * the APM stuff is unsafe.  We will still try power down
-	 * because is is useful to some people and they know what
-	 * they are doing because they booted with the smp-power-off
-	 * kernel option.
+	 * This may be called on an SMP machine.
 	 */
-	if (apm_enabled || (smp_hack == 2)) {
+#ifdef CONFIG_SMP
+	/* Some bioses don't like being called from CPU != 0 */
+	while (cpu_number_map[smp_processor_id()] != 0) {
+		kernel_thread(apm_magic, NULL,
+			CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+		schedule();
+	}
+#endif
 #ifdef CONFIG_APM_REAL_MODE_POWER_OFF
-		unsigned char	po_bios_call[] = {
-			0xb8, 0x00, 0x10,	/* movw  $0x1000,ax  */
-			0x8e, 0xd0,		/* movw  ax,ss       */
-			0xbc, 0x00, 0xf0,	/* movw  $0xf000,sp  */
-			0xb8, 0x07, 0x53,	/* movw  $0x5307,ax  */
-			0xbb, 0x01, 0x00,	/* movw  $0x0001,bx  */
-			0xb9, 0x03, 0x00,	/* movw  $0x0003,cx  */
-			0xcd, 0x15		/* int   $0x15       */
-		};
-
-		machine_real_restart(po_bios_call, sizeof(po_bios_call));
+	machine_real_restart(po_bios_call, sizeof(po_bios_call));
 #else
-		(void) apm_set_power_state(APM_STATE_OFF);
+	(void) apm_set_power_state(APM_STATE_OFF);
 #endif
-	}
 }
 
-#ifdef CONFIG_APM_DO_ENABLE
-static int __init apm_enable_power_management(void)
+static int apm_enable_power_management(int enable)
 {
 	u32	eax;
 
+	if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED))
+		return APM_NOT_ENGAGED;
 	if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
-			1, &eax))
+			enable, &eax))
 		return (eax >> 8) & 0xff;
-	apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+	if (enable)
+		apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+	else
+		apm_bios_info.flags |= APM_BIOS_DISABLED;
 	return APM_SUCCESS;
 }
-#endif
 
 static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
 {
@@ -632,12 +710,21 @@
 }
 #endif
 
-static int __init apm_engage_power_management(u_short device)
+static int apm_engage_power_management(u_short device, int enable)
 {
 	u32	eax;
 
-	if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, 1, &eax))
+	if ((enable == 0) && (device == APM_DEVICE_ALL)
+	    && (apm_bios_info.flags & APM_BIOS_DISABLED))
+		return APM_DISABLED;
+	if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
 		return (eax >> 8) & 0xff;
+	if (device == APM_DEVICE_ALL) {
+		if (enable)
+			apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+		else
+			apm_bios_info.flags |= APM_BIOS_DISENGAGED;
+	}
 	return APM_SUCCESS;
 }
 
@@ -655,7 +742,6 @@
 }
 
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
-/* Called from console driver -- must make sure apm_enabled. */
 static int apm_console_blank(int blank)
 {
 	int	error;
@@ -664,9 +750,13 @@
 	state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
 	/* Blank the first display device */
 	error = set_power_state(0x100, state);
-	if (error != APM_SUCCESS)
+	if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
 		/* try to blank them all instead */
 		error = set_power_state(0x1ff, state);
+		if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
+			/* try to blank device one instead */
+			error = set_power_state(0x101, state);
+	}
 	if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
 		return 1;
 	apm_error("set display", error);
@@ -674,20 +764,20 @@
 }
 #endif
 
-static int queue_empty(struct apm_bios_struct * as)
+static int queue_empty(struct apm_user *as)
 {
 	return as->event_head == as->event_tail;
 }
 
-static apm_event_t get_queued_event(struct apm_bios_struct * as)
+static apm_event_t get_queued_event(struct apm_user *as)
 {
 	as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
 	return as->events[as->event_tail];
 }
 
-static void queue_event(apm_event_t event, struct apm_bios_struct *sender)
+static void queue_event(apm_event_t event, struct apm_user *sender)
 {
-	struct apm_bios_struct *	as;
+	struct apm_user *	as;
 
 	if (user_list == NULL)
 		return;
@@ -751,18 +841,11 @@
 #endif
 }
 
-static void suspend(void)
+static void reinit_timer(void)
 {
-	int		err;
 #ifdef INIT_TIMER_AFTER_SUSPEND
 	unsigned long	flags;
-#endif
 
-	get_time_diff();
-	err = apm_set_power_state(APM_STATE_SUSPEND);
-	if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
-		apm_error("suspend", err);
-#ifdef INIT_TIMER_AFTER_SUSPEND
 	save_flags(flags);
 	cli();
 	/* set the clock to 100 Hz */
@@ -774,7 +857,27 @@
 	udelay(10);
 	restore_flags(flags);
 #endif
+}
+
+static int suspend(void)
+{
+	int		err;
+	int		ret;
+	struct apm_user	*as;
+
+	get_time_diff();
+	err = apm_set_power_state(APM_STATE_SUSPEND);
+	reinit_timer();
 	set_time();
+	ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR);
+	if (!ret)
+		apm_error("suspend", err);
+	for (as = user_list; as != NULL; as = as->next) {
+		as->suspend_wait = 0;
+		as->suspend_result = (ret ? 0 : -EIO);
+	}
+	wake_up_interruptible(&apm_suspend_waitqueue);
+	return ret;
 }
 
 static void standby(void)
@@ -806,15 +909,14 @@
 	return 0;
 }
 
-static int send_event(apm_event_t event, apm_event_t undo,
-		       struct apm_bios_struct *sender)
+static int send_event(apm_event_t event, struct apm_user *sender)
 {
 	switch (event) {
 	case APM_SYS_SUSPEND:
 	case APM_CRITICAL_SUSPEND:
 	case APM_USER_SUSPEND:
 		/* map all suspends to ACPI D3 */
-		if (pm_send_request(PM_SUSPEND, (void*) 3)) {
+		if (pm_send_request(PM_SUSPEND, (void *)3)) {
 			if (apm_bios_info.version > 0x100)
 				apm_set_power_state(APM_STATE_REJECT);
 			return 0;
@@ -823,11 +925,7 @@
 	case APM_NORMAL_RESUME:
 	case APM_CRITICAL_RESUME:
 		/* map all resumes to ACPI D0 */
-		if (pm_send_request(PM_RESUME, 0)) {
-			if (apm_bios_info.version > 0x100)
-				apm_set_power_state(APM_STATE_REJECT);
-			return 0;
-		}
+		(void) pm_send_request(PM_RESUME, (void *)0);
 		break;
 	}
 
@@ -864,7 +962,7 @@
 			if (waiting_for_resume)
 				break;
 #endif
-			if (send_event(event, APM_STANDBY_RESUME, NULL)) {
+			if (send_event(event, NULL)) {
 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
 				waiting_for_resume = 1;
 #endif
@@ -888,12 +986,12 @@
 			if (waiting_for_resume)
 				break;
 #endif
-			if (send_event(event, APM_NORMAL_RESUME, NULL)) {
+			if (send_event(event, NULL)) {
 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
 				waiting_for_resume = 1;
 #endif
 				if (suspends_pending <= 0)
-					suspend();
+					(void) suspend();
 			}
 			break;
 
@@ -908,13 +1006,13 @@
 			ignore_bounce = 1;
 #endif
 			set_time();
-			send_event(event, 0, NULL);
+			send_event(event, NULL);
 			break;
 
 		case APM_CAPABILITY_CHANGE:
 		case APM_LOW_BATTERY:
 		case APM_POWER_STATUS_CHANGE:
-			send_event(event, 0, NULL);
+			send_event(event, NULL);
 			break;
 
 		case APM_UPDATE_TIME:
@@ -922,7 +1020,7 @@
 			break;
 
 		case APM_CRITICAL_SUSPEND:
-			suspend();
+			(void) suspend();
 			break;
 		}
 	}
@@ -930,18 +1028,18 @@
 
 static void apm_event_handler(void)
 {
-	static int	pending_count = 0;
+	static int	pending_count = 4;
 	int		err;
 
 	if ((standbys_pending > 0) || (suspends_pending > 0)) {
-		if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
+		if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) {
 			pending_count = 4;
 			err = apm_set_power_state(APM_STATE_BUSY);
 			if (err)
 				apm_error("busy", err);
 		}
 	} else
-		pending_count = 0;
+		pending_count = 4;
 	check_events();
 }
 
@@ -957,13 +1055,17 @@
 static void apm_mainloop(void)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	apm_enabled = 1;
+
+	if (smp_num_cpus > 1)
+		return;
 
 	add_wait_queue(&apm_waitqueue, &wait);
 	current->state = TASK_INTERRUPTIBLE;
 	for (;;) {
 		/* Nothing to do, just sleep for the timeout */
 		schedule_timeout(APM_CHECK_TIMEOUT);
+		if (exit_kapmd)
+			break;
 
 		/*
 		 * Ok, check all events, check for idle (and mark us sleeping
@@ -976,11 +1078,11 @@
 			continue;
 		if (apm_do_idle()) {
 			unsigned long start = jiffies;
-			do {
+			while (system_idle()) {
 				apm_do_idle();
 				if (jiffies - start > APM_CHECK_TIMEOUT)
 					break;
-			} while (system_idle());
+			}
 			apm_do_busy();
 			apm_event_handler();
 		}
@@ -988,7 +1090,7 @@
 	}
 }
 
-static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
+static int check_apm_user(struct apm_user *as, const char *func)
 {
 	if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
 		printk(KERN_ERR "apm: %s passed bad filp", func);
@@ -999,13 +1101,13 @@
 
 static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
 {
-	struct apm_bios_struct *	as;
+	struct apm_user *	as;
 	int			i;
 	apm_event_t		event;
 	DECLARE_WAITQUEUE(wait, current);
 
 	as = fp->private_data;
-	if (check_apm_bios_struct(as, "read"))
+	if (check_apm_user(as, "read"))
 		return -EIO;
 	if (count < sizeof(apm_event_t))
 		return -EINVAL;
@@ -1053,10 +1155,10 @@
 
 static unsigned int do_poll(struct file *fp, poll_table * wait)
 {
-	struct apm_bios_struct * as;
+	struct apm_user * as;
 
 	as = fp->private_data;
-	if (check_apm_bios_struct(as, "select"))
+	if (check_apm_user(as, "poll"))
 		return 0;
 	poll_wait(fp, &apm_waitqueue, wait);
 	if (!queue_empty(as))
@@ -1067,11 +1169,11 @@
 static int do_ioctl(struct inode * inode, struct file *filp,
 		    u_int cmd, u_long arg)
 {
-	struct apm_bios_struct *	as;
-	int				send_ok = 1;
+	struct apm_user *	as;
+	DECLARE_WAITQUEUE(wait, current);
 
 	as = filp->private_data;
-	if (check_apm_bios_struct(as, "ioctl"))
+	if (check_apm_user(as, "ioctl"))
 		return -EIO;
 	if (!as->suser)
 		return -EPERM;
@@ -1081,11 +1183,9 @@
 			as->standbys_read--;
 			as->standbys_pending--;
 			standbys_pending--;
-		}
-		else
-			send_ok = send_event(APM_USER_STANDBY,
-					     APM_STANDBY_RESUME, as);
-		if (send_ok && (standbys_pending <= 0))
+		} else if (!send_event(APM_USER_STANDBY, as))
+			return -EAGAIN;
+		if (standbys_pending <= 0)
 			standby();
 		break;
 	case APM_IOC_SUSPEND:
@@ -1093,12 +1193,25 @@
 			as->suspends_read--;
 			as->suspends_pending--;
 			suspends_pending--;
+		} else if (!send_event(APM_USER_SUSPEND, as))
+			return -EAGAIN;
+		if (suspends_pending <= 0) {
+			if (!suspend())
+				return -EIO;
+		} else {
+			as->suspend_wait = 1;
+			add_wait_queue(&apm_suspend_waitqueue, &wait);
+			while (1) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				if ((as->suspend_wait == 0)
+				    || signal_pending(current))
+					break;
+				schedule();
+			}
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&apm_suspend_waitqueue, &wait);
+			return as->suspend_result;
 		}
-		else
-			send_ok = send_event(APM_USER_SUSPEND,
-					     APM_NORMAL_RESUME, as);
-		if (send_ok && (suspends_pending <= 0))
-			suspend();
 		break;
 	default:
 		return -EINVAL;
@@ -1108,10 +1221,10 @@
 
 static int do_release(struct inode * inode, struct file * filp)
 {
-	struct apm_bios_struct *	as;
+	struct apm_user *	as;
 
 	as = filp->private_data;
-	if (check_apm_bios_struct(as, "release"))
+	if (check_apm_user(as, "release"))
 		return 0;
 	filp->private_data = NULL;
 	if (as->standbys_pending > 0) {
@@ -1122,12 +1235,12 @@
 	if (as->suspends_pending > 0) {
 		suspends_pending -= as->suspends_pending;
 		if (suspends_pending <= 0)
-			suspend();
+			(void) suspend();
 	}
 	if (user_list == as)
 		user_list = as->next;
 	else {
-		struct apm_bios_struct *	as1;
+		struct apm_user *	as1;
 
 		for (as1 = user_list;
 		     (as1 != NULL) && (as1->next != as);
@@ -1139,17 +1252,21 @@
 			as1->next = as->next;
 	}
 	kfree_s(as, sizeof(*as));
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static int do_open(struct inode * inode, struct file * filp)
 {
-	struct apm_bios_struct *	as;
+	struct apm_user *	as;
 
-	as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
+	MOD_INC_USE_COUNT;
+
+	as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
 	if (as == NULL) {
 		printk(KERN_ERR "apm: cannot allocate struct of size %d bytes",
 		       sizeof(*as));
+		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 	as->magic = APM_BIOS_MAGIC;
@@ -1184,11 +1301,10 @@
 	int             time_units     = -1;
 	char            *units         = "?";
 
-	if (!apm_enabled)
-		return 0;
 	p = buf;
 
-	if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
+	if ((smp_num_cpus == 1) &&
+	    !(error = apm_get_power_status(&bx, &cx, &dx))) {
 		ac_line_status = (bx >> 8) & 0xff;
 		battery_status = bx & 0xff;
 		if ((cx & 0xff) != 0xff)
@@ -1264,6 +1380,11 @@
 	char *		power_stat;
 	char *		bat_stat;
 
+	kapmd_running = 1;
+
+	exit_files(current);	/* daemonize doesn't do exit_files */
+	daemonize();
+
 	strcpy(current->comm, "kapmd");
 	sigfillset(&current->blocked);
 
@@ -1278,7 +1399,7 @@
 			apm_bios_info.version = 0x100;
 		}
 	}
-	if (debug) {
+	if (debug && (smp_num_cpus == 1)) {
 		printk(KERN_INFO "apm: Connection version %d.%d\n",
 			(apm_bios_info.version >> 8) & 0xff,
 			apm_bios_info.version & 0xff);
@@ -1328,32 +1449,51 @@
 		 * is booted with PM disabled but not in the docking station.
 		 * Unfortunate ...
 		 */
-		error = apm_enable_power_management();
+		error = apm_enable_power_management(1);
 		if (error) {
 			apm_error("enable power management", error);
 			return -1;
 		}
 	}
 #endif
-	if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0)
+	if ((apm_bios_info.flags & APM_BIOS_DISENGAGED)
 	    && (apm_bios_info.version > 0x0100)) {
-		if (apm_engage_power_management(0x0001) == APM_SUCCESS)
-			apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+		error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+		if (error) {
+			apm_error("engage power management", error);
+			return -1;
+		}
 	}
 
 	/* Install our power off handler.. */
-	if (power_off_enabled)
+	if (power_off)
 		pm_power_off = apm_power_off;
 #ifdef CONFIG_MAGIC_SYSRQ
 	sysrq_power_off = apm_power_off;
 #endif
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
-	console_blank_hook = apm_console_blank;
+	if (smp_num_cpus == 1)
+		console_blank_hook = apm_console_blank;
 #endif
 
 	pm_active = 1;
 
 	apm_mainloop();
+
+	pm_active = 0;
+
+#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
+	if (smp_num_cpus == 1)
+		console_blank_hook = NULL;
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+	sysrq_power_off = NULL;
+#endif
+	if (power_off)
+		pm_power_off = NULL;
+
+	kapmd_running = 0;
+
 	return 0;
 }
 
@@ -1371,10 +1511,9 @@
 			str += 3;
 		if (strncmp(str, "debug", 5) == 0)
 			debug = !invert;
-		if (strncmp(str, "power-off", 9) == 0)
-			power_off_enabled = !invert;
-		if (strncmp(str, "smp-power-off", 13) == 0)
-			smp_hack = !invert;
+		if ((strncmp(str, "power-off", 9) == 0) ||
+		    (strncmp(str, "power_off", 9) == 0))
+			power_off = !invert;
 		str = strchr(str, ',');
 		if (str != NULL)
 			str += strspn(str, ", \t");
@@ -1455,7 +1594,10 @@
 		printk(KERN_NOTICE "apm: disabled on user request.\n");
 		APM_INIT_ERROR_RETURN;
 	}
-
+	if ((smp_num_cpus > 1) && !power_off) {
+		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+		APM_INIT_ERROR_RETURN;
+	}
 	if (PM_IS_ACTIVE()) {
 		printk(KERN_NOTICE "apm: overridden by ACPI.\n");
 		APM_INIT_ERROR_RETURN;
@@ -1472,9 +1614,6 @@
 	_set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
 
 	apm_bios_entry.offset = apm_bios_info.offset;
-#ifdef CONFIG_APM_BAD_ENTRY_OFFSET
-	apm_bios_entry.offset &= 0xffff;
-#endif
 	apm_bios_entry.segment = APM_CS;
 	set_base(gdt[APM_CS >> 3],
 		 __va((unsigned long)apm_bios_info.cseg << 4));
@@ -1483,18 +1622,16 @@
 	set_base(gdt[APM_DS >> 3],
 		 __va((unsigned long)apm_bios_info.dseg << 4));
 #ifndef APM_RELAX_SEGMENTS
-	if (apm_bios_info.version == 0x100)
+	if (apm_bios_info.version == 0x100) {
 #endif
-	{
 		/* For ASUS motherboard, Award BIOS rev 110 (and others?) */
 		_set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
 		/* For some unknown machine. */
 		_set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
 		/* For the DEC Hinote Ultra CT475 (and others?) */
 		_set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
-	}
 #ifndef APM_RELAX_SEGMENTS
-	else {
+	} else {
 		_set_limit((char *)&gdt[APM_CS >> 3],
 			(apm_bios_info.cseg_len - 1) & 0xffff);
 		_set_limit((char *)&gdt[APM_CS_16 >> 3],
@@ -1504,21 +1641,36 @@
 	}
 #endif
 
-#ifdef CONFIG_SMP
+	create_proc_info_entry("apm", 0, NULL, apm_get_info);
+
+	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+
 	if (smp_num_cpus > 1) {
-		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
-		if (smp_hack)
-			smp_hack = 2;
+		printk(KERN_NOTICE
+		   "apm: disabled - APM is not SMP safe (power off active).\n");
 		APM_INIT_ERROR_RETURN;
 	}
-#endif
-
-	create_proc_info_entry("apm", 0, 0, apm_get_info);
 
 	misc_register(&apm_device);
 
-	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 	return 0;
 }
 
-__initcall(apm_init);
+static void __exit apm_exit(void)
+{
+	misc_deregister(&apm_device);
+	remove_proc_entry("apm", NULL);
+	exit_kapmd = 1;
+	while (kapmd_running)
+		schedule();
+}
+
+module_init(apm_init);
+module_exit(apm_exit);
+
+MODULE_AUTHOR("Stephen Rothwell");
+MODULE_DESCRIPTION("Advanced Power Management");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Enable debug mode");
+
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.3.46/linux/arch/i386/kernel/i386_ksyms.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/i386/kernel/i386_ksyms.c	Sun Feb 20 20:37:09 2000
@@ -10,6 +10,7 @@
 #include <linux/smp_lock.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
+#include <linux/apm_bios.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
@@ -20,6 +21,7 @@
 #include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/mmx.h>
+#include <asm/desc.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(elf_fpregset_t *);
@@ -34,6 +36,8 @@
 EXPORT_SYMBOL(drive_info);
 #endif
 
+extern unsigned long get_cmos_time(void);
+
 /* platform dependent support */
 EXPORT_SYMBOL(boot_cpu_data);
 EXPORT_SYMBOL(EISA_bus);
@@ -51,6 +55,9 @@
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(pm_idle);
 EXPORT_SYMBOL(pm_power_off);
+EXPORT_SYMBOL(get_cmos_time);
+EXPORT_SYMBOL(apm_bios_info);
+EXPORT_SYMBOL(gdt);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.46/linux/arch/i386/kernel/irq.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/i386/kernel/irq.c	Fri Feb 18 08:15:52 2000
@@ -713,6 +713,7 @@
 		if (!(status & IRQ_WAITING)) {
 			irq_desc[i].status = status & ~IRQ_AUTODETECT;
 			irq_desc[i].handler->shutdown(i);
+			continue;
 		}
 
 		if (i < 32)
diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c
--- v2.3.46/linux/arch/i386/kernel/microcode.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/i386/kernel/microcode.c	Fri Feb 18 15:11:13 2000
@@ -18,6 +18,8 @@
  *
  *	1.0	16 February 2000, Tigran Aivazian <tigran@sco.com>
  *		Initial release.
+ *	1.01	18 February 2000, Tigran Aivazian <tigran@sco.com>
+ *		Added read() support + cleanups.
  */
 
 #include <linux/init.h>
@@ -31,7 +33,7 @@
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-#define MICROCODE_VERSION 	"1.0"
+#define MICROCODE_VERSION 	"1.01"
 
 MODULE_DESCRIPTION("CPU (P6) microcode update driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>");
@@ -40,11 +42,12 @@
 /* VFS interface */
 static int microcode_open(struct inode *, struct file *);
 static int microcode_release(struct inode *, struct file *);
+static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
 static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *);
 
 
 /* internal helpers to do the work */
-static void do_microcode_update(void);
+static int do_microcode_update(void);
 static void do_update_one(void *);
 
 /*
@@ -56,8 +59,10 @@
 /* the actual array of microcode blocks, each 2048 bytes */
 static struct microcode * microcode = NULL;
 static unsigned int microcode_num = 0;
+static char *mc_applied = NULL; /* holds an array of applied microcode blocks */
 
 static struct file_operations microcode_fops = {
+	read:		microcode_read,
 	write:		microcode_write,
 	open:		microcode_open,
 	release:	microcode_release,
@@ -71,21 +76,32 @@
 
 static int __init microcode_init(void)
 {
-	/* write-only /proc/driver/microcode file, one day may become read-write.. */
-	proc_microcode = create_proc_entry("microcode", S_IWUSR, proc_root_driver);
+	int size;
+
+	proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver);
 	if (!proc_microcode) {
-		printk(KERN_ERR "microcode: can't create /proc/driver/microcode entry\n");
+		printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n");
 		return -ENOMEM;
 	}
 	proc_microcode->ops = &microcode_inops;
-	printk(KERN_ERR "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION);
+	size = smp_num_cpus * sizeof(struct microcode);
+	mc_applied = kmalloc(size, GFP_KERNEL);
+	if (!mc_applied) {
+		remove_proc_entry("microcode", proc_root_driver);
+		printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n");
+		return -ENOMEM;
+	}
+	memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed
+	                                update makes this obvious */
+	printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION);
 	return 0;
 }
 
 static void __exit microcode_exit(void)
 {
 	remove_proc_entry("microcode", proc_root_driver);
-	printk(KERN_ERR "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION);
+	kfree(mc_applied);
+	printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION);
 }
 
 module_init(microcode_init);
@@ -116,23 +132,46 @@
 	return 0;
 }
 
+/* a pointer to 'struct update_req' is passed to the IPI hanlder = do_update_one()
+ * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
+ * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
+ */
+struct update_req {
+	int err;
+	int slot;
+} update_req[NR_CPUS];
 
-static void do_microcode_update(void)
+static int do_microcode_update(void)
 {
-	if (smp_call_function(do_update_one, NULL, 1, 0) != 0)
+	int i, error = 0, err;
+	struct microcode *m;
+
+	if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0)
 		panic("do_microcode_update(): timed out waiting for other CPUs\n");
-	do_update_one(NULL);
+	do_update_one((void *)update_req);
+
+	for (i=0; i<smp_num_cpus; i++) {
+		err = update_req[i].err;
+		error += err;
+		if (!err) {
+			m = (struct microcode *)mc_applied + i;
+			memcpy(m, &microcode[update_req[i].slot], sizeof(struct microcode));
+		}
+	}
+	return error ? -EIO : 0;
 }
 
-static void do_update_one(void *unused)
+static void do_update_one(void *arg)
 {
+	struct update_req *req;
 	struct cpuinfo_x86 * c;
 	unsigned int pf = 0, val[2], rev, sig;
-	int i, id;
-
-	id = smp_processor_id();
-	c = cpu_data + id;
+	int i, cpu_num;
 
+	cpu_num = smp_processor_id();
+	c = cpu_data + cpu_num;
+	req = (struct update_req *)arg + cpu_num;
+	req->err = 1; /* be pessimistic */
 
 	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6)
 		return;
@@ -153,7 +192,7 @@
 			if (microcode[i].rev <= rev) {
 				printk(KERN_ERR 
 					"microcode: CPU%d not 'upgrading' to earlier revision"
-					" %d (current=%d)\n", id, microcode[i].rev, rev);
+					" %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
 			} else { 
 				int sum = 0;
 				struct microcode *m = &microcode[i];
@@ -163,29 +202,47 @@
 					sum += *sump;
 				if (sum != 0) {
 					printk(KERN_ERR "microcode: CPU%d aborting, "
-							"bad checksum\n", id);
+							"bad checksum\n", cpu_num);
 					break;
 				}
+
 				wrmsr(0x79, (unsigned int)(m->bits), 0);
 				__asm__ __volatile__ ("cpuid");
 				rdmsr(0x8B, val[0], val[1]);
+
+				req->err = 0;
+				req->slot = i;
 				printk(KERN_ERR "microcode: CPU%d microcode updated "
-						"from revision %d to %d\n", id, rev, val[1]);
+						"from revision %d to %d, date=%08x\n", 
+						cpu_num, rev, val[1], m->date);
 			}
 			break;
 		}
 }
 
+static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
+{
+	size_t fsize = smp_num_cpus * sizeof(struct microcode);
+
+	if (!proc_microcode->size || *ppos >= fsize)
+		return 0; /* EOF */
+	if (*ppos + len > fsize)
+		len = fsize - *ppos;
+	if (copy_to_user(buf, mc_applied + *ppos, len))
+		return -EFAULT;
+	*ppos += len;
+	return len;
+}
+
 static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
 {
+	ssize_t ret;
+
 	if (len % sizeof(struct microcode) != 0) {
 		printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", 
 			sizeof(struct microcode));
 		return -EINVAL;
-		return -EINVAL;
 	}
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
 	lock_kernel();
 	microcode_num = len/sizeof(struct microcode);
 	microcode = vmalloc(len);
@@ -198,8 +255,12 @@
 		unlock_kernel();
 		return -EFAULT;
 	}
-	do_microcode_update();
+	ret = do_microcode_update();
+	if (!ret) {
+		proc_microcode->size = smp_num_cpus * sizeof(struct microcode);
+		ret = (ssize_t)len;
+	}
 	vfree(microcode);
 	unlock_kernel();
-	return len;
+	return ret;
 }
diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.3.46/linux/arch/i386/kernel/mtrr.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/i386/kernel/mtrr.c	Sun Feb 20 20:23:20 2000
@@ -1,6 +1,6 @@
 /*  Generic MTRR (Memory Type Range Register) driver.
 
-    Copyright (C) 1997-1999  Richard Gooch
+    Copyright (C) 1997-2000  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -224,6 +224,10 @@
                success.
     19991008   Manfred Spraul <manfreds@colorfullife.com>
     	       replaced spin_lock_reschedule() with a normal semaphore.
+  v1.36
+    20000221   Richard Gooch <rgooch@atnf.csiro.au>
+               Compile fix if procfs and devfs not enabled.
+	       Formatting changes.
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -261,7 +265,7 @@
 #include <asm/hardirq.h>
 #include <linux/irq.h>
 
-#define MTRR_VERSION            "1.35 (19990512)"
+#define MTRR_VERSION            "1.36 (20000221)"
 
 #define TRUE  1
 #define FALSE 0
@@ -484,8 +488,9 @@
     unsigned long dummy, mask_lo, base_lo;
 
     rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
-    if ((mask_lo & 0x800) == 0) {
-	/* Invalid (i.e. free) range. */
+    if ( (mask_lo & 0x800) == 0 )
+    {
+	/*  Invalid (i.e. free) range  */
 	*base = 0;
 	*size = 0;
 	*type = 0;
@@ -541,22 +546,26 @@
       *size = 0;
 
     /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
-    if (reg < 7) {
-      switch (rcr) {
-	case  1: *type = MTRR_TYPE_UNCACHABLE; break;
-	case  8: *type = MTRR_TYPE_WRBACK;     break;
-	case  9: *type = MTRR_TYPE_WRCOMB;     break;
-	case 24:
-	default: *type = MTRR_TYPE_WRTHROUGH;  break;
-      }
-    } else {
-      switch (rcr) {
-	case  0: *type = MTRR_TYPE_UNCACHABLE; break;
-	case  8: *type = MTRR_TYPE_WRCOMB;     break;
-	case  9: *type = MTRR_TYPE_WRBACK;     break;
-	case 25:
-	default: *type = MTRR_TYPE_WRTHROUGH;  break;
-      }
+    if (reg < 7)
+    {
+	switch (rcr)
+	{
+	  case  1: *type = MTRR_TYPE_UNCACHABLE; break;
+	  case  8: *type = MTRR_TYPE_WRBACK;     break;
+	  case  9: *type = MTRR_TYPE_WRCOMB;     break;
+	  case 24:
+	  default: *type = MTRR_TYPE_WRTHROUGH;  break;
+	}
+    } else
+    {
+	switch (rcr)
+	{
+	  case  0: *type = MTRR_TYPE_UNCACHABLE; break;
+	  case  8: *type = MTRR_TYPE_WRCOMB;     break;
+	  case  9: *type = MTRR_TYPE_WRBACK;     break;
+	  case 25:
+	  default: *type = MTRR_TYPE_WRTHROUGH;  break;
+	}
     }
 }   /*  End Function cyrix_get_arr  */
 
@@ -657,20 +666,24 @@
     size &= 0x7fff; /* make sure arr_size <= 14 */
     for(arr_size = 0; size; arr_size++, size >>= 1);
 
-    if (reg<7) {
-      switch (type) {
-	case MTRR_TYPE_UNCACHABLE:	arr_type =  1; break;
-	case MTRR_TYPE_WRCOMB:		arr_type =  9; break;
-	case MTRR_TYPE_WRTHROUGH:	arr_type = 24; break;
-	default:			arr_type =  8; break;
-      }
-    } else {
-      switch (type) {
-	case MTRR_TYPE_UNCACHABLE:	arr_type =  0; break;
-	case MTRR_TYPE_WRCOMB:		arr_type =  8; break;
-	case MTRR_TYPE_WRTHROUGH:	arr_type = 25; break;
-	default:			arr_type =  9; break;
-      }
+    if (reg<7)
+    {
+	switch (type) {
+	  case MTRR_TYPE_UNCACHABLE:	arr_type =  1; break;
+	  case MTRR_TYPE_WRCOMB:		arr_type =  9; break;
+	  case MTRR_TYPE_WRTHROUGH:	arr_type = 24; break;
+	  default:			arr_type =  8; break;
+	}
+    }
+    else
+    {
+	switch (type)
+	{
+	  case MTRR_TYPE_UNCACHABLE:	arr_type =  0; break;
+	  case MTRR_TYPE_WRCOMB:		arr_type =  8; break;
+	  case MTRR_TYPE_WRTHROUGH:	arr_type = 25; break;
+	  default:			arr_type =  9; break;
+	}
     }
 
     if (do_safe) set_mtrr_prepare (&ctxt);
@@ -783,16 +796,18 @@
     int changed = FALSE;
 
     rdmsr(MTRRphysBase_MSR(index), lo, hi);
-    if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
-	|| (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
-	wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+    if ( (vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
+	 || (vr->base_hi & 0xfUL) != (hi & 0xfUL) )
+    {
+	wrmsr (MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
 	changed = TRUE;
     }
 
-    rdmsr(MTRRphysMask_MSR(index), lo, hi);
+    rdmsr (MTRRphysMask_MSR(index), lo, hi);
 
-    if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
-	|| (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
+    if ( (vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
+	 || (vr->mask_hi & 0xfUL) != (hi & 0xfUL) )
+    {
 	wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
 	changed = TRUE;
     }
@@ -820,22 +835,27 @@
     unsigned long lo, hi;
 
     rdmsr(MTRRfix64K_00000_MSR, lo, hi);
-    if (p[0] != lo || p[1] != hi) {
-	wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+    if (p[0] != lo || p[1] != hi)
+    {
+	wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]);
 	changed = TRUE;
     }
 
-    for (i = 0; i < 2; i++) {
-	rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
-	if (p[2 + i*2] != lo || p[3 + i*2] != hi) {
-	    wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
+    for (i = 0; i < 2; i++)
+    {
+	rdmsr (MTRRfix16K_80000_MSR + i, lo, hi);
+	if (p[2 + i*2] != lo || p[3 + i*2] != hi)
+	{
+	    wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
 	    changed = TRUE;
 	}
     }
 
-    for (i = 0; i < 8; i++) {
-	rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
-	if (p[6 + i*2] != lo || p[7 + i*2] != hi) {
+    for (i = 0; i < 8; i++)
+    {
+	rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi);
+	if (p[6 + i*2] != lo || p[7 + i*2] != hi)
+	{
 	    wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
 	    changed = TRUE;
 	}
@@ -903,8 +923,8 @@
 	change_mask |= MTRR_CHANGE_MASK_FIXED;
     /*  Set_mtrr_restore restores the old value of MTRRdefType,
 	so to set it we fiddle with the saved value  */
-    if ((ctxt->deftype_lo & 0xff) != state->def_type
-	|| ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled)
+    if ( (ctxt->deftype_lo & 0xff) != state->def_type
+	 || ( (ctxt->deftype_lo & 0xc00) >> 10 ) != state->enabled)
     {
 	ctxt->deftype_lo |= (state->def_type | state->enabled << 10);
 	change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
@@ -1057,11 +1077,14 @@
     unsigned long lbase, lsize;
 
     /* If we are to set up a region >32M then look at ARR7 immediately */
-    if (size > 0x2000000UL) {
+    if (size > 0x2000000UL)
+    {
 	cyrix_get_arr (7, &lbase, &lsize, &ltype);
 	if (lsize < 1) return 7;
-    /* else try ARR0-ARR6 first */
-    } else {
+	/*  Else try ARR0-ARR6 first  */
+    }
+    else
+    {
 	for (i = 0; i < 7; i++)
 	{
 	    cyrix_get_arr (i, &lbase, &lsize, &ltype);
@@ -1099,29 +1122,32 @@
     switch (boot_cpu_data.x86_vendor)
     {
       case X86_VENDOR_AMD:
-	if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */
-	  /* Apply the K6 block alignment and size rules
+	if (boot_cpu_data.x86 < 6)
+	{   /* pre-Athlon CPUs */
+	    /* Apply the K6 block alignment and size rules
 	     In order
 		o Uncached or gathering only
 		o 128K or bigger block
 		o Power of 2 block
 		o base suitably aligned to the power
 	    */
-	  if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
-	      (size & ~(size-1))-size || (base & (size-1)))
-	      return -EINVAL;
+	    if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+		 (size & ~(size-1))-size || ( base & (size-1) ) )
+		return -EINVAL;
 	  break;
-	} /* else fall through */
+	}
+	/*  Else fall through  */
       case X86_VENDOR_INTEL:
-	/*  Double check for Intel, we may run on Athlon. */
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
-	  /*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
-	  if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
-	       (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) )
-	  {
-	      printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
-	      return -EINVAL;
-	  }
+	/*  Double check for Intel, we may run on Athlon  */
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+	{
+	    /*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
+	    if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
+		 (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) -1 ) ) )
+	    {
+		printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+		return -EINVAL;
+	    }
 	}
 	/*  Fall through  */
       case X86_VENDOR_CYRIX:
@@ -1236,7 +1262,7 @@
 
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
     max = get_num_var_ranges ();
-    down(&main_lock);
+    down (&main_lock);
     if (reg < 0)
     {
 	/*  Search for existing MTRR  */
@@ -1258,15 +1284,15 @@
     }
     if (reg >= max)
     {
-	up(&main_lock);
+	up (&main_lock);
 	printk ("mtrr: register: %d too big\n", reg);
 	return -EINVAL;
     }
     if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX)
     {
-	if ((reg == 3) && arr3_protected)
+	if ( (reg == 3) && arr3_protected )
 	{
-	    up(&main_lock);
+	    up (&main_lock);
 	    printk ("mtrr: ARR3 cannot be changed\n");
 	    return -EINVAL;
 	}
@@ -1274,19 +1300,19 @@
     (*get_mtrr) (reg, &lbase, &lsize, &ltype);
     if (lsize < 1)
     {
-	up(&main_lock);
+	up (&main_lock);
 	printk ("mtrr: MTRR %d not used\n", reg);
 	return -EINVAL;
     }
     if (usage_table[reg] < 1)
     {
-	up(&main_lock);
+	up (&main_lock);
 	printk ("mtrr: reg: %d has count=0\n", reg);
 	return -EINVAL;
     }
     if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0);
     compute_ascii ();
-    up(&main_lock);
+    up (&main_lock);
     return reg;
 }   /*  End Function mtrr_del  */
 
@@ -1473,16 +1499,17 @@
 
 static struct file_operations mtrr_fops =
 {
-	 read:		mtrr_read,
-	 write:		mtrr_write,
-	 ioctl:		mtrr_ioctl,
-	 release:	mtrr_close,
+    read:	mtrr_read,
+    write:	mtrr_write,
+    ioctl:	mtrr_ioctl,
+    release:	mtrr_close,
 };
 
 #  ifdef CONFIG_PROC_FS
 
-static struct inode_operations proc_mtrr_inode_operations = {
-	&mtrr_fops,             /* default property file-ops */
+static struct inode_operations proc_mtrr_inode_operations =
+{
+    &mtrr_fops,             /* default property file-ops */
 };
 
 static struct proc_dir_entry *proc_root_mtrr;
@@ -1538,15 +1565,17 @@
 
 #ifdef __SMP__
 
-typedef struct {
-  unsigned long base;
-  unsigned long size;
-  mtrr_type type;
+typedef struct
+{
+    unsigned long base;
+    unsigned long size;
+    mtrr_type type;
 } arr_state_t;
 
-arr_state_t arr_state[8] __initdata = {
-  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
-  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
+arr_state_t arr_state[8] __initdata =
+{
+    {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
+    {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
 };
 
 unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
@@ -1604,31 +1633,35 @@
     ccr[5] = getCx86 (CX86_CCR5);
     ccr[6] = getCx86 (CX86_CCR6);
 
-    if (ccr[3] & 1) {
-      ccrc[3] = 1;
-      arr3_protected = 1;
-    } else {
-      /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
-       * access to SMM memory through ARR3 (bit 7).
-       */
-      if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
-      if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
-      if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
-      arr3_protected = 0;
-      if (ccr[6] & 0x02) {
-        ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */
-        setCx86 (CX86_CCR6, ccr[6]);
-      }
-      /* Disable ARR3. This is safe now that we disabled SMM. */
-      /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
+    if (ccr[3] & 1)
+    {
+	ccrc[3] = 1;
+	arr3_protected = 1;
+    }
+    else
+    {
+	/* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+	 * access to SMM memory through ARR3 (bit 7).
+	 */
+	if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
+	if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
+	if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
+	arr3_protected = 0;
+	if (ccr[6] & 0x02) {
+	    ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */
+	    setCx86 (CX86_CCR6, ccr[6]);
+	}
+	/* Disable ARR3. This is safe now that we disabled SMM. */
+	/* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
     }
     /* If we changed CCR1 in memory, change it in the processor, too. */
     if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
 
     /* Enable ARR usage by the processor */
-    if (!(ccr[5] & 0x20)) {
-      ccr[5] |= 0x20; ccrc[5] = 1;
-      setCx86 (CX86_CCR5, ccr[5]);
+    if (!(ccr[5] & 0x20))
+    {
+	ccr[5] |= 0x20; ccrc[5] = 1;
+	setCx86 (CX86_CCR5, ccr[5]);
     }
 
 #ifdef __SMP__
@@ -1680,11 +1713,14 @@
     switch (boot_cpu_data.x86_vendor)
     {
       case X86_VENDOR_AMD:
-	if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */
-	  get_mtrr = amd_get_mtrr;
-	  set_mtrr_up = amd_set_mtrr_up;
-	  break;
-	} /* else fall through */
+	if (boot_cpu_data.x86 < 6)
+	{
+	    /* pre-Athlon CPUs */
+	    get_mtrr = amd_get_mtrr;
+	    set_mtrr_up = amd_set_mtrr_up;
+	    break;
+	}
+	/*   Else fall through  */
       case X86_VENDOR_INTEL:
 	get_mtrr = intel_get_mtrr;
 	set_mtrr_up = intel_set_mtrr_up;
@@ -1713,7 +1749,7 @@
     switch (boot_cpu_data.x86_vendor)
     {
       case X86_VENDOR_AMD:
-	if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */
+	if (boot_cpu_data.x86 < 6) break;  /*  Pre-Athlon CPUs  */
       case X86_VENDOR_INTEL:
 	get_mtrr_state (&smp_mtrr_state);
 	break;
@@ -1751,7 +1787,7 @@
     switch (boot_cpu_data.x86_vendor)
     {
       case X86_VENDOR_AMD:
-	/* Just for robustness: pre-Athlon CPUs cannot do SMP. */
+	/*  Just for robustness: pre-Athlon CPUs cannot do SMP  */
 	if (boot_cpu_data.x86 < 6) break;
       case X86_VENDOR_INTEL:
 	intel_mtrr_init_secondary_cpu ();
@@ -1775,17 +1811,17 @@
 int __init mtrr_init(void)
 {
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
-#  ifdef __SMP__
+#ifdef __SMP__
     switch (boot_cpu_data.x86_vendor)
     {
       case X86_VENDOR_AMD:
-	if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */
+	if (boot_cpu_data.x86 < 6) break;  /*  Pre-Athlon CPUs  */
       case X86_VENDOR_INTEL:
 	finalize_mtrr_state (&smp_mtrr_state);
 	mtrr_state_warn (smp_changes_mask);
 	break;
     }
-#  else /* __SMP__ */
+#else  /*  __SMP__  */
     mtrr_setup ();
     switch (boot_cpu_data.x86_vendor)
     {
@@ -1796,15 +1832,17 @@
         centaur_mcr_init ();
         break;
     }
-#  endif  /*  !__SMP__  */
+#endif  /*  !__SMP__  */
 
-#  ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_FS
     proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
     proc_root_mtrr->ops = &proc_mtrr_inode_operations;
-#endif    
+#endif
+#ifdev CONFIG_DEVFS_FS
     devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0,
 				   S_IFREG | S_IRUGO | S_IWUSR, 0, 0,
 				   &mtrr_fops, NULL);
+#endif
     init_table ();
     return 0;
 }   /*  End Function mtrr_init  */
diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.3.46/linux/arch/i386/kernel/process.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/i386/kernel/process.c	Sun Feb 20 20:37:09 2000
@@ -48,16 +48,6 @@
 
 int hlt_counter=0;
 
-void disable_hlt(void)
-{
-	hlt_counter++;
-}
-
-void enable_hlt(void)
-{
-	hlt_counter--;
-}
-
 /*
  * Powermanagement idle function, if any..
  */
@@ -68,6 +58,16 @@
  */
 void (*pm_power_off)(void) = NULL;
 
+void disable_hlt(void)
+{
+	hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+	hlt_counter--;
+}
+
 /*
  * We use this if we don't have any better
  * idle routine..
@@ -293,7 +293,7 @@
 
 void machine_restart(char * __unused)
 {
-#if __SMP__
+#if CONFIG_SMP
 	/*
 	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
 	 * other OSs see a clean IRQ state.
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.3.46/linux/arch/sparc/defconfig	Thu Feb 10 17:11:05 2000
+++ linux/arch/sparc/defconfig	Fri Feb 18 14:51:22 2000
@@ -259,18 +259,17 @@
 # CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=m
 # CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
 CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_SYSV_FS=m
 # CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
 
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v2.3.46/linux/arch/sparc/kernel/ioport.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/kernel/ioport.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.32 2000/02/12 03:04:48 zaitcev Exp $
+/* $Id: ioport.c,v 1.34 2000/02/18 13:48:48 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -348,7 +348,7 @@
  * CPU view of this memory may be inconsistent with
  * a device view and explicit flushing is necessary.
  */
-u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len)
+u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len, int direction)
 {
 #if 0 /* This is the version that abuses consistent space */
 	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
@@ -395,7 +395,7 @@
 #endif
 }
 
-void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n)
+void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n, int direction)
 {
 #if 0 /* This is the version that abuses consistent space */
 	struct resource *res;
@@ -424,7 +424,7 @@
 #endif
 }
 
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n)
+int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
 {
 	mmu_get_scsi_sgl(sg, n, sdev->bus);
 
@@ -435,14 +435,14 @@
 	return n;
 }
 
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n)
+void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
 {
 	mmu_release_scsi_sgl(sg, n, sdev->bus);
 }
 
 /*
  */
-void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size)
+void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size, int direction)
 {
 	unsigned long va;
 	struct resource *res;
@@ -456,7 +456,7 @@
 	mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK);
 }
 
-void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n)
+void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
 {
 	printk("sbus_dma_sync_sg: not implemented yet\n");
 }
@@ -577,8 +577,10 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size)
+dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	return virt_to_bus(ptr);
 }
 
@@ -589,8 +591,10 @@
  * After this call, reads by the cpu to the buffer are guarenteed to see
  * whatever the device wrote there.
  */
-void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
+void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do... */
 }
 
@@ -609,9 +613,13 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	int n;
+
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
 	for (n = 0; n < nents; n++) {
 		sg->dvma_address = virt_to_bus(sg->address);
 		sg->dvma_length = sg->length;
@@ -624,8 +632,10 @@
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents)
+void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do... */
 }
 
@@ -638,8 +648,10 @@
  * next point you give the PCI dma address back to the card, the
  * device again owns the buffer.
  */
-void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size)
+void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	mmu_inval_dma_area((unsigned long)bus_to_virt(ba),
 	    (size + PAGE_SIZE-1) & PAGE_MASK);
 }
@@ -650,8 +662,10 @@
  * The same as pci_dma_sync_single but for a scatter-gather list,
  * same rules and usage.
  */
-void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	while (nents) {
 		--nents;
 		mmu_inval_dma_area((unsigned long)sg->address,
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.3.46/linux/arch/sparc/kernel/sparc_ksyms.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Sun Feb 20 08:48:45 2000
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.90 2000/02/13 09:52:54 anton Exp $
+/* $Id: sparc_ksyms.c,v 1.91 2000/02/18 20:23:24 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -190,6 +190,8 @@
 EXPORT_SYMBOL(sbus_unmap_sg);
 EXPORT_SYMBOL(sbus_dma_sync_single);
 EXPORT_SYMBOL(sbus_dma_sync_sg);
+EXPORT_SYMBOL(sbus_iounmap);
+EXPORT_SYMBOL(sbus_ioremap);
 #endif
 #if CONFIG_PCI
 /* We do not have modular drivers for PCI devices yet. */
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.3.46/linux/arch/sparc/kernel/sys_sparc.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/kernel/sys_sparc.c	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.60 2000/02/08 20:24:18 davem Exp $
+/* $Id: sys_sparc.c,v 1.61 2000/02/16 07:31:29 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.46/linux/arch/sparc/kernel/sys_sunos.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.112 2000/01/29 07:40:11 davem Exp $
+/* $Id: sys_sunos.c,v 1.113 2000/02/16 07:31:29 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.3.46/linux/arch/sparc/kernel/systbls.S	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/kernel/systbls.S	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.93 2000/01/29 16:41:18 jj Exp $
+/* $Id: systbls.S,v 1.94 2000/02/16 07:31:30 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.3.46/linux/arch/sparc/mm/fault.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/mm/fault.c	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.113 2000/01/21 11:38:47 jj Exp $
+/* $Id: fault.c,v 1.114 2000/02/14 04:52:36 jj Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -342,7 +342,6 @@
 {
 	extern void sun4c_update_mmu_cache(struct vm_area_struct *,
 					   unsigned long,pte_t);
-	extern pgd_t *sun4c_pgd_offset(struct mm_struct *,unsigned long);
 	extern pte_t *sun4c_pte_offset(pmd_t *,unsigned long);
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
@@ -362,7 +361,7 @@
 		}
 	}
 
-	pgdp = sun4c_pgd_offset(mm, address);
+	pgdp = pgd_offset(mm, address);
 	ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
 
 	if (pgd_val(*pgdp)) {
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/nosun4c.c linux/arch/sparc/mm/nosun4c.c
--- v2.3.46/linux/arch/sparc/mm/nosun4c.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/mm/nosun4c.c	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: nosun4c.c,v 1.2 1999/08/31 06:54:36 davem Exp $
+/* $Id: nosun4c.c,v 1.3 2000/02/14 04:52:36 jj Exp $
  * nosun4c.c: This file is a bunch of dummies for SMP compiles, 
  *         so that it does not need sun4c and avoid ifdefs.
  *
@@ -50,11 +50,6 @@
 
 void sun4c_complete_all_stores(void)
 {
-}
-
-pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
-{
-	return NULL;
 }
 
 pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.3.46/linux/arch/sparc/mm/srmmu.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/mm/srmmu.c	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.207 2000/02/14 02:51:53 davem Exp $
+/* $Id: srmmu.c,v 1.208 2000/02/14 04:52:33 jj Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -201,7 +201,7 @@
 }
 
 /* to find an entry in a top-level page table... */
-static inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
+extern inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
 {
 	return mm->pgd + (address >> SRMMU_PGDIR_SHIFT);
 }
@@ -2337,7 +2337,6 @@
 	BTFIXUPSET_CALL(pgd_set, srmmu_pgd_set, BTFIXUPCALL_NORM);
 	
 	BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK);
-	BTFIXUPSET_CALL(pgd_offset, srmmu_pgd_offset, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_offset, srmmu_pte_offset, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_free_kernel, srmmu_pte_free, BTFIXUPCALL_NORM);
diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.46/linux/arch/sparc/mm/sun4c.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/mm/sun4c.c	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.189 2000/02/14 02:51:55 davem Exp $
+/* $Id: sun4c.c,v 1.190 2000/02/14 04:52:34 jj Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2185,7 +2185,7 @@
 }
 
 /* to find an entry in a page-table-directory */
-pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
+extern inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
 {
 	return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
 }
@@ -2273,7 +2273,7 @@
 		
 		ret = (unsigned long *)__get_free_page(GFP_KERNEL);
 		memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t));
-		init = pgd_offset(&init_mm, 0);
+		init = sun4c_pgd_offset(&init_mm, 0);
 		memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
 			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
@@ -2696,7 +2696,6 @@
 	BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM);
 	
 	BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK);
-	BTFIXUPSET_CALL(pgd_offset, sun4c_pgd_offset, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_offset, sun4c_pte_offset, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_free_kernel, sun4c_pte_free_kernel, BTFIXUPCALL_NORM);
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.46/linux/arch/sparc64/config.in	Thu Feb 10 17:11:05 2000
+++ linux/arch/sparc64/config.in	Sun Feb 20 20:15:01 2000
@@ -226,9 +226,9 @@
       if [ "$CONFIG_PCI" = "y" ]; then
 	 tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
 	 tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
-	 tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
+	 tristate 'RealTek RTL-8139 support' CONFIG_8139TOO
 	 tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
-	 tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
+	 tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100
 	 tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
       fi
       endmenu
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.46/linux/arch/sparc64/defconfig	Thu Feb 10 17:11:05 2000
+++ linux/arch/sparc64/defconfig	Fri Feb 18 14:51:22 2000
@@ -318,12 +318,12 @@
 # CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=m
 # CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
 CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_SYSV_FS=m
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.46/linux/arch/sparc64/kernel/ioctl32.c	Thu Feb 10 17:11:06 2000
+++ linux/arch/sparc64/kernel/ioctl32.c	Thu Feb 17 09:26:30 2000
@@ -1,7 +1,7 @@
-/* $Id: ioctl32.c,v 1.79 2000/02/08 20:24:25 davem Exp $
+/* $Id: ioctl32.c,v 1.80 2000/02/17 06:45:09 jj Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
- * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
  *
  * These routines maintain argument size conversion between 32bit and 64bit
@@ -42,6 +42,7 @@
 #include <linux/netdevice.h>
 #include <linux/raw.h>
 #include <linux/smb_fs.h>
+#include <linux/blkpg.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -435,7 +436,7 @@
         __kernel_caddr_t32  ifcbuf;
 };
 
-static int dev_ifname32(unsigned int fd, unsigned long arg)
+static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct net_device *dev;
 	struct ifreq32 ifr32;
@@ -454,7 +455,7 @@
 	return (err ? -EFAULT : 0);
 }
 
-static inline int dev_ifconf(unsigned int fd, unsigned long arg)
+static inline int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifconf32 ifc32;
 	struct ifconf ifc;
@@ -671,7 +672,7 @@
 	u32 start;
 };
                         
-static inline int hdio_getgeo(unsigned int fd, unsigned long arg)
+static inline int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t old_fs = get_fs();
 	struct hd_geometry geo;
@@ -1024,8 +1025,8 @@
 	unsigned int	badness;
 };
 
-#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) 
-#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) 
+#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32)
+#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32)
 #define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32)
 #define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32)
 #define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32)
@@ -1648,7 +1649,7 @@
 	u32 chardata;			/* font data in expanded form */
 };
 
-static int do_fontx_ioctl(struct file *file, int cmd, struct consolefontdesc32 *user_cfd)
+static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file)
 {
 	struct consolefontdesc cfdarg;
 	struct console_font_op op;
@@ -1657,7 +1658,7 @@
 	perm = vt_check(file);
 	if (perm < 0) return perm;
 	
-	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) 
+	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32)))
 		return -EFAULT;
 	
 	cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata);
@@ -1703,7 +1704,7 @@
 	u32 data;    /* font data with height fixed to 32 */
 };
                                         
-static int do_kdfontop_ioctl(struct file *file, struct console_font_op32 *fontop)
+static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file)
 {
 	struct console_font_op op;
 	int perm = vt_check(file), i;
@@ -1731,7 +1732,7 @@
 	u32 entries;
 };
 
-static int do_unimap_ioctl(struct file *file, int cmd, struct unimapdesc32 *user_ud)
+static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file)
 {
 	struct unimapdesc32 tmp;
 	int perm = vt_check(file);
@@ -1978,768 +1979,813 @@
         return -EINVAL;
 }
 
-asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	struct file * filp;
-	int error = -EBADF;
-
-	lock_kernel();
-	filp = fget(fd);
-	if(!filp)
-		goto out2;
+	return -EINVAL;
+}
 
-	if (!filp->f_op || !filp->f_op->ioctl) {
-		error = sys_ioctl (fd, cmd, arg);
-		goto out;
-	}
-	switch (cmd) {
-	case SIOCGIFNAME:
-		error = dev_ifname32(fd, arg);
-		goto out;
+static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* The mkswap binary hard codes it to Intel value :-((( */
+	return w_long(fd, BLKGETSIZE, arg);
+}
 
-	case SIOCGIFCONF:
-		error = dev_ifconf(fd, arg);
-		goto out;
-		
-	case SIOCGIFFLAGS:
-	case SIOCSIFFLAGS:
-	case SIOCGIFMETRIC:
-	case SIOCSIFMETRIC:
-	case SIOCGIFMTU:
-	case SIOCSIFMTU:
-	case SIOCGIFMEM:
-	case SIOCSIFMEM:
-	case SIOCGIFHWADDR:
-	case SIOCSIFHWADDR:
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-	case SIOCGIFINDEX:
-	case SIOCGIFMAP:
-	case SIOCSIFMAP:
-	case SIOCGIFADDR:
-	case SIOCSIFADDR:
-	case SIOCGIFBRDADDR:
-	case SIOCSIFBRDADDR:
-	case SIOCGIFDSTADDR:
-	case SIOCSIFDSTADDR:
-	case SIOCGIFNETMASK:
-	case SIOCSIFNETMASK:
-	case SIOCSIFPFLAGS:
-	case SIOCGIFPFLAGS:
-	case SIOCGPPPSTATS:
-	case SIOCGPPPCSTATS:
-	case SIOCGPPPVER:
-	case SIOCGIFTXQLEN:
-	case SIOCSIFTXQLEN:
-	case SIOCETHTOOL:
-		error = dev_ifsioc(fd, cmd, arg);
-		goto out;
-		
-	case SIOCADDRT:
-	case SIOCDELRT:
-		error = routing_ioctl(fd, cmd, arg);
-		goto out;
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
+                                
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
+	
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
+}
 
-	case SIOCRTMSG: /* Note SIOCRTMSG is no longer, so this is safe and
-			 * the user would have seen just an -EINVAL anyways.
-			 */
-		error = -EINVAL;
-		goto out;
+static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+}
 
-	case SIOCGSTAMP:
-		/* Sorry, timeval in the kernel is different now. */
-		error = do_siocgstamp(fd, cmd, arg);
-		goto out;
+struct ioctl_trans {
+	unsigned int cmd;
+	unsigned int handler;
+	unsigned int next;
+};
 
-	case HDIO_GETGEO:
-		error = hdio_getgeo(fd, arg);
-		goto out;
-		
-	case BLKRAGET:
-	case BLKGETSIZE:
-	case 0x1260:
-		/* The mkswap binary hard codes it to Intel value :-((( */
-		if(cmd == 0x1260)
-			cmd = BLKGETSIZE;
-		error = w_long(fd, cmd, arg);
-		goto out;
-		
-	case FBIOPUTCMAP32:
-	case FBIOGETCMAP32:
-		error = fbiogetputcmap(fd, cmd, arg);
-		goto out;
-		
-	case FBIOSCURSOR32:
-		error = fbiogscursor(fd, cmd, arg);
-		goto out;
+#define COMPATIBLE_IOCTL(cmd) asm volatile(".word %0, sys_ioctl, 0" : : "i" (cmd));
+#define HANDLE_IOCTL(cmd,handler) asm volatile(".word %0, %1, 0" : : "i" (cmd), "i" (handler));
+#define IOCTL_TABLE_START void ioctl32_foo(void) { asm volatile(".data\nioctl_translations:");
+#define IOCTL_TABLE_END asm volatile("\nioctl_translations_end:\n\t.previous"); }
 
-	case FBIOGET_FSCREENINFO:
-	case FBIOGETCMAP:
-	case FBIOPUTCMAP:
-		error = fb_ioctl_trans(fd, cmd, arg);
-		goto out;
+IOCTL_TABLE_START
+/* List here exlicitly which ioctl's are known to have
+ * compatable types passed or none at all...
+ */
+/* Big T */
+COMPATIBLE_IOCTL(TCGETA)
+COMPATIBLE_IOCTL(TCSETA)
+COMPATIBLE_IOCTL(TCSETAW)
+COMPATIBLE_IOCTL(TCSETAF)
+COMPATIBLE_IOCTL(TCSBRK)
+COMPATIBLE_IOCTL(TCXONC)
+COMPATIBLE_IOCTL(TCFLSH)
+COMPATIBLE_IOCTL(TCGETS)
+COMPATIBLE_IOCTL(TCSETS)
+COMPATIBLE_IOCTL(TCSETSW)
+COMPATIBLE_IOCTL(TCSETSF)
+COMPATIBLE_IOCTL(TIOCLINUX)
+/* Little t */
+COMPATIBLE_IOCTL(TIOCGETD)
+COMPATIBLE_IOCTL(TIOCSETD)
+COMPATIBLE_IOCTL(TIOCEXCL)
+COMPATIBLE_IOCTL(TIOCNXCL)
+COMPATIBLE_IOCTL(TIOCCONS)
+COMPATIBLE_IOCTL(TIOCGSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSWINSZ)
+COMPATIBLE_IOCTL(TIOCGWINSZ)
+COMPATIBLE_IOCTL(TIOCMGET)
+COMPATIBLE_IOCTL(TIOCMBIC)
+COMPATIBLE_IOCTL(TIOCMBIS)
+COMPATIBLE_IOCTL(TIOCMSET)
+COMPATIBLE_IOCTL(TIOCPKT)
+COMPATIBLE_IOCTL(TIOCNOTTY)
+COMPATIBLE_IOCTL(TIOCSTI)
+COMPATIBLE_IOCTL(TIOCOUTQ)
+COMPATIBLE_IOCTL(TIOCSPGRP)
+COMPATIBLE_IOCTL(TIOCGPGRP)
+COMPATIBLE_IOCTL(TIOCSCTTY)
+COMPATIBLE_IOCTL(TIOCGPTN)
+COMPATIBLE_IOCTL(TIOCSPTLCK)
+COMPATIBLE_IOCTL(TIOCGSERIAL)
+COMPATIBLE_IOCTL(TIOCSSERIAL)
+COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Big F */
+COMPATIBLE_IOCTL(FBIOGTYPE)
+COMPATIBLE_IOCTL(FBIOSATTR)
+COMPATIBLE_IOCTL(FBIOGATTR)
+COMPATIBLE_IOCTL(FBIOSVIDEO)
+COMPATIBLE_IOCTL(FBIOGVIDEO)
+COMPATIBLE_IOCTL(FBIOGCURSOR32)  /* This is not implemented yet. Later it should be converted... */
+COMPATIBLE_IOCTL(FBIOSCURPOS)
+COMPATIBLE_IOCTL(FBIOGCURPOS)
+COMPATIBLE_IOCTL(FBIOGCURMAX)
+COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
+COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
+COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
+COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO)
+COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO)
+COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO)
+COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE)
+COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE)
+COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP)
+COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP)
+/* Little f */
+COMPATIBLE_IOCTL(FIOCLEX)
+COMPATIBLE_IOCTL(FIONCLEX)
+COMPATIBLE_IOCTL(FIOASYNC)
+COMPATIBLE_IOCTL(FIONBIO)
+COMPATIBLE_IOCTL(FIONREAD)  /* This is also TIOCINQ */
+/* 0x00 */
+COMPATIBLE_IOCTL(FIBMAP)
+COMPATIBLE_IOCTL(FIGETBSZ)
+/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ *         Some need translations, these do not.
+ */
+COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
+COMPATIBLE_IOCTL(HDIO_SET_DMA)
+COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
+COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR)
+COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
+COMPATIBLE_IOCTL(HDIO_SET_32BIT)
+COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
+COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
+COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
+COMPATIBLE_IOCTL(HDIO_SET_NICE)
+/* 0x02 -- Floppy ioctls */
+COMPATIBLE_IOCTL(FDMSGON)
+COMPATIBLE_IOCTL(FDMSGOFF)
+COMPATIBLE_IOCTL(FDSETEMSGTRESH)
+COMPATIBLE_IOCTL(FDFLUSH)
+COMPATIBLE_IOCTL(FDWERRORCLR)
+COMPATIBLE_IOCTL(FDSETMAXERRS)
+COMPATIBLE_IOCTL(FDGETMAXERRS)
+COMPATIBLE_IOCTL(FDGETDRVTYP)
+COMPATIBLE_IOCTL(FDEJECT)
+COMPATIBLE_IOCTL(FDCLRPRM)
+COMPATIBLE_IOCTL(FDFMTBEG)
+COMPATIBLE_IOCTL(FDFMTEND)
+COMPATIBLE_IOCTL(FDRESET)
+COMPATIBLE_IOCTL(FDTWADDLE)
+COMPATIBLE_IOCTL(FDFMTTRK)
+COMPATIBLE_IOCTL(FDRAWCMD)
+/* 0x12 */
+COMPATIBLE_IOCTL(BLKROSET)
+COMPATIBLE_IOCTL(BLKROGET)
+COMPATIBLE_IOCTL(BLKRRPART)
+COMPATIBLE_IOCTL(BLKFLSBUF)
+COMPATIBLE_IOCTL(BLKRASET)
+COMPATIBLE_IOCTL(BLKFRASET)
+COMPATIBLE_IOCTL(BLKSECTSET)
+COMPATIBLE_IOCTL(BLKSSZGET)
 
-	case HDIO_GET_KEEPSETTINGS:
-	case HDIO_GET_UNMASKINTR:
-	case HDIO_GET_DMA:
-	case HDIO_GET_32BIT:
-	case HDIO_GET_MULTCOUNT:
-	case HDIO_GET_NOWERR:
-	case HDIO_GET_NICE:
-		error = hdio_ioctl_trans(fd, cmd, arg);
-		goto out;
 
-	case FDSETPRM32:
-	case FDDEFPRM32:
-	case FDGETPRM32:
-	case FDSETDRVPRM32:
-	case FDGETDRVPRM32:
-	case FDGETDRVSTAT32:
-	case FDPOLLDRVSTAT32:
-	case FDGETFDCSTAT32:
-	case FDWERRORGET32:
-		error = fd_ioctl_trans(fd, cmd, arg);
-		goto out;
+#if 0	/* New RAID code is being merged, fix up to handle
+	 * new RAID ioctls when fully merged in 2.3.x -DaveM
+	 */
+/* 0x09 */
+COMPATIBLE_IOCTL(REGISTER_DEV)
+COMPATIBLE_IOCTL(REGISTER_DEV_NEW)
+COMPATIBLE_IOCTL(START_MD)
+COMPATIBLE_IOCTL(STOP_MD)
+#endif
+	
+/* Big K */
+COMPATIBLE_IOCTL(PIO_FONT)
+COMPATIBLE_IOCTL(GIO_FONT)
+COMPATIBLE_IOCTL(KDSIGACCEPT)
+COMPATIBLE_IOCTL(KDGETKEYCODE)
+COMPATIBLE_IOCTL(KDSETKEYCODE)
+COMPATIBLE_IOCTL(KIOCSOUND)
+COMPATIBLE_IOCTL(KDMKTONE)
+COMPATIBLE_IOCTL(KDGKBTYPE)
+COMPATIBLE_IOCTL(KDSETMODE)
+COMPATIBLE_IOCTL(KDGETMODE)
+COMPATIBLE_IOCTL(KDSKBMODE)
+COMPATIBLE_IOCTL(KDGKBMODE)
+COMPATIBLE_IOCTL(KDSKBMETA)
+COMPATIBLE_IOCTL(KDGKBMETA)
+COMPATIBLE_IOCTL(KDGKBENT)
+COMPATIBLE_IOCTL(KDSKBENT)
+COMPATIBLE_IOCTL(KDGKBSENT)
+COMPATIBLE_IOCTL(KDSKBSENT)
+COMPATIBLE_IOCTL(KDGKBDIACR)
+COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDGKBLED)
+COMPATIBLE_IOCTL(KDSKBLED)
+COMPATIBLE_IOCTL(KDGETLED)
+COMPATIBLE_IOCTL(KDSETLED)
+COMPATIBLE_IOCTL(GIO_SCRNMAP)
+COMPATIBLE_IOCTL(PIO_SCRNMAP)
+COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_FONTRESET)
+COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
+/* Little k */
+COMPATIBLE_IOCTL(KIOCTYPE)
+COMPATIBLE_IOCTL(KIOCLAYOUT)
+COMPATIBLE_IOCTL(KIOCGTRANS)
+COMPATIBLE_IOCTL(KIOCTRANS)
+COMPATIBLE_IOCTL(KIOCCMD)
+COMPATIBLE_IOCTL(KIOCSDIRECT)
+COMPATIBLE_IOCTL(KIOCSLED)
+COMPATIBLE_IOCTL(KIOCGLED)
+COMPATIBLE_IOCTL(KIOCSRATE)
+COMPATIBLE_IOCTL(KIOCGRATE)
+/* Big S */
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
+COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+/* Big V */
+COMPATIBLE_IOCTL(VT_SETMODE)
+COMPATIBLE_IOCTL(VT_GETMODE)
+COMPATIBLE_IOCTL(VT_GETSTATE)
+COMPATIBLE_IOCTL(VT_OPENQRY)
+COMPATIBLE_IOCTL(VT_ACTIVATE)
+COMPATIBLE_IOCTL(VT_WAITACTIVE)
+COMPATIBLE_IOCTL(VT_RELDISP)
+COMPATIBLE_IOCTL(VT_DISALLOCATE)
+COMPATIBLE_IOCTL(VT_RESIZE)
+COMPATIBLE_IOCTL(VT_RESIZEX)
+COMPATIBLE_IOCTL(VT_LOCKSWITCH)
+COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
+/* Little v */
+COMPATIBLE_IOCTL(VUIDSFORMAT)
+COMPATIBLE_IOCTL(VUIDGFORMAT)
+/* Little v, the video4linux ioctls */
+COMPATIBLE_IOCTL(VIDIOCGCAP)
+COMPATIBLE_IOCTL(VIDIOCGCHAN)
+COMPATIBLE_IOCTL(VIDIOCSCHAN)
+COMPATIBLE_IOCTL(VIDIOCGPICT)
+COMPATIBLE_IOCTL(VIDIOCSPICT)
+COMPATIBLE_IOCTL(VIDIOCCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCKEY)
+COMPATIBLE_IOCTL(VIDIOCGAUDIO)
+COMPATIBLE_IOCTL(VIDIOCSAUDIO)
+COMPATIBLE_IOCTL(VIDIOCSYNC)
+COMPATIBLE_IOCTL(VIDIOCMCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCGMBUF)
+COMPATIBLE_IOCTL(VIDIOCGUNIT)
+COMPATIBLE_IOCTL(VIDIOCGCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCSCAPTURE)
+/* BTTV specific... */
+COMPATIBLE_IOCTL(_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]))
+COMPATIBLE_IOCTL(_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int))
+COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
+/* Little p (/dev/rtc, /dev/envctrl, etc.) */
+COMPATIBLE_IOCTL(RTCGET)
+COMPATIBLE_IOCTL(RTCSET)
+COMPATIBLE_IOCTL(I2CIOCSADR)
+COMPATIBLE_IOCTL(I2CIOCGADR)
+/* Little m */
+COMPATIBLE_IOCTL(MTIOCTOP)
+/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
+ * embedded pointers in the arg which we'd need to clean up...
+ */
+COMPATIBLE_IOCTL(OPROMGETOPT)
+COMPATIBLE_IOCTL(OPROMSETOPT)
+COMPATIBLE_IOCTL(OPROMNXTOPT)
+COMPATIBLE_IOCTL(OPROMSETOPT2)
+COMPATIBLE_IOCTL(OPROMNEXT)
+COMPATIBLE_IOCTL(OPROMCHILD)
+COMPATIBLE_IOCTL(OPROMGETPROP)
+COMPATIBLE_IOCTL(OPROMNXTPROP)
+COMPATIBLE_IOCTL(OPROMU2P)
+COMPATIBLE_IOCTL(OPROMGETCONS)
+COMPATIBLE_IOCTL(OPROMGETFBNAME)
+COMPATIBLE_IOCTL(OPROMGETBOOTARGS)
+COMPATIBLE_IOCTL(OPROMSETCUR)
+COMPATIBLE_IOCTL(OPROMPCI2NODE)
+COMPATIBLE_IOCTL(OPROMPATH2NODE)
+/* Socket level stuff */
+COMPATIBLE_IOCTL(FIOSETOWN)
+COMPATIBLE_IOCTL(SIOCSPGRP)
+COMPATIBLE_IOCTL(FIOGETOWN)
+COMPATIBLE_IOCTL(SIOCGPGRP)
+COMPATIBLE_IOCTL(SIOCATMARK)
+COMPATIBLE_IOCTL(SIOCSIFLINK)
+COMPATIBLE_IOCTL(SIOCSIFENCAP)
+COMPATIBLE_IOCTL(SIOCGIFENCAP)
+COMPATIBLE_IOCTL(SIOCSIFBR)
+COMPATIBLE_IOCTL(SIOCGIFBR)
+COMPATIBLE_IOCTL(SIOCSARP)
+COMPATIBLE_IOCTL(SIOCGARP)
+COMPATIBLE_IOCTL(SIOCDARP)
+#if 0 /* XXX No longer exist in new routing code. XXX */
+COMPATIBLE_IOCTL(OLD_SIOCSARP)
+COMPATIBLE_IOCTL(OLD_SIOCGARP)
+COMPATIBLE_IOCTL(OLD_SIOCDARP)
+#endif
+COMPATIBLE_IOCTL(SIOCSRARP)
+COMPATIBLE_IOCTL(SIOCGRARP)
+COMPATIBLE_IOCTL(SIOCDRARP)
+COMPATIBLE_IOCTL(SIOCADDDLCI)
+COMPATIBLE_IOCTL(SIOCDELDLCI)
+/* SG stuff */
+COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_EMULATED_HOST)
+COMPATIBLE_IOCTL(SG_SET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
+/* PPP stuff */
+COMPATIBLE_IOCTL(PPPIOCGFLAGS)
+COMPATIBLE_IOCTL(PPPIOCSFLAGS)
+COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGUNIT)
+COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGMRU)
+COMPATIBLE_IOCTL(PPPIOCSMRU)
+COMPATIBLE_IOCTL(PPPIOCSMAXCID)
+COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+COMPATIBLE_IOCTL(PPPIOCGNPMODE)
+COMPATIBLE_IOCTL(PPPIOCSNPMODE)
+COMPATIBLE_IOCTL(PPPIOCGDEBUG)
+COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
+COMPATIBLE_IOCTL(PPPIOCATTACH)
+COMPATIBLE_IOCTL(PPPIOCDETACH)
+/* CDROM stuff */
+COMPATIBLE_IOCTL(CDROMPAUSE)
+COMPATIBLE_IOCTL(CDROMRESUME)
+COMPATIBLE_IOCTL(CDROMPLAYMSF)
+COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
+COMPATIBLE_IOCTL(CDROMREADTOCHDR)
+COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
+COMPATIBLE_IOCTL(CDROMSTOP)
+COMPATIBLE_IOCTL(CDROMSTART)
+COMPATIBLE_IOCTL(CDROMEJECT)
+COMPATIBLE_IOCTL(CDROMVOLCTRL)
+COMPATIBLE_IOCTL(CDROMSUBCHNL)
+COMPATIBLE_IOCTL(CDROMEJECT_SW)
+COMPATIBLE_IOCTL(CDROMMULTISESSION)
+COMPATIBLE_IOCTL(CDROM_GET_MCN)
+COMPATIBLE_IOCTL(CDROMRESET)
+COMPATIBLE_IOCTL(CDROMVOLREAD)
+COMPATIBLE_IOCTL(CDROMSEEK)
+COMPATIBLE_IOCTL(CDROMPLAYBLK)
+COMPATIBLE_IOCTL(CDROMCLOSETRAY)
+COMPATIBLE_IOCTL(CDROM_SET_OPTIONS)
+COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS)
+COMPATIBLE_IOCTL(CDROM_SELECT_SPEED)
+COMPATIBLE_IOCTL(CDROM_SELECT_DISC)
+COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED)
+COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS)
+COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
+COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
+COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
+COMPATIBLE_IOCTL(CDROM_DEBUG)
+COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* Big L */
+COMPATIBLE_IOCTL(LOOP_SET_FD)
+COMPATIBLE_IOCTL(LOOP_CLR_FD)
+/* Big A */
+COMPATIBLE_IOCTL(AUDIO_GETINFO)
+COMPATIBLE_IOCTL(AUDIO_SETINFO)
+COMPATIBLE_IOCTL(AUDIO_DRAIN)
+COMPATIBLE_IOCTL(AUDIO_GETDEV)
+COMPATIBLE_IOCTL(AUDIO_GETDEV_SUNOS)
+COMPATIBLE_IOCTL(AUDIO_FLUSH)
+/* Big Q for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
+COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
+COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
+/* Big T for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_START)
+COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
+COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
+/* Little m for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
+/* Big P for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
+COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
+/* SNDCTL_DSP_MAPINBUF,  XXX needs translation */
+/* SNDCTL_DSP_MAPOUTBUF,  XXX needs translation */
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
+COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
+/* Big C for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
+COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
+COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
+COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
+/* Big M for sound/OSS */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
+/* SOUND_MIXER_READ_ENHANCE,  same value as READ_MUTE */
+/* SOUND_MIXER_READ_LOUD,  same value as READ_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
+/* SOUND_MIXER_WRITE_ENHANCE,  same value as WRITE_MUTE */
+/* SOUND_MIXER_WRITE_LOUD,  same value as WRITE_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
+COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
+COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
+COMPATIBLE_IOCTL(OSS_GETVERSION)
+/* AUTOFS */
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+/* Raw devices */
+COMPATIBLE_IOCTL(RAW_SETBIND)
+COMPATIBLE_IOCTL(RAW_GETBIND)
+/* SMB ioctls which do not need any translations */
+COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+/* Little a */
+COMPATIBLE_IOCTL(ATMSIGD_CTRL)
+COMPATIBLE_IOCTL(ATMARPD_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_MCAST)
+COMPATIBLE_IOCTL(ATMLEC_DATA)
+COMPATIBLE_IOCTL(ATM_SETSC)
+COMPATIBLE_IOCTL(SIOCSIFATMTCP)
+COMPATIBLE_IOCTL(SIOCMKCLIP)
+COMPATIBLE_IOCTL(ATMARP_MKIP)
+COMPATIBLE_IOCTL(ATMARP_SETENTRY)
+COMPATIBLE_IOCTL(ATMARP_ENCAP)
+COMPATIBLE_IOCTL(ATMTCP_CREATE)
+COMPATIBLE_IOCTL(ATMTCP_REMOVE)
+COMPATIBLE_IOCTL(ATMMPC_CTRL)
+COMPATIBLE_IOCTL(ATMMPC_DATA)
+/* And these ioctls need translation */
+HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
+HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
+HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc)
+HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
+HANDLE_IOCTL(SIOCETHTOOL, dev_ifsioc)
+HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
+HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
+/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
+HANDLE_IOCTL(SIOCRTMSG, ret_einval)
+HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
+HANDLE_IOCTL(BLKRAGET, w_long)
+HANDLE_IOCTL(BLKGETSIZE, w_long)
+HANDLE_IOCTL(0x1260, broken_blkgetsize)
+HANDLE_IOCTL(BLKFRAGET, w_long)
+HANDLE_IOCTL(BLKSECTGET, w_long)
+HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
+HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap)
+HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap)
+HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor)
+HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
+HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
+HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans)
+HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
+HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
+HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans)
+HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
+HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
+HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
+HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl)
+HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl)
+HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl)
+HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl)
+HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl)
+HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl)
+/* One SMB ioctl needs translations. */
+#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32)
+HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
+HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
+HANDLE_IOCTL(SUNI_GETLOOP, do_atm_ioctl)
+HANDLE_IOCTL(SUNI_SETLOOP, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
+IOCTL_TABLE_END
+
+unsigned int ioctl32_hash_table[1024];
+
+extern inline unsigned long ioctl32_hash(unsigned long cmd)
+{
+	return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
+}
+
+static void ioctl32_insert_translation(struct ioctl_trans *trans)
+{
+	unsigned long hash;
+	struct ioctl_trans *t;
+
+	hash = ioctl32_hash (trans->cmd);
+	if (!ioctl32_hash_table[hash])
+		ioctl32_hash_table[hash] = (u32)(long)trans;
+	else {
+		t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash];
+		while (t->next)
+			t = (struct ioctl_trans *)(long)t->next;
+		trans->next = 0;
+		t->next = (u32)(long)trans;
+	}
+}
 
-	case PPPIOCGIDLE32:
-	case PPPIOCSCOMPRESS32:
-		error = ppp_ioctl_trans(fd, cmd, arg);
-		goto out;
+static int __init init_sys32_ioctl(void)
+{
+	int i;
+	extern struct ioctl_trans ioctl_translations[], ioctl_translations_end[];
 
-	case MTIOCGET32:
-	case MTIOCPOS32:
-	case MTIOCGETCONFIG32:
-	case MTIOCSETCONFIG32:
-		error = mt_ioctl_trans(fd, cmd, arg);
-		goto out;
+	for (i = 0; &ioctl_translations[i] < &ioctl_translations_end[0]; i++)
+		ioctl32_insert_translation(&ioctl_translations[i]);
+	return 0;
+}
 
-	case CDROMREADMODE2:
-	case CDROMREADMODE1:
-	case CDROMREADRAW:
-	case CDROMREADCOOKED:
-	case CDROMREADAUDIO:
-	case CDROMREADALL:
-	case CDROM_SEND_PACKET:
-		error = cdrom_ioctl_trans(fd, cmd, arg);
-		goto out;
-		
-	case LOOP_SET_STATUS:
-	case LOOP_GET_STATUS:
-		error = loop_status(fd, cmd, arg);
-		goto out;
+__initcall(init_sys32_ioctl);
 
-#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
-	case AUTOFS_IOC_SETTIMEOUT32:
-		error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
-		goto out;
-		
-	case PIO_FONTX:
-	case GIO_FONTX:
-		error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)arg);
-		goto out;
-		
-	case PIO_UNIMAP:
-	case GIO_UNIMAP:
-		error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)arg);
-		goto out;
+static struct ioctl_trans *additional_ioctls;
 
-	case KDFONTOP:
-		error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)arg);
-		goto out;
-		
-	case EXT2_IOC32_GETFLAGS:
-	case EXT2_IOC32_SETFLAGS:
-	case EXT2_IOC32_GETVERSION:
-	case EXT2_IOC32_SETVERSION:
-		error = do_ext2_ioctl(fd, cmd, arg);
-		goto out;
-		
-	case VIDIOCGTUNER32:
-	case VIDIOCSTUNER32:
-	case VIDIOCGWIN32:
-	case VIDIOCSWIN32:
-	case VIDIOCGFBUF32:
-	case VIDIOCSFBUF32:
-	case VIDIOCGFREQ32:
-	case VIDIOCSFREQ32:
-		error = do_video_ioctl(fd, cmd, arg);
-		goto out;
+/* Always call these with kernel lock held! */
 
-	/* One SMB ioctl needs translations. */
-	case _IOR('u', 1, __kernel_uid_t32): /* SMB_IOC_GETMOUNTUID */
-		error = do_smb_getmountuid(fd, cmd, arg);
-		goto out;
+int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *))
+{
+	int i;
+	if (!additional_ioctls) {
+		additional_ioctls = module_map(PAGE_SIZE);
+		if (!additional_ioctls) return -ENOMEM;
+	}
+	for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++)
+		if (!additional_ioctls[i].cmd)
+			break;
+	if (i == PAGE_SIZE/sizeof(struct ioctl_trans))
+		return -ENOMEM;
+	additional_ioctls[i].cmd = cmd;
+	if (!handler)
+		additional_ioctls[i].handler = (u32)(long)sys_ioctl;
+	else
+		additional_ioctls[i].handler = (u32)(long)handler;
+	ioctl32_insert_translation(&additional_ioctls[i]);
+	return 0;
+}
 
-	case ATM_GETLINKRATE32:
-	case ATM_GETNAMES32:
-	case ATM_GETTYPE32:
-        case ATM_GETESI32:
-	case ATM_GETADDR32:
-        case ATM_RSTADDR32:
-        case ATM_ADDADDR32:
-        case ATM_DELADDR32:
-        case ATM_GETCIRANGE32:
-        case ATM_SETCIRANGE32:
-	case ATM_SETESI32:
-	case ATM_SETESIF32:
-	case ATM_GETSTAT32:
-	case ATM_GETSTATZ32:
-	case SUNI_GETLOOP:
-	case SUNI_SETLOOP:
-	case SONET_GETSTAT:
-	case SONET_GETSTATZ:
-	case SONET_GETDIAG:
-	case SONET_SETDIAG:
-	case SONET_CLRDIAG:
-	case SONET_SETFRAMING:
-	case SONET_GETFRAMING:
-	case SONET_GETFRSENSE:
-                error = do_atm_ioctl(fd, cmd, arg);
-                goto out;
-		
-	/* List here exlicitly which ioctl's are known to have
-	 * compatable types passed or none at all...
-	 */
+int unregister_ioctl32_conversion(unsigned int cmd)
+{
+	unsigned long hash = ioctl32_hash(cmd);
+	struct ioctl_trans *t, *t1;
 
-	/* Big T */
-	case TCGETA:
-	case TCSETA:
-	case TCSETAW:
-	case TCSETAF:
-	case TCSBRK:
-	case TCXONC:
-	case TCFLSH:
-	case TCGETS:
-	case TCSETS:
-	case TCSETSW:
-	case TCSETSF:
-	case TIOCLINUX:
-
-	/* Little t */
-	case TIOCGETD:
-	case TIOCSETD:
-	case TIOCEXCL:
-	case TIOCNXCL:
-	case TIOCCONS:
-	case TIOCGSOFTCAR:
-	case TIOCSSOFTCAR:
-	case TIOCSWINSZ:
-	case TIOCGWINSZ:
-	case TIOCMGET:
-	case TIOCMBIC:
-	case TIOCMBIS:
-	case TIOCMSET:
-	case TIOCPKT:
-	case TIOCNOTTY:
-	case TIOCSTI:
-	case TIOCOUTQ:
-	case TIOCSPGRP:
-	case TIOCGPGRP:
-	case TIOCSCTTY:
-	case TIOCGPTN:
-	case TIOCSPTLCK:
-	case TIOCGSERIAL:
-	case TIOCSSERIAL:
-	case TIOCSERGETLSR:
-	
-	/* Big F */
-	case FBIOGTYPE:
-	case FBIOSATTR:
-	case FBIOGATTR:
-	case FBIOSVIDEO:
-	case FBIOGVIDEO:
-	case FBIOGCURSOR32: /* This is not implemented yet. Later it should be converted... */
-	case FBIOSCURPOS:
-	case FBIOGCURPOS:
-	case FBIOGCURMAX:
-
-	case FBIOGET_VSCREENINFO:
-	case FBIOPUT_VSCREENINFO:
-	case FBIOPAN_DISPLAY:
-	case FBIOGET_FCURSORINFO:
-	case FBIOGET_VCURSORINFO:
-	case FBIOPUT_VCURSORINFO:
-	case FBIOGET_CURSORSTATE:
-	case FBIOPUT_CURSORSTATE:
-	case FBIOGET_CON2FBMAP:
-	case FBIOPUT_CON2FBMAP:
-
-	/* Little f */
-	case FIOCLEX:
-	case FIONCLEX:
-	case FIOASYNC:
-	case FIONBIO:
-	case FIONREAD: /* This is also TIOCINQ */
-	
-	/* 0x00 */
-	case FIBMAP:
-	case FIGETBSZ:
-	
-	/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
-	 *         Some need translations, these do not.
-	 */
-	case HDIO_GET_IDENTITY:
-	case HDIO_SET_DMA:
-	case HDIO_SET_KEEPSETTINGS:
-	case HDIO_SET_UNMASKINTR:
-	case HDIO_SET_NOWERR:
-	case HDIO_SET_32BIT:
-	case HDIO_SET_MULTCOUNT:
-	case HDIO_DRIVE_CMD:
-	case HDIO_SET_PIO_MODE:
-	case HDIO_SCAN_HWIF:
-	case HDIO_SET_NICE:
-	case BLKROSET:
-	case BLKROGET:
-
-	/* 0x02 -- Floppy ioctls */
-	case FDMSGON:
-	case FDMSGOFF:
-	case FDSETEMSGTRESH:
-	case FDFLUSH:
-	case FDWERRORCLR:
-	case FDSETMAXERRS:
-	case FDGETMAXERRS:
-	case FDGETDRVTYP:
-	case FDEJECT:
-	case FDCLRPRM:
-	case FDFMTBEG:
-	case FDFMTEND:
-	case FDRESET:
-	case FDTWADDLE:
-	case FDFMTTRK:
-	case FDRAWCMD:
-
-	/* 0x12 */
-	case BLKRRPART:
-	case BLKFLSBUF:
-	case BLKRASET:
+	t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash];
+	if (!t) return -EINVAL;
+	if (t->cmd == cmd && t >= additional_ioctls &&
+	    (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
+		ioctl32_hash_table[hash] = t->next;
+		t->cmd = 0;
+		return 0;
+	} else while (t->next) {
+		t1 = (struct ioctl_trans *)(long)t->next;
+		if (t1->cmd == cmd && t1 >= additional_ioctls &&
+		    (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
+			t1->cmd = 0;
+			t->next = t1->next;
+			return 0;
+		}
+		t = t1;
+	}
+	return -EINVAL;
+}
 
-#if 0	/* New RAID code is being merged, fix up to handle
-	 * new RAID ioctls when fully merged in 2.3.x -DaveM
-	 */
-	/* 0x09 */
-	case REGISTER_DEV:
-	case REGISTER_DEV_NEW:
-	case START_MD:
-	case STOP_MD:
-#endif
-	
-	/* Big K */
-	case PIO_FONT:
-	case GIO_FONT:
-	case KDSIGACCEPT:
-	case KDGETKEYCODE:
-	case KDSETKEYCODE:
-	case KIOCSOUND:
-	case KDMKTONE:
-	case KDGKBTYPE:
-	case KDSETMODE:
-	case KDGETMODE:
-	case KDSKBMODE:
-	case KDGKBMODE:
-	case KDSKBMETA:
-	case KDGKBMETA:
-	case KDGKBENT:
-	case KDSKBENT:
-	case KDGKBSENT:
-	case KDSKBSENT:
-	case KDGKBDIACR:
-	case KDSKBDIACR:
-	case KDGKBLED:
-	case KDSKBLED:
-	case KDGETLED:
-	case KDSETLED:
-	case GIO_SCRNMAP:
-	case PIO_SCRNMAP:
-	case GIO_UNISCRNMAP:
-	case PIO_UNISCRNMAP:
-	case PIO_FONTRESET:
-	case PIO_UNIMAPCLR:
-	
-	/* Little k */
-	case KIOCTYPE:
-	case KIOCLAYOUT:
-	case KIOCGTRANS:
-	case KIOCTRANS:
-	case KIOCCMD:
-	case KIOCSDIRECT:
-	case KIOCSLED:
-	case KIOCGLED:
-	case KIOCSRATE:
-	case KIOCGRATE:
-	
-	/* Big S */
-	case SCSI_IOCTL_GET_IDLUN:
-	case SCSI_IOCTL_DOORLOCK:
-	case SCSI_IOCTL_DOORUNLOCK:
-	case SCSI_IOCTL_TEST_UNIT_READY:
-	case SCSI_IOCTL_TAGGED_ENABLE:
-	case SCSI_IOCTL_TAGGED_DISABLE:
-	case SCSI_IOCTL_GET_BUS_NUMBER:
-	case SCSI_IOCTL_SEND_COMMAND:
-	
-	/* Big V */
-	case VT_SETMODE:
-	case VT_GETMODE:
-	case VT_GETSTATE:
-	case VT_OPENQRY:
-	case VT_ACTIVATE:
-	case VT_WAITACTIVE:
-	case VT_RELDISP:
-	case VT_DISALLOCATE:
-	case VT_RESIZE:
-	case VT_RESIZEX:
-	case VT_LOCKSWITCH:
-	case VT_UNLOCKSWITCH:
-	
-	/* Little v */
-	case VUIDSFORMAT:
-	case VUIDGFORMAT:
-
-	/* Little v, the video4linux ioctls */
-	case VIDIOCGCAP:
-	case VIDIOCGCHAN:
-	case VIDIOCSCHAN:
-	case VIDIOCGPICT:
-	case VIDIOCSPICT:
-	case VIDIOCCAPTURE:
-	case VIDIOCKEY:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-	case VIDIOCSYNC:
-	case VIDIOCMCAPTURE:
-	case VIDIOCGMBUF:
-	case VIDIOCGUNIT:
-	case VIDIOCGCAPTURE:
-	case VIDIOCSCAPTURE:
-
-	/* BTTV specific... */
-	case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
-	case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
-	case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
-	case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
-	case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
-	case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
-	case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
-	case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
-
-	/* Little p (/dev/rtc, /dev/envctrl, etc.) */
-	case RTCGET:
-	case RTCSET:
-	case I2CIOCSADR:
-	case I2CIOCGADR:
+asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct file * filp;
+	int error = -EBADF;
+	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+	struct ioctl_trans *t;
 
-	/* Little m */
-	case MTIOCTOP:
+	lock_kernel();
+	filp = fget(fd);
+	if(!filp)
+		goto out2;
 
-	/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
-	 * embedded pointers in the arg which we'd need to clean up...
-	 */
-	case OPROMGETOPT:
-	case OPROMSETOPT:
-	case OPROMNXTOPT:
-	case OPROMSETOPT2:
-	case OPROMNEXT:
-	case OPROMCHILD:
-	case OPROMGETPROP:
-	case OPROMNXTPROP:
-	case OPROMU2P:
-	case OPROMGETCONS:
-	case OPROMGETFBNAME:
-	case OPROMGETBOOTARGS:
-	case OPROMSETCUR:
-	case OPROMPCI2NODE:
-	case OPROMPATH2NODE:
-
-	/* Socket level stuff */
-	case FIOSETOWN:
-	case SIOCSPGRP:
-	case FIOGETOWN:
-	case SIOCGPGRP:
-	case SIOCATMARK:
-	case SIOCSIFLINK:
-	case SIOCSIFENCAP:
-	case SIOCGIFENCAP:
-	case SIOCSIFBR:
-	case SIOCGIFBR:
-	case SIOCSARP:
-	case SIOCGARP:
-	case SIOCDARP:
-#if 0 /* XXX No longer exist in new routing code. XXX */
-	case OLD_SIOCSARP:
-	case OLD_SIOCGARP:
-	case OLD_SIOCDARP:
-#endif
-	case SIOCSRARP:
-	case SIOCGRARP:
-	case SIOCDRARP:
-	case SIOCADDDLCI:
-	case SIOCDELDLCI:
-	
-	/* SG stuff */
-	case SG_SET_TIMEOUT:
-	case SG_GET_TIMEOUT:
-	case SG_EMULATED_HOST:
-	case SG_SET_TRANSFORM:
-	case SG_GET_TRANSFORM:
-
-	/* PPP stuff */
-	case PPPIOCGFLAGS:
-	case PPPIOCSFLAGS:
-	case PPPIOCGASYNCMAP:
-	case PPPIOCSASYNCMAP:
-	case PPPIOCGUNIT:
-	case PPPIOCGRASYNCMAP:
-	case PPPIOCSRASYNCMAP:
-	case PPPIOCGMRU:
-	case PPPIOCSMRU:
-	case PPPIOCSMAXCID:
-	case PPPIOCGXASYNCMAP:
-	case PPPIOCSXASYNCMAP:
-	case PPPIOCXFERUNIT:
-	case PPPIOCGNPMODE:
-	case PPPIOCSNPMODE:
-	case PPPIOCGDEBUG:
-	case PPPIOCSDEBUG:
-	case PPPIOCNEWUNIT:
-	case PPPIOCATTACH:
-	case PPPIOCDETACH:
-
-	/* CDROM stuff */
-	case CDROMPAUSE:
-	case CDROMRESUME:
-	case CDROMPLAYMSF:
-	case CDROMPLAYTRKIND:
-	case CDROMREADTOCHDR:
-	case CDROMREADTOCENTRY:
-	case CDROMSTOP:
-	case CDROMSTART:
-	case CDROMEJECT:
-	case CDROMVOLCTRL:
-	case CDROMSUBCHNL:
-	case CDROMEJECT_SW:
-	case CDROMMULTISESSION:
-	case CDROM_GET_MCN:
-	case CDROMRESET:
-	case CDROMVOLREAD:
-	case CDROMSEEK:
-	case CDROMPLAYBLK:
-	case CDROMCLOSETRAY:
-	case CDROM_SET_OPTIONS:
-	case CDROM_CLEAR_OPTIONS:
-	case CDROM_SELECT_SPEED:
-	case CDROM_SELECT_DISC:
-	case CDROM_MEDIA_CHANGED:
-	case CDROM_DRIVE_STATUS:
-	case CDROM_DISC_STATUS:
-	case CDROM_CHANGER_NSLOTS:
-	case CDROM_LOCKDOOR:
-	case CDROM_DEBUG:
-	case CDROM_GET_CAPABILITY:
-	
-	/* Big L */
-	case LOOP_SET_FD:
-	case LOOP_CLR_FD:
-	
-	/* Big A */
-	case AUDIO_GETINFO:
-	case AUDIO_SETINFO:
-	case AUDIO_DRAIN:
-	case AUDIO_GETDEV:
-	case AUDIO_GETDEV_SUNOS:
-	case AUDIO_FLUSH:
-
-	/* Big Q for sound/OSS */
-	case SNDCTL_SEQ_RESET:
-	case SNDCTL_SEQ_SYNC:
-	case SNDCTL_SYNTH_INFO:
-	case SNDCTL_SEQ_CTRLRATE:
-	case SNDCTL_SEQ_GETOUTCOUNT:
-	case SNDCTL_SEQ_GETINCOUNT:
-	case SNDCTL_SEQ_PERCMODE:
-	case SNDCTL_FM_LOAD_INSTR:
-	case SNDCTL_SEQ_TESTMIDI:
-	case SNDCTL_SEQ_RESETSAMPLES:
-	case SNDCTL_SEQ_NRSYNTHS:
-	case SNDCTL_SEQ_NRMIDIS:
-	case SNDCTL_MIDI_INFO:
-	case SNDCTL_SEQ_THRESHOLD:
-	case SNDCTL_SYNTH_MEMAVL:
-	case SNDCTL_FM_4OP_ENABLE:
-	case SNDCTL_SEQ_PANIC:
-	case SNDCTL_SEQ_OUTOFBAND:
-	case SNDCTL_SEQ_GETTIME:
-	case SNDCTL_SYNTH_ID:
-	case SNDCTL_SYNTH_CONTROL:
-	case SNDCTL_SYNTH_REMOVESAMPLE:
-
-	/* Big T for sound/OSS */
-	case SNDCTL_TMR_TIMEBASE:
-	case SNDCTL_TMR_START:
-	case SNDCTL_TMR_STOP:
-	case SNDCTL_TMR_CONTINUE:
-	case SNDCTL_TMR_TEMPO:
-	case SNDCTL_TMR_SOURCE:
-	case SNDCTL_TMR_METRONOME:
-	case SNDCTL_TMR_SELECT:
-
-	/* Little m for sound/OSS */
-	case SNDCTL_MIDI_PRETIME:
-	case SNDCTL_MIDI_MPUMODE:
-	case SNDCTL_MIDI_MPUCMD:
-
-	/* Big P for sound/OSS */
-	case SNDCTL_DSP_RESET:
-	case SNDCTL_DSP_SYNC:
-	case SNDCTL_DSP_SPEED:
-	case SNDCTL_DSP_STEREO:
-	case SNDCTL_DSP_GETBLKSIZE:
-	case SNDCTL_DSP_CHANNELS:
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_POST:
-	case SNDCTL_DSP_SUBDIVIDE:
-	case SNDCTL_DSP_SETFRAGMENT:
-	case SNDCTL_DSP_GETFMTS:
-	case SNDCTL_DSP_SETFMT:
-	case SNDCTL_DSP_GETOSPACE:
-	case SNDCTL_DSP_GETISPACE:
-	case SNDCTL_DSP_NONBLOCK:
-	case SNDCTL_DSP_GETCAPS:
-	case SNDCTL_DSP_GETTRIGGER:
-	case SNDCTL_DSP_SETTRIGGER:
-	case SNDCTL_DSP_GETIPTR:
-	case SNDCTL_DSP_GETOPTR:
-	/* case SNDCTL_DSP_MAPINBUF: XXX needs translation */
-	/* case SNDCTL_DSP_MAPOUTBUF: XXX needs translation */
-	case SNDCTL_DSP_SETSYNCRO:
-	case SNDCTL_DSP_SETDUPLEX:
-	case SNDCTL_DSP_GETODELAY:
-	case SNDCTL_DSP_PROFILE:
-
-	case SOUND_PCM_READ_RATE:
-	case SOUND_PCM_READ_CHANNELS:
-	case SOUND_PCM_READ_BITS:
-	case SOUND_PCM_READ_FILTER:
-
-	/* Big C for sound/OSS */
-	case SNDCTL_COPR_RESET:
-	case SNDCTL_COPR_LOAD:
-	case SNDCTL_COPR_RDATA:
-	case SNDCTL_COPR_RCODE:
-	case SNDCTL_COPR_WDATA:
-	case SNDCTL_COPR_WCODE:
-	case SNDCTL_COPR_RUN:
-	case SNDCTL_COPR_HALT:
-	case SNDCTL_COPR_SENDMSG:
-	case SNDCTL_COPR_RCVMSG:
-
-	/* Big M for sound/OSS */
-	case SOUND_MIXER_READ_VOLUME:
-	case SOUND_MIXER_READ_BASS:
-	case SOUND_MIXER_READ_TREBLE:
-	case SOUND_MIXER_READ_SYNTH:
-	case SOUND_MIXER_READ_PCM:
-	case SOUND_MIXER_READ_SPEAKER:
-	case SOUND_MIXER_READ_LINE:
-	case SOUND_MIXER_READ_MIC:
-	case SOUND_MIXER_READ_CD:
-	case SOUND_MIXER_READ_IMIX:
-	case SOUND_MIXER_READ_ALTPCM:
-	case SOUND_MIXER_READ_RECLEV:
-	case SOUND_MIXER_READ_IGAIN:
-	case SOUND_MIXER_READ_OGAIN:
-	case SOUND_MIXER_READ_LINE1:
-	case SOUND_MIXER_READ_LINE2:
-	case SOUND_MIXER_READ_LINE3:
-	case SOUND_MIXER_READ_MUTE:
-	/* case SOUND_MIXER_READ_ENHANCE: same value as READ_MUTE */
-	/* case SOUND_MIXER_READ_LOUD: same value as READ_MUTE */
-	case SOUND_MIXER_READ_RECSRC:
-	case SOUND_MIXER_READ_DEVMASK:
-	case SOUND_MIXER_READ_RECMASK:
-	case SOUND_MIXER_READ_STEREODEVS:
-	case SOUND_MIXER_READ_CAPS:
-
-	case SOUND_MIXER_WRITE_VOLUME:
-	case SOUND_MIXER_WRITE_BASS:
-	case SOUND_MIXER_WRITE_TREBLE:
-	case SOUND_MIXER_WRITE_SYNTH:
-	case SOUND_MIXER_WRITE_PCM:
-	case SOUND_MIXER_WRITE_SPEAKER:
-	case SOUND_MIXER_WRITE_LINE:
-	case SOUND_MIXER_WRITE_MIC:
-	case SOUND_MIXER_WRITE_CD:
-	case SOUND_MIXER_WRITE_IMIX:
-	case SOUND_MIXER_WRITE_ALTPCM:
-	case SOUND_MIXER_WRITE_RECLEV:
-	case SOUND_MIXER_WRITE_IGAIN:
-	case SOUND_MIXER_WRITE_OGAIN:
-	case SOUND_MIXER_WRITE_LINE1:
-	case SOUND_MIXER_WRITE_LINE2:
-	case SOUND_MIXER_WRITE_LINE3:
-	case SOUND_MIXER_WRITE_MUTE:
-	/* case SOUND_MIXER_WRITE_ENHANCE: same value as WRITE_MUTE */
-	/* case SOUND_MIXER_WRITE_LOUD: same value as WRITE_MUTE */
-	case SOUND_MIXER_WRITE_RECSRC:
-
-	case SOUND_MIXER_INFO:
-	case SOUND_OLD_MIXER_INFO:
-	case SOUND_MIXER_ACCESS:
-	case SOUND_MIXER_PRIVATE1:
-	case SOUND_MIXER_PRIVATE2:
-	case SOUND_MIXER_PRIVATE3:
-	case SOUND_MIXER_PRIVATE4:
-	case SOUND_MIXER_PRIVATE5:
-	case SOUND_MIXER_GETLEVELS:
-	case SOUND_MIXER_SETLEVELS:
-
-	case OSS_GETVERSION:
-
-	/* AUTOFS */
-	case AUTOFS_IOC_READY:
-	case AUTOFS_IOC_FAIL:
-	case AUTOFS_IOC_CATATONIC:
-	case AUTOFS_IOC_PROTOVER:
-	case AUTOFS_IOC_EXPIRE:
-	
-	/* Raw devices */
-	case RAW_SETBIND:
-	case RAW_GETBIND:
-
-	/* SMB ioctls which do not need any translations */
-	case SMB_IOC_NEWCONN:
-
-	/* Little a */
-	case ATMSIGD_CTRL:
-	case ATMARPD_CTRL:
-	case ATMLEC_CTRL:
-	case ATMLEC_MCAST:
-	case ATMLEC_DATA:
-	case ATM_SETSC:
-        case SIOCSIFATMTCP:
-	case SIOCMKCLIP:
-        case ATMARP_MKIP:
-        case ATMARP_SETENTRY:
-        case ATMARP_ENCAP:
-        case ATMTCP_CREATE:
-        case ATMTCP_REMOVE:
-        case ATMMPC_CTRL:
-        case ATMMPC_DATA:
-	    
+	if (!filp->f_op || !filp->f_op->ioctl) {
 		error = sys_ioctl (fd, cmd, arg);
 		goto out;
+	}
 
-	default:
-		do {
-			static int count = 0;
-			if (++count <= 20)
-				printk("sys32_ioctl: Unknown cmd fd(%d) "
-				       "cmd(%08x) arg(%08x)\n",
-				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
-		} while(0);
+	t = (struct ioctl_trans *)(long)ioctl32_hash_table [ioctl32_hash (cmd)];
+
+	while (t && t->cmd != cmd)
+		t = (struct ioctl_trans *)(long)t->next;
+	if (t) {
+		handler = (void *)(long)t->handler;
+		error = handler(fd, cmd, arg, filp);
+	} else {
+		static int count = 0;
+		if (++count <= 20)
+			printk("sys32_ioctl: Unknown cmd fd(%d) "
+			       "cmd(%08x) arg(%08x)\n",
+			       (int)fd, (unsigned int)cmd, (unsigned int)arg);
 		error = -EINVAL;
-		break;
 	}
 out:
 	fput(filp);
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c
--- v2.3.46/linux/arch/sparc64/kernel/pci_iommu.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/kernel/pci_iommu.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.8 2000/01/28 13:41:59 jj Exp $
+/* $Id: pci_iommu.c,v 1.10 2000/02/18 13:48:54 davem Exp $
  * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -99,13 +99,12 @@
 	return NULL;
 }
 
-#define IOPTE_CONSISTANT(CTX, PADDR) \
-	(IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | \
-	 (((CTX) << 47) & IOPTE_CONTEXT) | \
-	 ((PADDR) & IOPTE_PAGE))
+#define IOPTE_CONSISTENT(CTX) \
+	(IOPTE_VALID | IOPTE_CACHE | \
+	 (((CTX) << 47) & IOPTE_CONTEXT))
 
-#define IOPTE_STREAMING(CTX, PADDR) \
-	(IOPTE_CONSISTANT(CTX, PADDR) | IOPTE_STBUF)
+#define IOPTE_STREAMING(CTX) \
+	(IOPTE_CONSISTENT(CTX) | IOPTE_STBUF)
 
 #define IOPTE_INVALID	0UL
 
@@ -127,11 +126,6 @@
 	if (order >= 10)
 		return NULL;
 
-	/* We still don't support devices which don't recognize at least 30 bits
-	   of bus address. Bug me to code it (is pretty easy actually). -jj */
-	if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff)
-		BUG();
-
 	first_page = __get_free_pages(GFP_ATOMIC, order);
 	if (first_page == 0UL)
 		return NULL;
@@ -157,7 +151,9 @@
 		ctx = iommu->iommu_cur_ctx++;
 	first_page = __pa(first_page);
 	while (npages--) {
-		iopte_val(*iopte) = IOPTE_CONSISTANT(ctx, first_page);
+		iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) |
+				     IOPTE_WRITE |
+				     (first_page & IOPTE_PAGE));
 		iopte++;
 		first_page += PAGE_SIZE;
 	}
@@ -215,7 +211,7 @@
 /* Map a single buffer at PTR of SZ bytes for PCI DMA
  * in streaming mode.
  */
-dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz)
+dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -224,14 +220,13 @@
 	unsigned long flags, npages, oaddr;
 	unsigned long i, base_paddr, ctx;
 	u32 bus_addr, ret;
+	unsigned long iopte_protection;
 
 	pcp = pdev->sysdata;
 	iommu = &pcp->pbm->parent->iommu;
 	strbuf = &pcp->pbm->stc;
 
-	/* We still don't support devices which don't recognize at least 30 bits
-	   of bus address. Bug me to code it (is pretty easy actually). -jj */
-	if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff)
+	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	oaddr = (unsigned long)ptr;
@@ -248,13 +243,15 @@
 	ctx = 0;
 	if (iommu->iommu_ctxflush)
 		ctx = iommu->iommu_cur_ctx++;
-	if (strbuf->strbuf_enabled) {
-		for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
-			iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr);
-	} else {
-		for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
-			iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr);
-	}
+	if (strbuf->strbuf_enabled)
+		iopte_protection = IOPTE_STREAMING(ctx);
+	else
+		iopte_protection = IOPTE_CONSISTENT(ctx);
+	if (direction != PCI_DMA_TODEVICE)
+		iopte_protection |= IOPTE_WRITE;
+
+	for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
+		iopte_val(*base) = iopte_protection | base_paddr;
 
 	/* Flush the IOMMU TLB. */
 	if (iommu->iommu_ctxflush) {
@@ -270,7 +267,7 @@
 }
 
 /* Unmap a single streaming mode DMA translation. */
-void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz)
+void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -278,6 +275,9 @@
 	iopte_t *base;
 	unsigned long flags, npages, i, ctx;
 
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
 	pcp = pdev->sysdata;
 	iommu = &pcp->pbm->parent->iommu;
 	strbuf = &pcp->pbm->stc;
@@ -335,7 +335,7 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long ctx, int streaming)
+static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_protection)
 {
 	struct scatterlist *dma_sg = sg;
 	int i;
@@ -375,10 +375,7 @@
 				sg++;
 			}
 
-			if (streaming)
-				pteval = IOPTE_STREAMING(ctx, pteval);
-			else
-				pteval = IOPTE_CONSISTANT(ctx, pteval);
+			pteval = iopte_protection | (pteval & IOPTE_PAGE);
 			while (len > 0) {
 				*iopte++ = __iopte(pteval);
 				pteval += PAGE_SIZE;
@@ -413,12 +410,12 @@
  * When making changes here, inspect the assembly output. I was having
  * hard time to kepp this routine out of using stack slots for holding variables.
  */
-int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
 	struct pci_strbuf *strbuf;
-	unsigned long flags, ctx, i, npages;
+	unsigned long flags, ctx, i, npages, iopte_protection;
 	iopte_t *base;
 	u32 dma_base;
 	struct scatterlist *sgtmp;
@@ -426,7 +423,7 @@
 
 	/* Fast path single entry scatterlists. */
 	if (nelems == 1) {
-		sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length);
+		sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length, direction);
 		sglist->dvma_length = sglist->length;
 		return 1;
 	}
@@ -435,9 +432,7 @@
 	iommu = &pcp->pbm->parent->iommu;
 	strbuf = &pcp->pbm->stc;
 	
-	/* We still don't support devices which don't recognize at least 30 bits
-	   of bus address. Bug me to code it (is pretty easy actually). -jj */
-	if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff)
+	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	/* Step 1: Prepare scatter list. */
@@ -468,7 +463,13 @@
 		ctx = iommu->iommu_cur_ctx++;
 
 	/* Step 5: Create the mappings. */
-	fill_sg (base, sglist, used, ctx, strbuf->strbuf_enabled);
+	if (strbuf->strbuf_enabled)
+		iopte_protection = IOPTE_STREAMING(ctx);
+	else
+		iopte_protection = IOPTE_CONSISTENT(ctx);
+	if (direction != PCI_DMA_TODEVICE)
+		iopte_protection |= IOPTE_WRITE;
+	fill_sg (base, sglist, used, iopte_protection);
 #ifdef VERIFY_SG
 	verify_sglist(sglist, nelems, base, npages);
 #endif
@@ -487,7 +488,7 @@
 }
 
 /* Unmap a set of streaming mode DMA translations. */
-void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -496,6 +497,9 @@
 	unsigned long flags, ctx, i, npages;
 	u32 bus_addr;
 
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
 	pcp = pdev->sysdata;
 	iommu = &pcp->pbm->parent->iommu;
 	strbuf = &pcp->pbm->stc;
@@ -562,7 +566,7 @@
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
  */
-void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz)
+void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -623,7 +627,7 @@
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  */
-void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -683,4 +687,20 @@
 		membar("#LoadLoad");
 
 	spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask)
+{
+	struct pcidev_cookie *pcp = pdev->sysdata;
+	u32 dma_addr_mask;
+
+	if (pdev == NULL) {
+		dma_addr_mask = 0xffffffff;
+	} else {
+		struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+
+		dma_addr_mask = iommu->dma_addr_mask;
+	}
+
+	return (device_mask & dma_addr_mask) == dma_addr_mask;
 }
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.3.46/linux/arch/sparc64/kernel/pci_psycho.c	Thu Feb 10 17:11:06 2000
+++ linux/arch/sparc64/kernel/pci_psycho.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.11 2000/02/08 05:11:32 jj Exp $
+/* $Id: pci_psycho.c,v 1.13 2000/02/18 13:48:54 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1264,6 +1264,7 @@
 	p->iommu.page_table = (iopte_t *)tsbbase;
 	p->iommu.page_table_sz_bits = 17;
 	p->iommu.page_table_map_base = 0xc0000000;
+	p->iommu.dma_addr_mask = 0xffffffff;
 	memset((char *)tsbbase, 0, PAGE_SIZE << 7);
 
 	/* Make sure DMA address 0 is never returned just to allow catching
@@ -1344,9 +1345,7 @@
 				   int is_pbm_a)
 {
 	unsigned long base = p->controller_regs;
-
-	/* Currently we don't even use it. */
-	pbm->stc.strbuf_enabled = 0;
+	u64 control;
 
 	if (is_pbm_a) {
 		pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_A;
@@ -1368,14 +1367,29 @@
 	pbm->stc.strbuf_flushflag_pa = (unsigned long)
 		__pa(pbm->stc.strbuf_flushflag);
 
-#if 0
-	/* And when we do enable it, these are the sorts of things
-	 * we'll do.
+	/* Enable the streaming buffer.  We have to be careful
+	 * just in case OBP left it with LRU locking enabled.
+	 *
+	 * It is possible to control if PBM will be rerun on
+	 * line misses.  Currently I just retain whatever setting
+	 * OBP left us with.  All checks so far show it having
+	 * a value of zero.
 	 */
+#undef PSYCHO_STRBUF_RERUN_ENABLE
+#undef PSYCHO_STRBUF_RERUN_DISABLE
 	control = psycho_read(pbm->stc.strbuf_control);
-	control |= PSYCHO_SBUFCTRL_SB_EN;
-	psycho_write(pbm->stc.strbuf_control, control);
+	control |= PSYCHO_STRBUF_CTRL_ENAB;
+	control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR);
+#ifdef PSYCHO_STRBUF_RERUN_ENABLE
+	control &= ~(PSYCHO_STRBUF_CTRL_RRDIS);
+#else
+#ifdef PSYCHO_STRBUF_RERUN_DISABLE
+	control |= PSYCHO_STRBUF_CTRL_RRDIS;
 #endif
+#endif
+	psycho_write(pbm->stc.strbuf_control, control);
+
+	pbm->stc.strbuf_enabled = 1;
 }
 
 #define PSYCHO_IOSPACE_A	0x002000000UL
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.3.46/linux/arch/sparc64/kernel/pci_sabre.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/kernel/pci_sabre.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.12 2000/02/08 05:11:33 jj Exp $
+/* $Id: pci_sabre.c,v 1.14 2000/02/18 13:48:55 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1105,7 +1105,8 @@
 }
 
 static void __init sabre_iommu_init(struct pci_controller_info *p,
-				    int tsbsize, unsigned long dvma_offset)
+				    int tsbsize, unsigned long dvma_offset,
+				    u32 dma_mask)
 {
 	unsigned long tsbbase, i, order;
 	u64 control;
@@ -1140,6 +1141,7 @@
 	}
 	p->iommu.page_table = (iopte_t *)tsbbase;
 	p->iommu.page_table_map_base = dvma_offset;
+	p->iommu.dma_addr_mask = dma_mask;
 	memset((char *)tsbbase, 0, PAGE_SIZE << order);
 
 	/* Make sure DMA address 0 is never returned just to allow catching
@@ -1312,7 +1314,7 @@
 	int tsbsize, err;
 	u32 busrange[2];
 	u32 vdma[2];
-	u32 upa_portid;
+	u32 upa_portid, dma_mask;
 	int bus;
 
 	p = kmalloc(sizeof(*p), GFP_ATOMIC);
@@ -1372,12 +1374,19 @@
 		prom_halt();
 	}
 
+	dma_mask = vdma[0];
 	switch(vdma[1]) {
 		case 0x20000000:
+			dma_mask |= 0x1fffffff;
 			tsbsize = 64;
 			break;
 		case 0x40000000:
+			dma_mask |= 0x3fffffff;
+			tsbsize = 128;
+			break;
+
 		case 0x80000000:
+			dma_mask |= 0x7fffffff;
 			tsbsize = 128;
 			break;
 		default:
@@ -1385,7 +1394,7 @@
 			prom_halt();
 	}
 
-	sabre_iommu_init(p, tsbsize, vdma[0]);
+	sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
 
 	printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
 
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- v2.3.46/linux/arch/sparc64/kernel/sbus.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/kernel/sbus.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.7 2000/01/28 13:41:58 jj Exp $
+/* $Id: sbus.c,v 1.9 2000/02/18 13:48:57 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -308,12 +308,16 @@
 		free_pages((unsigned long)cpu, order);
 }
 
-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size)
+dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int dir)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	unsigned long npages, phys_base, flags;
 	iopte_t *iopte;
 	u32 dma_base, offset;
+	unsigned long iopte_bits;
+
+	if (dir == SBUS_DMA_NONE)
+		BUG();
 
 	phys_base = (unsigned long) ptr;
 	offset = (u32) (phys_base & ~PAGE_MASK);
@@ -325,10 +329,11 @@
 	iopte = alloc_streaming_cluster(iommu, npages);
 	dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT);
 	npages = size >> PAGE_SHIFT;
+	iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
+	if (dir != SBUS_DMA_TODEVICE)
+		iopte_bits |= IOPTE_WRITE;
 	while (npages--) {
-		*iopte++ = __iopte(IOPTE_VALID | IOPTE_STBUF |
-				   IOPTE_CACHE | IOPTE_WRITE |
-				   (phys_base & IOPTE_PAGE));
+		*iopte++ = __iopte(iopte_bits | (phys_base & IOPTE_PAGE));
 		phys_base += PAGE_SIZE;
 	}
 	npages = size >> PAGE_SHIFT;
@@ -338,7 +343,7 @@
 	return (dma_base | offset);
 }
 
-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size)
+void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, int direction)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	u32 dma_base = dma_addr & PAGE_MASK;
@@ -352,7 +357,7 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused)
+static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_bits)
 {
 	struct scatterlist *dma_sg = sg;
 	int i;
@@ -392,9 +397,7 @@
 				sg++;
 			}
 
-			pteval = ((pteval & IOPTE_PAGE) |
-				  IOPTE_VALID | IOPTE_STBUF |
-				  IOPTE_CACHE | IOPTE_WRITE);
+			pteval = ((pteval & IOPTE_PAGE) | iopte_bits);
 			while (len > 0) {
 				*iopte++ = __iopte(pteval);
 				pteval += PAGE_SIZE;
@@ -424,7 +427,7 @@
 	}
 }
 
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
+int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int dir)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	unsigned long flags, npages;
@@ -432,10 +435,14 @@
 	u32 dma_base;
 	struct scatterlist *sgtmp;
 	int used;
+	unsigned long iopte_bits;
+
+	if (dir == SBUS_DMA_NONE)
+		BUG();
 
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length);
+		sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length, dir);
 		sg->dvma_length = sg->length;
 		return 1;
 	}
@@ -457,7 +464,11 @@
 	}
 	used = nents - used;
 
-	fill_sg(iopte, sg, used);
+	iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
+	if (dir != SBUS_DMA_TODEVICE)
+		iopte_bits |= IOPTE_WRITE;
+
+	fill_sg(iopte, sg, used, iopte_bits);
 #ifdef VERIFY_SG
 	verify_sglist(sg, nents, iopte, npages);
 #endif
@@ -467,7 +478,7 @@
 	return used;
 }
 
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
+void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
 {
 	unsigned long size, flags;
 	struct sbus_iommu *iommu;
@@ -476,7 +487,7 @@
 
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length);
+		sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length, direction);
 		return;
 	}
 
@@ -495,7 +506,7 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size)
+void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	unsigned long flags;
@@ -507,7 +518,7 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
+void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	unsigned long flags, size;
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.3.46/linux/arch/sparc64/kernel/sys_sparc.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/kernel/sys_sparc.c	Thu Feb 17 09:26:30 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.35 2000/01/29 07:40:12 davem Exp $
+/* $Id: sys_sparc.c,v 1.36 2000/02/16 07:31:35 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.46/linux/arch/sparc64/kernel/sys_sparc32.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.131 2000/01/21 11:38:54 jj Exp $
+/* $Id: sys_sparc32.c,v 1.132 2000/02/16 07:31:35 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.46/linux/arch/sparc64/kernel/sys_sunos32.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.38 2000/01/29 07:40:13 davem Exp $
+/* $Id: sys_sunos32.c,v 1.39 2000/02/16 07:31:37 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.3.46/linux/arch/sparc64/kernel/systbls.S	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/kernel/systbls.S	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.67 2000/01/29 16:41:21 jj Exp $
+/* $Id: systbls.S,v 1.68 2000/02/16 07:31:38 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.3.46/linux/arch/sparc64/solaris/misc.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/solaris/misc.c	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.21 2000/01/29 07:40:15 davem Exp $
+/* $Id: misc.c,v 1.22 2000/02/16 07:31:41 davem Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c
--- v2.3.46/linux/arch/sparc64/solaris/socksys.c	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/solaris/socksys.c	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.11 2000/02/09 22:32:17 davem Exp $
+/* $Id: socksys.c,v 1.12 2000/02/17 05:50:11 davem Exp $
  * socksys.c: /dev/inet/ stuff for Solaris emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.3.46/linux/drivers/Makefile linux/drivers/Makefile
--- v2.3.46/linux/drivers/Makefile	Tue Feb  1 01:35:43 2000
+++ linux/drivers/Makefile	Thu Feb 17 09:57:13 2000
@@ -52,7 +52,7 @@
 MOD_SUB_DIRS += video
 endif
 
-ifdef CONFIG_PPC
+ifdef CONFIG_MAC
 SUB_DIRS += macintosh
 MOD_SUB_DIRS += macintosh
 endif
diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c
--- v2.3.46/linux/drivers/acorn/net/ether1.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/acorn/net/ether1.c	Thu Feb 17 23:34:46 2000
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/drivers/net/ether1.c
  *
- * (C) Copyright 1996,1997,1998 Russell King
+ * (C) Copyright 1996-2000 Russell King
  *
  * Acorn ether1 driver (82586 chip)
  *  for Acorn machines
@@ -28,6 +28,7 @@
  *				TDR now only reports failure when chip reports non-zero
  *				TDR time-distance.
  * 1.05	RMK	31/12/1997	Removed calls to dev_tint for 2.1
+ * 1.06	RMK	10/02/2000	Updated for 2.3.43
  */
 
 #include <linux/module.h>
@@ -64,9 +65,16 @@
 #define RX_AREA_START	0x05000
 #define RX_AREA_END	0x0fc00
 
-#define tx_done(dev) 0
+static int ether1_open(struct net_device *dev);
+static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
+static void ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int ether1_close(struct net_device *dev);
+static struct enet_statistics *ether1_getstats(struct net_device *dev);
+static void ether1_setmulticastlist(struct net_device *dev);
+static void ether1_timeout(struct net_device *dev);
+
 /* ------------------------------------------------------------------------- */
-static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.05\n";
+static char *version = "ether1 ethernet driver (c) 2000 Russell King v1.06\n";
 
 #define BUS_16 16
 #define BUS_8  8
@@ -636,12 +644,12 @@
 	if (net_debug && version_printed++ == 0)
 		printk (KERN_INFO "%s", version);
 
-	printk (KERN_INFO "%s: ether1 found [%d, %04lx, %d]", dev->name, priv->bus_type,
-		dev->base_addr, dev->irq);
-
 	request_region (dev->base_addr, 16, "ether1");
 	request_region (dev->base_addr + 0x800, 4096, "ether1(ram)");
 
+	printk (KERN_INFO "%s: ether1 at %lx, IRQ%d, ether address ",
+		dev->name, dev->base_addr, dev->irq);
+
 	for (i = 0; i < 6; i++)
 		printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]);
 
@@ -650,11 +658,13 @@
 		return 1;
 	}
 
-	dev->open		    = ether1_open;
-	dev->stop		    = ether1_close;
+	dev->open		= ether1_open;
+	dev->stop		= ether1_close;
 	dev->hard_start_xmit    = ether1_sendpacket;
-	dev->get_stats	    = ether1_getstats;
+	dev->get_stats		= ether1_getstats;
 	dev->set_multicast_list = ether1_setmulticastlist;
+	dev->tx_timeout		= ether1_timeout;
+	dev->watchdog_timeo	= 5 * HZ / 100;
 
 	/* Fill in the fields of the device structure with ethernet values */
 	ether_setup (dev);
@@ -727,38 +737,18 @@
 	return start;
 }
 
-static void
-ether1_restart (struct net_device *dev, char *reason)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	priv->stats.tx_errors ++;
-
-	if (reason)
-		printk (KERN_WARNING "%s: %s - resetting device\n", dev->name, reason);
-	else
-		printk (" - resetting device\n");
-
-	ether1_reset (dev);
-
-	dev->start = 0;
-	dev->tbusy = 0;
-
-	if (ether1_init_for_open (dev))
-		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
-
-	dev->start = 1;
-}
-
 static int
 ether1_open (struct net_device *dev)
 {
 	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 
-	if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev))
-		return -EAGAIN;
-
 	MOD_INC_USE_COUNT;
 
+	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) {
+		MOD_DEC_USE_COUNT;
+		return -EAGAIN;
+	}
+
 	memset (&priv->stats, 0, sizeof (struct enet_statistics));
 
 	if (ether1_init_for_open (dev)) {
@@ -767,95 +757,94 @@
 		return -EAGAIN;
 	}
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+	netif_start_queue(dev);
 
 	return 0;
 }
 
+static void
+ether1_timeout(struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+
+	printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
+		dev->name);
+	printk(KERN_WARNING "%s: resetting device\n", dev->name);
+
+	ether1_reset (dev);
+
+	if (ether1_init_for_open (dev))
+		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
+
+	priv->stats.tx_errors++;
+	netif_wake_queue(dev);
+}
+
 static int
 ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
 {
 	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
+	unsigned long flags;
+	tx_t tx;
+	tbd_t tbd;
+	nop_t nop;
 
-	if (priv->restart)
-		ether1_restart (dev, NULL);
-
-	if (dev->tbusy) {
-		/*
-		 * If we get here, some higher level has decided that we are broken.
-		 * There should really be a "kick me" function call instead.
-		 */
-		int tickssofar = jiffies - dev->trans_start;
+	if (priv->restart) {
+		printk(KERN_WARNING "%s: resetting device\n", dev->name);
 
-		if (tickssofar < 5)
-			return 1;
+		ether1_reset(dev);
 
-		/* Try to restart the adapter. */
-		ether1_restart (dev, "transmit timeout, network cable problem?");
-		dev->trans_start = jiffies;
+		if (ether1_init_for_open(dev))
+			printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
 	}
 
 	/*
-	 * Block a timer-based transmit from overlapping.  This could better be
-	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	 * insert packet followed by a nop
 	 */
-	if (test_and_set_bit (0, (void *)&dev->tbusy) != 0)
-		printk (KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-	else {
-		int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-		int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
-		unsigned long flags;
-		tx_t tx;
-		tbd_t tbd;
-		nop_t nop;
-
-		/*
-		 * insert packet followed by a nop
-		 */
-		txaddr = ether1_txalloc (dev, TX_SIZE);
-		tbdaddr = ether1_txalloc (dev, TBD_SIZE);
-		dataddr = ether1_txalloc (dev, len);
-		nopaddr = ether1_txalloc (dev, NOP_SIZE);
-
-		tx.tx_status = 0;
-		tx.tx_command = CMD_TX | CMD_INTR;
-		tx.tx_link = nopaddr;
-		tx.tx_tbdoffset = tbdaddr;
-		tbd.tbd_opts = TBD_EOL | len;
-		tbd.tbd_link = I82586_NULL;
-		tbd.tbd_bufl = dataddr;
-		tbd.tbd_bufh = 0;
-		nop.nop_status = 0;
-		nop.nop_command = CMD_NOP;
-		nop.nop_link = nopaddr;
-
-		save_flags_cli (flags);
-		ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
-		ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
-		ether1_writebuffer (dev, skb->data, dataddr, len);
-		ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
-		tmp = priv->tx_link;
-		priv->tx_link = nopaddr;
+	txaddr = ether1_txalloc (dev, TX_SIZE);
+	tbdaddr = ether1_txalloc (dev, TBD_SIZE);
+	dataddr = ether1_txalloc (dev, len);
+	nopaddr = ether1_txalloc (dev, NOP_SIZE);
+
+	tx.tx_status = 0;
+	tx.tx_command = CMD_TX | CMD_INTR;
+	tx.tx_link = nopaddr;
+	tx.tx_tbdoffset = tbdaddr;
+	tbd.tbd_opts = TBD_EOL | len;
+	tbd.tbd_link = I82586_NULL;
+	tbd.tbd_bufl = dataddr;
+	tbd.tbd_bufh = 0;
+	nop.nop_status = 0;
+	nop.nop_command = CMD_NOP;
+	nop.nop_link = nopaddr;
+
+	save_flags_cli(flags);
+	ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
+	ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
+	ether1_writebuffer (dev, skb->data, dataddr, len);
+	ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
+	tmp = priv->tx_link;
+	priv->tx_link = nopaddr;
+
+	/* now reset the previous nop pointer */
+	ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
 
-		/* now reset the previous nop pointer */
-		ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
+	restore_flags(flags);
 
-		restore_flags (flags);
-
-		/* handle transmit */
-		dev->trans_start = jiffies;
+	/* handle transmit */
+	dev->trans_start = jiffies;
 
-		/* check to see if we have room for a full sized ether frame */
-		tmp = priv->tx_head;
-		tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
-		priv->tx_head = tmp;
-		if (tst != -1)
-			dev->tbusy = 0;
-	}
+	/* check to see if we have room for a full sized ether frame */
+	tmp = priv->tx_head;
+	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+	priv->tx_head = tmp;
 	dev_kfree_skb (skb);
 
+	if (tst == -1)
+		netif_stop_queue(dev);
+
 	return 0;
 }
 
@@ -957,9 +946,7 @@
 	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
 	priv->tx_head = caddr;
 	if (tst != -1)
-		dev->tbusy = 0;
-    
-	mark_bh (NET_BH);
+		netif_wake_queue(dev);
 }
 
 static void
@@ -1024,8 +1011,6 @@
 	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	int status;
 
-	dev->interrupt = 1;
-
 	status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
 
 	if (status) {
@@ -1065,8 +1050,6 @@
 		}
 	} else
 	        outb (CTRL_ACK, REG_CONTROL);
-
-	dev->interrupt = 0;
 }
 
 static int
@@ -1076,9 +1059,6 @@
 
 	free_irq(dev->irq, dev);
 
-	dev->start = 0;
-	dev->tbusy = 0;
-
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1110,7 +1090,7 @@
 static struct ether_dev {
 	struct expansion_card	*ec;
 	char			name[9];
-	struct net_device		dev;
+	struct net_device	dev;
 } ether_devs[MAX_ECARDS];
 
 int
diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether1.h linux/drivers/acorn/net/ether1.h
--- v2.3.46/linux/drivers/acorn/net/ether1.h	Wed Aug 18 11:38:59 1999
+++ linux/drivers/acorn/net/ether1.h	Thu Feb 17 23:34:46 2000
@@ -43,13 +43,6 @@
 	unsigned char restart      : 1;
 };
 
-static int ether1_open (struct net_device *dev);
-static int ether1_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static int ether1_close (struct net_device *dev);
-static struct enet_statistics *ether1_getstats (struct net_device *dev);
-static void ether1_setmulticastlist (struct net_device *dev);
-
 #define I82586_NULL (-1)
 
 typedef struct { /* tdr */
diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c
--- v2.3.46/linux/drivers/acorn/net/ether3.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/acorn/net/ether3.c	Thu Feb 17 23:34:46 2000
@@ -36,9 +36,10 @@
  * 1.14	RMK	07/01/1998	Added initial code for ETHERB addressing.
  * 1.15	RMK	30/04/1999	More fixes to the transmit routine for buggy
  *				hardware.
+ * 1.16	RMK	10/02/2000	Updated for 2.3.43
  */
 
-static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.15\n";
+static char *version = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.16\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -74,9 +75,17 @@
 	{ 0xffff, 0xffff }
 };
 
-static void ether3_setmulticastlist(struct net_device *dev);
-static int  ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
-static void ether3_tx(struct net_device *dev, struct dev_priv *priv);
+static void	ether3_setmulticastlist(struct net_device *dev);
+static int	ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
+static void	ether3_tx(struct net_device *dev, struct dev_priv *priv);
+static int	ether3_probe1 (struct net_device *dev);
+static int	ether3_open (struct net_device *dev);
+static int	ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
+static void	ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static int	ether3_close (struct net_device *dev);
+static struct enet_statistics *ether3_getstats (struct net_device *dev);
+static void	ether3_setmulticastlist (struct net_device *dev);
+static void	ether3_timeout(struct net_device *dev);
 
 #define BUS_16		2
 #define BUS_8		1
@@ -406,6 +415,7 @@
 	static unsigned version_printed = 0;
 	struct dev_priv *priv;
 	unsigned int i, bus_type, error = ENODEV;
+	const char *name = "ether3";
 
 	if (net_debug && version_printed++ == 0)
 		printk(version);
@@ -421,7 +431,7 @@
 	priv = (struct dev_priv *) dev->priv;
 	memset(priv, 0, sizeof(struct dev_priv));
 
-	request_region(dev->base_addr, 128, "ether3");
+	request_region(dev->base_addr, 128, name);
 
 	/* Reset card...
 	 */
@@ -443,33 +453,38 @@
 
 	switch (bus_type) {
 	case BUS_UNKNOWN:
-		printk(KERN_ERR "%s: unable to identify podule bus width\n", dev->name);
+		printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
 		goto failed;
 
 	case BUS_8:
-		printk(KERN_ERR "%s: ether3 found, but is an unsupported 8-bit card\n", dev->name);
+		printk(KERN_ERR "%s: %s found, but is an unsupported "
+			"8-bit card\n", dev->name, name);
 		goto failed;
 
 	default:
 		break;
 	}
 
-	printk("%s: ether3 found at %lx, IRQ%d, ether address ", dev->name, dev->base_addr, dev->irq);
+	printk("%s: %s at %lx, IRQ%d, ether address ",
+		dev->name, name, dev->base_addr, dev->irq);
 	for (i = 0; i < 6; i++)
 		printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]);
 
-	if (!ether3_init_2(dev)) {
-		dev->open = ether3_open;
-		dev->stop = ether3_close;
-		dev->hard_start_xmit = ether3_sendpacket;
-		dev->get_stats = ether3_getstats;
-		dev->set_multicast_list = ether3_setmulticastlist;
+	if (ether3_init_2(dev))
+		goto failed;
 
-		/* Fill in the fields of the device structure with ethernet values. */
-		ether_setup(dev);
+	dev->open		= ether3_open;
+	dev->stop		= ether3_close;
+	dev->hard_start_xmit	= ether3_sendpacket;
+	dev->get_stats		= ether3_getstats;
+	dev->set_multicast_list	= ether3_setmulticastlist;
+	dev->tx_timeout		= ether3_timeout;
+	dev->watchdog_timeo	= 5 * HZ / 100;
 
-		return 0;
-	}
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	return 0;
 
 failed:
 	kfree(dev->priv);
@@ -535,12 +550,10 @@
 		return -EAGAIN;
 	}
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
 	ether3_init_for_open(dev);
 
+	netif_start_queue(dev);
+
 	return 0;
 }
 
@@ -552,8 +565,7 @@
 {
 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 
-	dev->tbusy = 1;
-	dev->start = 0;
+	netif_stop_queue(dev);
 
 	disable_irq(dev->irq);
 
@@ -602,6 +614,34 @@
 	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
 }
 
+static void
+ether3_timeout(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned long flags;
+
+	del_timer(&priv->timer);
+
+	save_flags_cli(flags);
+	printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
+	printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name,
+		ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
+	printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
+		ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
+	printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
+		priv->tx_head, priv->tx_tail);
+	ether3_setbuffer(dev, buffer_read, priv->tx_tail);
+	printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
+	restore_flags(flags);
+
+	priv->regs.config2 |= CFG2_CTRLO;
+	priv->stats.tx_errors += 1;
+	ether3_outw(priv->regs.config2, REG_CONFIG2);
+	priv->tx_head = priv->tx_tail = 0;
+
+	netif_wake_queue(dev);
+}
+
 /*
  * Transmit a packet
  */
@@ -609,102 +649,61 @@
 ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-retry:
-	if (!dev->tbusy) {
-		/* 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)) {
-			unsigned long flags;
-			unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-			unsigned int ptr, next_ptr;
-
-			length = (length + 1) & ~1;
-
-			if (priv->broken) {
-				dev_kfree_skb(skb);
-				priv->stats.tx_dropped ++;
-				dev->tbusy = 0;
-				return 0;
-			}
+	unsigned long flags;
+	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned int ptr, next_ptr;
+
+	length = (length + 1) & ~1;
+
+	if (priv->broken) {
+		dev_kfree_skb(skb);
+		priv->stats.tx_dropped ++;
+		netif_start_queue(dev);
+		return 0;
+	}
 
-			next_ptr = (priv->tx_head + 1) & 15;
+	next_ptr = (priv->tx_head + 1) & 15;
 
-			save_flags_cli(flags);
+	save_flags_cli(flags);
 
-			if (priv->tx_tail == next_ptr) {
-				restore_flags(flags);
-				return 1;	/* unable to queue */
-			}
+	if (priv->tx_tail == next_ptr) {
+		restore_flags(flags);
+		return 1;	/* unable to queue */
+	}
 
-			dev->trans_start = jiffies;
-			ptr		 = 0x600 * priv->tx_head;
-			priv->tx_head	 = next_ptr;
-			next_ptr	*= 0x600;
+	dev->trans_start = jiffies;
+	ptr		 = 0x600 * priv->tx_head;
+	priv->tx_head	 = next_ptr;
+	next_ptr	*= 0x600;
 
 #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
 
-			ether3_setbuffer(dev, buffer_write, next_ptr);
-			ether3_writelong(dev, 0);
-			ether3_setbuffer(dev, buffer_write, ptr);
-			ether3_writelong(dev, 0);
-			ether3_writebuffer(dev, skb->data, length);
-			ether3_writeword(dev, htons(next_ptr));
-			ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
-			ether3_setbuffer(dev, buffer_write, ptr);
-			ether3_writeword(dev, htons((ptr + length + 4)));
-			ether3_writeword(dev, TXHDR_FLAGS >> 16);
-			ether3_ledon(dev, priv);
-
-			if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
-				ether3_outw(ptr, REG_TRANSMITPTR);
-				ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
-			}
-
-			next_ptr = (priv->tx_head + 1) & 15;
-			if (priv->tx_tail != next_ptr)
-				dev->tbusy = 0;
-
-			restore_flags(flags);
+	ether3_setbuffer(dev, buffer_write, next_ptr);
+	ether3_writelong(dev, 0);
+	ether3_setbuffer(dev, buffer_write, ptr);
+	ether3_writelong(dev, 0);
+	ether3_writebuffer(dev, skb->data, length);
+	ether3_writeword(dev, htons(next_ptr));
+	ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
+	ether3_setbuffer(dev, buffer_write, ptr);
+	ether3_writeword(dev, htons((ptr + length + 4)));
+	ether3_writeword(dev, TXHDR_FLAGS >> 16);
+	ether3_ledon(dev, priv);
 
-			dev_kfree_skb(skb);
+	if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
+		ether3_outw(ptr, REG_TRANSMITPTR);
+		ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
+	}
 
-			return 0;
-		} else {
-			printk("%s: transmitter access conflict.\n", dev->name);
-			return 1;
-		}
-	} else {
-		/* If we get here, some higher level has decided we are broken.
-		 * There should really be a "kick me" function call instead.
-		 */
-		int tickssofar = jiffies - dev->trans_start;
-		unsigned long flags;
+	next_ptr = (priv->tx_head + 1) & 15;
+	restore_flags(flags);
 
-		if (tickssofar < 5)
-			return 1;
-		del_timer(&priv->timer);
+	dev_kfree_skb(skb);
 
-		save_flags_cli(flags);
-		printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
-		printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name,
-			ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
-		printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
-			ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
-		printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
-			priv->tx_head, priv->tx_tail);
-		ether3_setbuffer(dev, buffer_read, priv->tx_tail);
-		printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
-		restore_flags(flags);
+	if (priv->tx_tail == next_ptr)
+		netif_stop_queue(dev);
 
-		dev->tbusy = 0;
-		priv->regs.config2 |= CFG2_CTRLO;
-		priv->stats.tx_errors += 1;
-		ether3_outw(priv->regs.config2, REG_CONFIG2);
-		dev->trans_start = jiffies;
-		priv->tx_head = priv->tx_tail = 0;
-		goto retry;
-	}
+	return 0;
 }
 
 static void
@@ -721,8 +720,6 @@
 
 	priv = (struct dev_priv *)dev->priv;
 
-	dev->interrupt = 1;
-
 	status = ether3_inw(REG_STATUS);
 
 	if (status & STAT_INTRX) {
@@ -735,8 +732,6 @@
 		ether3_tx(dev, priv);
 	}
 
-	dev->interrupt = 0;
-
 #if NET_DEBUG > 1
 	if(net_debug & DEBUG_INT)
 		printk("done\n");
@@ -904,8 +899,7 @@
 
 	if (priv->tx_tail != tx_tail) {
 		priv->tx_tail = tx_tail;
-		dev->tbusy = 0;
-		mark_bh(NET_BH);	/* Inform upper layers. */
+		netif_wake_queue(dev);
 	}
 }
 
@@ -914,7 +908,7 @@
 static struct ether_dev {
 	struct expansion_card	*ec;
 	char			name[9];
-	struct net_device		dev;
+	struct net_device	dev;
 } ether_devs[MAX_ECARDS];
 
 int
diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether3.h linux/drivers/acorn/net/ether3.h
--- v2.3.46/linux/drivers/acorn/net/ether3.h	Wed Aug 18 11:38:59 1999
+++ linux/drivers/acorn/net/ether3.h	Thu Feb 17 23:34:46 2000
@@ -159,13 +159,4 @@
     int broken;				/* 0 = ok, 1 = something went wrong	 */
 };
 
-extern int	ether3_probe (struct net_device *dev);
-static int	ether3_probe1 (struct net_device *dev);
-static int	ether3_open (struct net_device *dev);
-static int	ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void	ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static int	ether3_close (struct net_device *dev);
-static struct enet_statistics *ether3_getstats (struct net_device *dev);
-static void	ether3_setmulticastlist (struct net_device *dev);
-
 #endif
diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c
--- v2.3.46/linux/drivers/acorn/net/etherh.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/acorn/net/etherh.c	Thu Feb 17 23:34:46 2000
@@ -13,6 +13,7 @@
  *		RMK	1.03	Added support for EtherLan500 cards
  *  23-11-1997	RMK	1.04	Added media autodetection
  *  16-04-1998	RMK	1.05	Improved media autodetection
+ *  10-02-2000	RMK	1.06	Updated for 2.3.43
  *
  * Insmod Module Parameters
  * ------------------------
@@ -61,7 +62,7 @@
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("i3 EtherH driver");
 
-static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n";
+static char *version = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.06\n";
 
 #define ETHERH500_DATAPORT	0x200	/* MEMC */
 #define ETHERH500_NS8390	0x000	/* MEMC */
@@ -190,8 +191,8 @@
 	
 	if (ei_status.dmaing) {
 		printk ("%s: DMAing conflict in etherh_block_input: "
-			" DMAstat %d irqlock %d intr %ld\n", dev->name,
-			ei_status.dmaing, ei_status.irqlock, dev->interrupt);
+			" DMAstat %d irqlock %d\n", dev->name,
+			ei_status.dmaing, ei_status.irqlock);
 		return;
 	}
 
@@ -248,8 +249,8 @@
 
 	if (ei_status.dmaing) {
 		printk ("%s: DMAing conflict in etherh_block_input: "
-			" DMAstat %d irqlock %d intr %ld\n", dev->name,
-			ei_status.dmaing, ei_status.irqlock, dev->interrupt);
+			" DMAstat %d irqlock %d\n", dev->name,
+			ei_status.dmaing, ei_status.irqlock);
 		return;
 	}
 
@@ -287,8 +288,8 @@
 
 	if (ei_status.dmaing) {
 		printk ("%s: DMAing conflict in etherh_get_header: "
-			" DMAstat %d irqlock %d intr %ld\n", dev->name,
-			ei_status.dmaing, ei_status.irqlock, dev->interrupt);
+			" DMAstat %d irqlock %d\n", dev->name,
+			ei_status.dmaing, ei_status.irqlock);
 		return;
 	}
 
@@ -359,6 +360,7 @@
 	unsigned int addr, i, reg0, tmp;
 	const char *dev_type;
 	const char *if_type;
+	const char *name = "etherh";
 
 	addr = dev->base_addr;
 
@@ -367,13 +369,13 @@
 
 	switch (dev->mem_end) {
 	case PROD_I3_ETHERLAN500:
-		dev_type = "500 ";
+		dev_type = "500";
 		break;
 	case PROD_I3_ETHERLAN600:
-		dev_type = "600 ";
+		dev_type = "600";
 		break;
 	case PROD_I3_ETHERLAN600A:
-		dev_type = "600A ";
+		dev_type = "600A";
 		break;
 	default:
 		dev_type = "";
@@ -382,7 +384,8 @@
 	reg0 = inb (addr);
 	if (reg0 == 0xff) {
 		if (net_debug & DEBUG_INIT)
-			printk ("%s: etherh error: NS8390 command register wrong\n", dev->name);
+			printk("%s: %s error: NS8390 command register wrong\n",
+				dev->name, name);
 		return -ENODEV;
 	}
 
@@ -393,34 +396,35 @@
 	inb (addr + EN0_COUNTER0);
 	if (inb (addr + EN0_COUNTER0) != 0) {
 		if (net_debug & DEBUG_INIT)
-			printk ("%s: etherh error: NS8390 not found\n", dev->name);
+			printk("%s: %s error: NS8390 not found\n",
+				dev->name, name);
 		outb (reg0, addr);
 		outb (tmp, addr + 13);
 		return -ENODEV;
 	}
 
-	if (ethdev_init (dev))
+	if (ethdev_init(dev))
 		return -ENOMEM;
 
-	request_region (addr, 16, "etherh");
+	request_region(addr, 16, name);
 
-	printk("%s: etherh %sfound at %lx, IRQ%d, ether address ",
-		dev->name, dev_type, dev->base_addr, dev->irq);
+	printk("%s: %s %s at %lx, IRQ%d, ether address ",
+		dev->name, name, dev_type, dev->base_addr, dev->irq);
 
 	for (i = 0; i < 6; i++)
 		printk (i == 5 ? "%2.2x " : "%2.2x:", dev->dev_addr[i]);
 
-	ei_status.name = "etherh";
-	ei_status.word16 = 1;
-	ei_status.tx_start_page = ETHERH_TX_START_PAGE;
-	ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES;
-	ei_status.stop_page = ETHERH_STOP_PAGE;
-	ei_status.reset_8390 = etherh_reset;
-	ei_status.block_input = etherh_block_input;
-	ei_status.block_output = etherh_block_output;
-	ei_status.get_8390_hdr = etherh_get_header;
-	dev->open = etherh_open;
-	dev->stop = etherh_close;
+	ei_status.name		= name;
+	ei_status.word16	= 1;
+	ei_status.tx_start_page	= ETHERH_TX_START_PAGE;
+	ei_status.rx_start_page	= ei_status.tx_start_page + TX_PAGES;
+	ei_status.stop_page	= ETHERH_STOP_PAGE;
+	ei_status.reset_8390	= etherh_reset;
+	ei_status.block_input	= etherh_block_input;
+	ei_status.block_output	= etherh_block_output;
+	ei_status.get_8390_hdr	= etherh_get_header;
+	dev->open		= etherh_open;
+	dev->stop		= etherh_close;
 
 	/* select 10bT */
 	ei_status.interface_num = 0;
@@ -567,7 +571,8 @@
 		my_ethers[i] = dev;
 
 		if (register_netdev(dev) != 0) {
-			printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr);
+			printk(KERN_ERR "No etherh card found at %08lX\n",
+				dev->base_addr);
 			if (ec[i]) {
 				ecard_release(ec[i]);
 				ec[i] = NULL;
diff -u --recursive --new-file v2.3.46/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.3.46/linux/drivers/block/DAC960.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/DAC960.c	Thu Feb 17 09:26:31 2000
@@ -2589,8 +2589,8 @@
 		      (long *) Argument);
     case BLKRAGET:
       /* Get Read-Ahead. */
-      if ((int *) Argument == NULL) return -EINVAL;
-      return put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument);
+      if ((long *) Argument == NULL) return -EINVAL;
+      return put_user(read_ahead[MAJOR(Inode->i_rdev)], (long *) Argument);
     case BLKRASET:
       /* Set Read-Ahead. */
       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
diff -u --recursive --new-file v2.3.46/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.46/linux/drivers/block/Makefile	Thu Feb 10 17:11:06 2000
+++ linux/drivers/block/Makefile	Thu Feb 17 16:13:04 2000
@@ -326,6 +326,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_BLK_DEV_LVM),y)
+L_OBJS += lvm.o lvm-snap.o
+else
+   ifeq ($(CONFIG_BLK_DEV_LVM),m)
+   M_OBJS += lvm-mod.o
+   endif
+endif
+
 ifeq ($(CONFIG_BLK_DEV_MD),y)
 LX_OBJS += md.o
 
@@ -354,13 +362,9 @@
 endif
 
 ifeq ($(CONFIG_MD_RAID5),y)
-LX_OBJS += xor.o
-CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer
 L_OBJS += raid5.o
 else
   ifeq ($(CONFIG_MD_RAID5),m)
-  LX_OBJS += xor.o
-  CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer
   M_OBJS += raid5.o
   endif
 endif
@@ -407,3 +411,6 @@
 
 ide-probe-mod.o: ide-probe.o ide-geometry.o
 	$(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
+
+lvm-mod.o:	lvm.o lvm-snap.o
+	$(LD) -r -o $@ lvm.o lvm-snap.o
diff -u --recursive --new-file v2.3.46/linux/drivers/block/README.lvm linux/drivers/block/README.lvm
--- v2.3.46/linux/drivers/block/README.lvm	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/README.lvm	Thu Feb 17 16:13:04 2000
@@ -0,0 +1,8 @@
+
+This is the Logical Volume Manager driver for Linux,
+
+Tools, library that manage logical volumes can be found
+at <http://linux.msede.com/lvm>.
+
+There you can obtain actual driver versions too.
+
diff -u --recursive --new-file v2.3.46/linux/drivers/block/icside.c linux/drivers/block/icside.c
--- v2.3.46/linux/drivers/block/icside.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/block/icside.c	Thu Feb 17 23:34:46 2000
@@ -24,6 +24,8 @@
 #include <asm/ecard.h>
 #include <asm/io.h>
 
+extern char *ide_xfer_verbose (byte xfer_rate);
+
 /*
  * Maximum number of interfaces per card
  */
diff -u --recursive --new-file v2.3.46/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.3.46/linux/drivers/block/ide-dma.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/block/ide-dma.c	Fri Feb 18 15:07:20 2000
@@ -214,6 +214,10 @@
 	struct scatterlist *sg = hwif->sg_table;
 	int nents = 0;
 
+	if (rq->cmd == READ)
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
 	bh = rq->bh;
 	do {
 		unsigned char *virt_addr = bh->b_data;
@@ -230,7 +234,7 @@
 		nents++;
 	} while (bh != NULL);
 
-	return pci_map_sg(hwif->pci_dev, sg, nents);
+	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
 /*
@@ -265,7 +269,8 @@
 				printk("%s: DMA table too small\n", drive->name);
 				pci_unmap_sg(HWIF(drive)->pci_dev,
 					     HWIF(drive)->sg_table,
-					     HWIF(drive)->sg_nents);
+					     HWIF(drive)->sg_nents,
+					     HWIF(drive)->sg_dma_direction);
 				return 0; /* revert to PIO for this request */
 			} else {
 				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
@@ -301,7 +306,7 @@
 	struct scatterlist *sg = HWIF(drive)->sg_table;
 	int nents = HWIF(drive)->sg_nents;
 
-	pci_unmap_sg(dev, sg, nents);
+	pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
 }
 
 /*
diff -u --recursive --new-file v2.3.46/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.3.46/linux/drivers/block/ide-probe.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/ide-probe.c	Thu Feb 17 23:59:57 2000
@@ -406,7 +406,7 @@
 	ide_ioreg_t ide_control_reg 	= hwif->io_ports[IDE_CONTROL_OFFSET];
 	ide_ioreg_t region_low 		= hwif->io_ports[IDE_DATA_OFFSET];
 	ide_ioreg_t region_high 	= region_low;
-	ide_ioreg_t region_request	= 8;
+	unsigned int region_request	= 8;
 	int i;
 
 	if (hwif->noprobe)
diff -u --recursive --new-file v2.3.46/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.46/linux/drivers/block/ll_rw_blk.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/ll_rw_blk.c	Sun Feb 20 20:26:10 2000
@@ -253,7 +253,7 @@
 	INIT_LIST_HEAD(&q->queue_head);
 	q->elevator = ELEVATOR_DEFAULTS;
 	q->request_fn     	= rfn;
-	q->back_merges_fn       	= ll_back_merge_fn;
+	q->back_merge_fn       	= ll_back_merge_fn;
 	q->front_merge_fn      	= ll_front_merge_fn;
 	q->merge_requests_fn	= ll_merge_requests_fn;
 	q->make_request_fn	= NULL;
@@ -469,22 +469,17 @@
 #define elevator_merge_after(q, req, lat)	__elevator_merge((q), (req), (lat), 1)
 static inline void __elevator_merge(request_queue_t * q, struct request * req, int latency, int after)
 {
-#ifdef DEBUG_ELEVATOR
 	int sequence = elevator_sequence(&q->elevator, latency);
 	if (after)
 		sequence -= req->nr_segments;
 	if (elevator_sequence_before(sequence, req->elevator_sequence)) {
-		static int warned = 0;
-		if (!warned) {
+		if (!after)
 			printk(KERN_WARNING __FUNCTION__
 			       ": req latency %d req latency %d\n",
 			       req->elevator_sequence - q->elevator.sequence,
 			       sequence - q->elevator.sequence);
-			warned = 1;
-		}
 		req->elevator_sequence = sequence;
 	}
-#endif
 }
 
 static inline void elevator_queue(request_queue_t * q,
@@ -679,7 +674,7 @@
 	int rw_ahead, max_req, max_sectors;
 	unsigned long flags;
 	int orig_latency, latency, __latency, starving, __starving, empty;
-	struct list_head * entry, * __entry;
+	struct list_head * entry, * __entry = NULL;
 
 	count = bh->b_size >> 9;
 	sector = bh->b_rsector;
@@ -1241,4 +1236,5 @@
 EXPORT_SYMBOL(blk_cleanup_queue);
 EXPORT_SYMBOL(blk_queue_headactive);
 EXPORT_SYMBOL(blk_queue_pluggable);
+EXPORT_SYMBOL(blk_queue_make_request);
 EXPORT_SYMBOL(generic_make_request);
diff -u --recursive --new-file v2.3.46/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.46/linux/drivers/block/loop.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/loop.c	Sun Feb 20 13:11:38 2000
@@ -377,13 +377,13 @@
 	spin_lock_irq(&io_request_lock);
 	current_request->sector += current_request->current_nr_sectors;
 	current_request->nr_sectors -= current_request->current_nr_sectors;
-	list_add(&current_request->queue, &current_request->q->queue_head);
+	list_add(&current_request->queue, &q->queue_head);
 	end_request(1);
 	goto repeat;
 error_out_lock:
 	spin_lock_irq(&io_request_lock);
 error_out:
-	list_add(&current_request->queue, &current_request->q->queue_head);
+	list_add(&current_request->queue, &q->queue_head);
 	end_request(0);
 	goto repeat;
 }
diff -u --recursive --new-file v2.3.46/linux/drivers/block/lvm-snap.c linux/drivers/block/lvm-snap.c
--- v2.3.46/linux/drivers/block/lvm-snap.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/lvm-snap.c	Thu Feb 17 16:13:05 2000
@@ -0,0 +1,434 @@
+/*
+ * kernel/lvm-snap.c
+ *
+ * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ *
+ * LVM snapshot driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * LVM driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/blkdev.h>
+#include <linux/smp_lock.h>
+#include <linux/types.h>
+#include <linux/iobuf.h>
+#include <linux/lvm.h>
+
+
+static char *lvm_snap_version = "LVM 0.8final (15/02/2000)\n";
+
+extern const char *const lvm_name;
+extern int lvm_blocksizes[];
+
+void lvm_snapshot_release(lv_t *);
+
+#define hashfn(dev,block,mask,chunk_size) \
+	((HASHDEV(dev)^((block)/(chunk_size))) & (mask))
+
+static inline lv_block_exception_t *
+lvm_find_exception_table(kdev_t org_dev, unsigned long org_start, lv_t * lv)
+{
+	struct list_head * hash_table = lv->lv_snapshot_hash_table, * next;
+	unsigned long mask = lv->lv_snapshot_hash_mask;
+	int chunk_size = lv->lv_chunk_size;
+	lv_block_exception_t * ret;
+	int i = 0;
+
+	hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
+	ret = NULL;
+	for (next = hash_table->next; next != hash_table; next = next->next)
+	{
+		lv_block_exception_t * exception;
+
+		exception = list_entry(next, lv_block_exception_t, hash);
+		if (exception->rsector_org == org_start &&
+		    exception->rdev_org == org_dev)
+		{
+			if (i)
+			{
+				/* fun, isn't it? :) */
+				list_del(next);
+				list_add(next, hash_table);
+			}
+			ret = exception;
+			break;
+		}
+		i++;
+	}
+	return ret;
+}
+
+static inline void lvm_hash_link(lv_block_exception_t * exception,
+				 kdev_t org_dev, unsigned long org_start,
+				 lv_t * lv)
+{
+	struct list_head * hash_table = lv->lv_snapshot_hash_table;
+	unsigned long mask = lv->lv_snapshot_hash_mask;
+	int chunk_size = lv->lv_chunk_size;
+
+	hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
+	list_add(&exception->hash, hash_table);
+}
+
+int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector,
+			     unsigned long pe_start, lv_t * lv)
+{
+	int ret;
+	unsigned long pe_off, pe_adjustment, __org_start;
+	kdev_t __org_dev;
+	int chunk_size = lv->lv_chunk_size;
+	lv_block_exception_t * exception;
+
+	pe_off = pe_start % chunk_size;
+	pe_adjustment = (*org_sector-pe_off) % chunk_size;
+	__org_start = *org_sector - pe_adjustment;
+	__org_dev = *org_dev;
+
+	ret = 0;
+	exception = lvm_find_exception_table(__org_dev, __org_start, lv);
+	if (exception)
+	{
+		*org_dev = exception->rdev_new;
+		*org_sector = exception->rsector_new + pe_adjustment;
+		ret = 1;
+	}
+	return ret;
+}
+
+static void lvm_drop_snapshot(lv_t * lv_snap, const char * reason)
+{
+	kdev_t last_dev;
+	int i;
+
+	/* no exception storage space available for this snapshot
+	   or error on this snapshot --> release it */
+	invalidate_buffers(lv_snap->lv_dev);
+
+	for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) {
+		if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) {
+			last_dev = lv_snap->lv_block_exception[i].rdev_new;
+			invalidate_buffers(last_dev);
+		}
+	}
+
+	lvm_snapshot_release(lv_snap);
+
+	printk(KERN_INFO
+	       "%s -- giving up to snapshot %s on %s due %s\n",
+	       lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name,
+	       reason);
+}
+
+static inline void lvm_snapshot_prepare_blocks(unsigned long * blocks,
+					       unsigned long start,
+					       int nr_sectors,
+					       int blocksize)
+{
+	int i, sectors_per_block, nr_blocks;
+
+	sectors_per_block = blocksize >> 9;
+	nr_blocks = nr_sectors / sectors_per_block;
+	start /= sectors_per_block;
+
+	for (i = 0; i < nr_blocks; i++)
+		blocks[i] = start++;
+}
+
+static inline int get_blksize(kdev_t dev)
+{
+	int correct_size = BLOCK_SIZE, i, major;
+
+	major = MAJOR(dev);
+	if (blksize_size[major])
+	{
+		i = blksize_size[major][MINOR(dev)];
+		if (i)
+			correct_size = i;
+	}
+	return correct_size;
+}
+
+#ifdef DEBUG_SNAPSHOT
+static inline void invalidate_snap_cache(unsigned long start, unsigned long nr,
+					 kdev_t dev)
+{
+	struct buffer_head * bh;
+	int sectors_per_block, i, blksize, minor;
+
+	minor = MINOR(dev);
+	blksize = lvm_blocksizes[minor];
+	sectors_per_block = blksize >> 9;
+	nr /= sectors_per_block;
+	start /= sectors_per_block;
+
+	for (i = 0; i < nr; i++)
+	{
+		bh = get_hash_table(dev, start++, blksize);
+		if (bh)
+			bforget(bh);
+	}
+}
+#endif
+
+/*
+ * copy on write handler for one snapshot logical volume
+ *
+ * read the original blocks and store it/them on the new one(s).
+ * if there is no exception storage space free any longer --> release snapshot.
+ *
+ * this routine gets called for each _first_ write to a physical chunk.
+ */
+int lvm_snapshot_COW(kdev_t org_phys_dev,
+		     unsigned long org_phys_sector,
+		     unsigned long org_pe_start,
+		     unsigned long org_virt_sector,
+		     lv_t * lv_snap)
+{
+	const char * reason;
+	unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off;
+	int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size;
+	struct kiobuf * iobuf;
+	unsigned long blocks[KIO_MAX_SECTORS];
+	int blksize_snap, blksize_org, min_blksize, max_blksize;
+	int max_sectors, nr_sectors;
+
+	/* check if we are out of snapshot space */
+	if (idx >= lv_snap->lv_remap_end)
+		goto fail_out_of_space;
+
+	/* calculate physical boundaries of source chunk */
+	pe_off = org_pe_start % chunk_size;
+	org_start = org_phys_sector - ((org_phys_sector-pe_off) % chunk_size);
+	virt_start = org_virt_sector - (org_phys_sector - org_start);
+
+	/* calculate physical boundaries of destination chunk */
+	snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
+	snap_start = lv_snap->lv_block_exception[idx].rsector_new;
+
+#ifdef DEBUG_SNAPSHOT
+	printk(KERN_INFO
+	       "%s -- COW: "
+	       "org %02d:%02d faulting %lu start %lu, "
+	       "snap %02d:%02d start %lu, "
+	       "size %d, pe_start %lu pe_off %lu, virt_sec %lu\n",
+	       lvm_name,
+	       MAJOR(org_phys_dev), MINOR(org_phys_dev), org_phys_sector,
+	       org_start,
+	       MAJOR(snap_phys_dev), MINOR(snap_phys_dev), snap_start,
+	       chunk_size,
+	       org_pe_start, pe_off,
+	       org_virt_sector);
+#endif
+
+	iobuf = lv_snap->lv_iobuf;
+
+	blksize_org = get_blksize(org_phys_dev);
+	blksize_snap = get_blksize(snap_phys_dev);
+	max_blksize = max(blksize_org, blksize_snap);
+	min_blksize = min(blksize_org, blksize_snap);
+	max_sectors = KIO_MAX_SECTORS * (min_blksize>>9);
+
+	if (chunk_size % (max_blksize>>9))
+		goto fail_blksize;
+
+	while (chunk_size)
+	{
+		nr_sectors = min(chunk_size, max_sectors);
+		chunk_size -= nr_sectors;
+
+		iobuf->length = nr_sectors << 9;
+
+		lvm_snapshot_prepare_blocks(blocks, org_start,
+					    nr_sectors, blksize_org);
+		if (brw_kiovec(READ, 1, &iobuf, org_phys_dev,
+			       blocks, blksize_org) != (nr_sectors<<9))
+			goto fail_raw_read;
+
+		lvm_snapshot_prepare_blocks(blocks, snap_start,
+					    nr_sectors, blksize_snap);
+		if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev,
+			       blocks, blksize_snap) != (nr_sectors<<9))
+			goto fail_raw_write;
+	}
+
+#ifdef DEBUG_SNAPSHOT
+	/* invalidate the logcial snapshot buffer cache */
+	invalidate_snap_cache(virt_start, lv_snap->lv_chunk_size,
+			      lv_snap->lv_dev);
+#endif
+
+	/* the original chunk is now stored on the snapshot volume
+	   so update the execption table */
+	lv_snap->lv_block_exception[idx].rdev_org = org_phys_dev;
+	lv_snap->lv_block_exception[idx].rsector_org = org_start;
+	lvm_hash_link(lv_snap->lv_block_exception + idx,
+		      org_phys_dev, org_start, lv_snap);
+	lv_snap->lv_remap_ptr = idx + 1;
+	return 0;
+
+	/* slow path */
+ out:
+	lvm_drop_snapshot(lv_snap, reason);
+	return 1;
+
+ fail_out_of_space:
+	reason = "out of space";
+	goto out;
+ fail_raw_read:
+	reason = "read error";
+	goto out;
+ fail_raw_write:
+	reason = "write error";
+	goto out;
+ fail_blksize:
+	reason = "blocksize error";
+	goto out;
+}
+
+static int lvm_snapshot_alloc_iobuf_pages(struct kiobuf * iobuf, int sectors)
+{
+	int bytes, nr_pages, err, i;
+
+	bytes = sectors << 9;
+	nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT;
+	err = expand_kiobuf(iobuf, nr_pages);
+	if (err)
+		goto out;
+
+	err = -ENOMEM;
+	iobuf->locked = 1;
+	iobuf->nr_pages = 0;
+	for (i = 0; i < nr_pages; i++)
+	{
+		struct page * page;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)
+		page = alloc_page(GFP_KERNEL);
+		if (!page)
+			goto out;
+#else
+		{
+			unsigned long addr = __get_free_page(GFP_USER);
+			if (!addr)
+				goto out;
+			iobuf->pagelist[i] = addr;
+			page = mem_map + MAP_NR(addr);
+		}
+#endif
+
+		iobuf->maplist[i] = page;
+		/* the only point to lock the page here is to be allowed
+		   to share unmap_kiobuf() in the fail-path */
+#ifndef LockPage
+#define LockPage(map) set_bit(PG_locked, &(map)->flags)
+#endif
+		LockPage(page);
+		iobuf->nr_pages++;
+	}
+	iobuf->offset = 0;
+
+	err = 0;
+ out:
+	return err;
+}
+
+static int calc_max_buckets(void)
+{
+	unsigned long mem;
+
+	mem = num_physpages << PAGE_SHIFT;
+	mem /= 100;
+	mem *= 2;
+	mem /= sizeof(struct list_head);
+
+	return mem;
+}
+
+static int lvm_snapshot_alloc_hash_table(lv_t * lv)
+{
+	int err;
+	unsigned long buckets, max_buckets, size;
+	struct list_head * hash;
+
+	buckets = lv->lv_remap_end;
+	max_buckets = calc_max_buckets();
+	buckets = min(buckets, max_buckets);
+	while (buckets & (buckets-1))
+		buckets &= (buckets-1);
+
+	size = buckets * sizeof(struct list_head);
+
+	err = -ENOMEM;
+	hash = vmalloc(size);
+	lv->lv_snapshot_hash_table = hash;
+
+	if (!hash)
+		goto out;
+
+	lv->lv_snapshot_hash_mask = buckets-1;
+	while (buckets--)
+		INIT_LIST_HEAD(hash+buckets);
+	err = 0;
+ out:
+	return err;
+}
+
+int lvm_snapshot_alloc(lv_t * lv_snap)
+{
+	int err, blocksize, max_sectors;
+
+	err = alloc_kiovec(1, &lv_snap->lv_iobuf);
+	if (err)
+		goto out;
+
+	blocksize = lvm_blocksizes[MINOR(lv_snap->lv_dev)];
+	max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9);
+
+	err = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors);
+	if (err)
+		goto out_free_kiovec;
+
+	err = lvm_snapshot_alloc_hash_table(lv_snap);
+	if (err)
+		goto out_free_kiovec;
+ out:
+	return err;
+
+ out_free_kiovec:
+	unmap_kiobuf(lv_snap->lv_iobuf);
+	free_kiovec(1, &lv_snap->lv_iobuf);
+	goto out;
+}
+
+void lvm_snapshot_release(lv_t * lv)
+{
+	if (lv->lv_block_exception)
+	{
+		vfree(lv->lv_block_exception);
+		lv->lv_block_exception = NULL;
+	}
+	if (lv->lv_snapshot_hash_table)
+	{
+		vfree(lv->lv_snapshot_hash_table);
+		lv->lv_snapshot_hash_table = NULL;
+	}
+	if (lv->lv_iobuf)
+	{
+		free_kiovec(1, &lv->lv_iobuf);
+		lv->lv_iobuf = NULL;
+	}
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/block/lvm.c linux/drivers/block/lvm.c
--- v2.3.46/linux/drivers/block/lvm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/lvm.c	Thu Feb 17 16:13:05 2000
@@ -0,0 +1,2556 @@
+/*
+ * kernel/lvm.c
+ *
+ * Copyright (C) 1997 - 2000  Heinz Mauelshagen, Germany
+ *
+ * February-November 1997
+ * April-May,July-August,November 1998
+ * January-March,May,July,September,October 1999
+ * January,February 2000
+ *
+ *
+ * LVM driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * LVM driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ *
+ */
+
+/*
+ * Changelog
+ *
+ *    09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT
+ *                 and VG_STATUS_GET_NAMELIST
+ *    18/01/1998 - change lvm_chr_open/close lock handling
+ *    30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and
+ *               - added   LV_STATUS_BYINDEX ioctl
+ *               - used lvm_status_byname_req_t and
+ *                      lvm_status_byindex_req_t vars
+ *    04/05/1998 - added multiple device support
+ *    08/05/1998 - added support to set/clear extendable flag in volume group
+ *    09/05/1998 - changed output of lvm_proc_get_info() because of
+ *                 support for free (eg. longer) logical volume names
+ *    12/05/1998 - added spin_locks (thanks to Pascal van Dam
+ *                 <pascal@ramoth.xs4all.nl>)
+ *    25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl()
+ *    26/05/1998 - reactivated verify_area by access_ok
+ *    07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go
+ *                 beyond 128/256 KB max allocation limit per call
+ *               - #ifdef blocked spin_lock calls to avoid compile errors
+ *                 with 2.0.x
+ *    11/06/1998 - another enhancement to spinlock code in lvm_chr_open()
+ *                 and use of LVM_VERSION_CODE instead of my own macros
+ *                 (thanks to  Michael Marxmeier <mike@msede.com>)
+ *    07/07/1998 - added statistics in lvm_map()
+ *    08/07/1998 - saved statistics in lvm_do_lv_extend_reduce()
+ *    25/07/1998 - used __initfunc macro
+ *    02/08/1998 - changes for official char/block major numbers
+ *    07/08/1998 - avoided init_module() and cleanup_module() to be static
+ *    30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters
+ *                 to sum of LVs open (no matter how often each is)
+ *    01/09/1998 - fixed lvm_gendisk.part[] index error
+ *    07/09/1998 - added copying of lv_current_pe-array
+ *                 in LV_STATUS_BYINDEX ioctl
+ *    17/11/1998 - added KERN_* levels to printk
+ *    13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename
+ *    07/02/1999 - fixed spinlock handling bug in case of LVM_RESET
+ *                 by moving spinlock code from lvm_chr_open()
+ *                 to lvm_chr_ioctl()
+ *               - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl()
+ *               - allowed LVM_RESET and retrieval commands to go ahead;
+ *                 only other update ioctls are blocked now
+ *               - fixed pv->pe to NULL for pv_status
+ *               - using lv_req structure in lvm_chr_ioctl() now
+ *               - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce()
+ *                 caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE)
+ *    09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to
+ *                 handle lgoical volume private read ahead sector
+ *               - implemented LV read_ahead handling with lvm_blk_read()
+ *                 and lvm_blk_write()
+ *    10/02/1999 - implemented 2.[12].* support function lvm_hd_name()
+ *                 to be used in drivers/block/genhd.c by disk_name()
+ *    12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO
+ *               - enhanced gendisk insert/remove handling
+ *    16/02/1999 - changed to dynamic block minor number allocation to
+ *                 have as much as 99 volume groups with 256 logical volumes
+ *                 as the grand total; this allows having 1 volume group with
+ *                 up to 256 logical volumes in it
+ *    21/02/1999 - added LV open count information to proc filesystem
+ *               - substituted redundant LVM_RESET code by calls
+ *                 to lvm_do_vg_remove()
+ *    22/02/1999 - used schedule_timeout() to be more responsive
+ *                 in case of lvm_do_vg_remove() with lots of logical volumes
+ *    19/03/1999 - fixed NULL pointer bug in module_init/lvm_init
+ *    17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0)
+ *               - enhanced lvm_hd_name support
+ *    03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and
+ *                 memcpy_tofs/memcpy_fromfs macro redefinitions
+ *    06/07/1999 - corrected reads/writes statistic counter copy in case
+ *                 of striped logical volume
+ *    28/07/1999 - implemented snapshot logical volumes
+ *                 - lvm_chr_ioctl
+ *                   - LV_STATUS_BYINDEX
+ *                   - LV_STATUS_BYNAME
+ *                 - lvm_do_lv_create
+ *                 - lvm_do_lv_remove
+ *                 - lvm_map
+ *                 - new lvm_snapshot_remap_block
+ *                 - new lvm_snapshot_remap_new_block
+ *    08/10/1999 - implemented support for multiple snapshots per
+ *                 original logical volume
+ *    12/10/1999 - support for 2.3.19
+ *    11/11/1999 - support for 2.3.28
+ *    21/11/1999 - changed lvm_map() interface to buffer_head based
+ *    19/12/1999 - support for 2.3.33
+ *    01/01/2000 - changed locking concept in lvm_map(),
+ *                 lvm_do_vg_create() and lvm_do_lv_remove()
+ *    15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl()
+ *    24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc.
+ *    29/01/2000 - used kmalloc/kfree again for all small structures
+ *    20/01/2000 - cleaned up lvm_chr_ioctl by moving code
+ *                 to seperated functions
+ *               - avoided "/dev/" in proc filesystem output
+ *               - avoided inline strings functions lvm_strlen etc.
+ *    14/02/2000 - support for 2.3.43
+ *               - integrated Andrea Arcagnelli's snapshot code
+ *
+ */
+
+
+static char *lvm_version = "LVM version 0.8final  by Heinz Mauelshagen  (15/02/2000)\n";
+static char *lvm_short_version = "version 0.8final  (15/02/2000)";
+
+#define MAJOR_NR	LVM_BLK_MAJOR
+#define	DEVICE_OFF(device)
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#ifdef MODVERSIONS
+#undef MODULE
+#define MODULE
+#include <linux/modversions.h>
+#endif
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <linux/hdreg.h>
+#include <linux/stat.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+#include <linux/locks.h>
+#include <linux/smp_lock.h>
+#include <asm/ioctl.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+
+#include <linux/errno.h>
+#include <linux/lvm.h>
+
+#define	LVM_CORRECT_READ_AHEAD( a) \
+   if      ( a < LVM_MIN_READ_AHEAD || \
+             a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD;
+
+#ifndef WRITEA
+#  define WRITEA WRITE
+#endif
+
+/*
+ * External function prototypes
+ */
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#else
+extern int lvm_init(void);
+#endif
+
+static void lvm_dummy_device_request(request_queue_t *);
+#define	DEVICE_REQUEST	lvm_dummy_device_request
+
+static void lvm_make_request_fn(int, struct buffer_head*);
+
+static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
+static int lvm_blk_open(struct inode *, struct file *);
+
+static ssize_t lvm_blk_read(struct file *, char *, size_t, loff_t *);
+static ssize_t lvm_blk_write(struct file *, const char *, size_t, loff_t *);
+
+static int lvm_chr_open(struct inode *, struct file *);
+
+static int lvm_chr_close(struct inode *, struct file *);
+static int lvm_blk_close(struct inode *, struct file *);
+
+static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong);
+
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+static int lvm_proc_get_info(char *, char **, off_t, int);
+static int (*lvm_proc_get_info_ptr) (char *, char **, off_t, int) =
+&lvm_proc_get_info;
+#endif
+
+#ifdef LVM_HD_NAME
+void lvm_hd_name(char *, int);
+#endif
+/* End external function prototypes */
+
+
+/*
+ * Internal function prototypes
+ */
+static void lvm_init_vars(void);
+
+/* external snapshot calls */
+int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *);
+int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *);
+int lvm_snapshot_alloc(lv_t *);
+void lvm_snapshot_release(lv_t *); 
+
+#ifdef LVM_HD_NAME
+extern void (*lvm_hd_name_ptr) (char *, int);
+#endif
+static int lvm_map(struct buffer_head *, int);
+static int lvm_do_lock_lvm(void);
+static int lvm_do_le_remap(vg_t *, void *);
+static int lvm_do_pe_lock_unlock(vg_t *r, void *);
+static int lvm_do_vg_create(int, void *);
+static int lvm_do_vg_extend(vg_t *, void *);
+static int lvm_do_vg_reduce(vg_t *, void *);
+static int lvm_do_vg_remove(int);
+static int lvm_do_lv_create(int, char *, lv_t *);
+static int lvm_do_lv_remove(int, char *, int);
+static int lvm_do_lv_extend_reduce(int, char *, lv_t *);
+static int lvm_do_lv_status_byname(vg_t *r, void *);
+static int lvm_do_lv_status_byindex(vg_t *, void *arg);
+static int lvm_do_pv_change(vg_t*, void*);
+static int lvm_do_pv_status(vg_t *, void *);
+static void lvm_geninit(struct gendisk *);
+#ifdef LVM_GET_INODE
+static struct inode *lvm_get_inode(int);
+void lvm_clear_inode(struct inode *);
+#endif
+/* END Internal function prototypes */
+
+
+/* volume group descriptor area pointers */
+static vg_t *vg[ABS_MAX_VG];
+static pv_t *pvp = NULL;
+static lv_t *lvp = NULL;
+static pe_t *pep = NULL;
+static pe_t *pep1 = NULL;
+
+
+/* map from block minor number to VG and LV numbers */
+typedef struct {
+	int vg_number;
+	int lv_number;
+} vg_lv_map_t;
+static vg_lv_map_t vg_lv_map[ABS_MAX_LV];
+
+
+/* Request structures (lvm_chr_ioctl()) */
+static pv_change_req_t pv_change_req;
+static pv_flush_req_t pv_flush_req;
+static pv_status_req_t pv_status_req;
+static pe_lock_req_t pe_lock_req;
+static le_remap_req_t le_remap_req;
+static lv_req_t lv_req;
+
+#ifdef LVM_TOTAL_RESET
+static int lvm_reset_spindown = 0;
+#endif
+
+static char pv_name[NAME_LEN];
+/* static char rootvg[NAME_LEN] = { 0, }; */
+static uint lv_open = 0;
+static const char *const lvm_name = LVM_NAME;
+static int lock = 0;
+static int loadtime = 0;
+static uint vg_count = 0;
+static long lvm_chr_open_count = 0;
+static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
+static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lvm_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait);
+
+static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
+
+static struct file_operations lvm_chr_fops =
+{
+	open:		lvm_chr_open,
+	release:	lvm_chr_close,
+	ioctl:		lvm_chr_ioctl,
+};
+
+static struct file_operations lvm_blk_fops =
+{
+        open:           lvm_blk_open,
+        release:        blkdev_close,
+        read:           lvm_blk_read,
+        write:          lvm_blk_write,
+        ioctl:          lvm_blk_ioctl,
+        fsync:          block_fsync,
+};
+
+#define BLOCK_DEVICE_OPERATIONS
+/* block device operations structure needed for 2.3.38? and above */
+static struct block_device_operations lvm_blk_dops =
+{
+	open: 		lvm_blk_open,
+	release:	lvm_blk_close,
+	ioctl:		lvm_blk_ioctl
+};
+
+/* gendisk structures */
+static struct hd_struct lvm_hd_struct[MAX_LV];
+static int lvm_blocksizes[MAX_LV] =
+{0,};
+static int lvm_size[MAX_LV] =
+{0,};
+static struct gendisk lvm_gendisk =
+{
+	MAJOR_NR,		/* major # */
+	LVM_NAME,		/* name of major */
+	0,			/* number of times minor is shifted
+				   to get real minor */
+	1,			/* maximum partitions per device */
+	lvm_hd_struct,		/* partition table */
+	lvm_size,		/* device size in blocks, copied
+				   to block_size[] */
+	MAX_LV,			/* number or real devices */
+	NULL,			/* internal */
+	NULL,			/* pointer to next gendisk struct (internal) */
+};
+
+
+#ifdef MODULE
+/*
+ * Module initialization...
+ */
+int init_module(void)
+#else
+/*
+ * Driver initialization...
+ */
+#ifdef __initfunc
+__initfunc(int lvm_init(void))
+#else
+int __init lvm_init(void)
+#endif
+#endif				/* #ifdef MODULE */
+{
+	struct gendisk *gendisk_ptr = NULL;
+
+	if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) {
+		printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name);
+		return -EIO;
+	}
+#ifdef BLOCK_DEVICE_OPERATIONS
+	if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0)
+#else
+	if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0)
+#endif
+	{
+		printk("%s -- register_blkdev failed\n", lvm_name);
+		if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0)
+			printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
+		return -EIO;
+	}
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+	create_proc_info_entry(LVM_NAME, S_IFREG | S_IRUGO,
+			       &proc_root, lvm_proc_get_info_ptr);
+#endif
+
+	lvm_init_vars();
+	lvm_geninit(&lvm_gendisk);
+
+	/* insert our gendisk at the corresponding major */
+	if (gendisk_head != NULL) {
+		gendisk_ptr = gendisk_head;
+		while (gendisk_ptr->next != NULL &&
+		       gendisk_ptr->major > lvm_gendisk.major) {
+			gendisk_ptr = gendisk_ptr->next;
+		}
+		lvm_gendisk.next = gendisk_ptr->next;
+		gendisk_ptr->next = &lvm_gendisk;
+	} else {
+		gendisk_head = &lvm_gendisk;
+		lvm_gendisk.next = NULL;
+	}
+
+#ifdef LVM_HD_NAME
+	/* reference from drivers/block/genhd.c */
+	lvm_hd_name_ptr = lvm_hd_name;
+#endif
+
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);
+	/* optional read root VGDA */
+/*
+   if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg);
+*/
+
+	printk(KERN_INFO
+	       "%s%s -- "
+#ifdef MODULE
+	       "Module"
+#else
+	       "Driver"
+#endif
+	       " successfully initialized\n",
+	       lvm_version, lvm_name);
+
+	return 0;
+} /* init_module() / lvm_init() */
+
+
+#ifdef MODULE
+/*
+ * Module cleanup...
+ */
+void cleanup_module(void)
+{
+	struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL;
+
+	if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) {
+		printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
+	}
+	if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) {
+		printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name);
+	}
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+
+	gendisk_ptr = gendisk_ptr_prev = gendisk_head;
+	while (gendisk_ptr != NULL) {
+		if (gendisk_ptr == &lvm_gendisk)
+			break;
+		gendisk_ptr_prev = gendisk_ptr;
+		gendisk_ptr = gendisk_ptr->next;
+	}
+	/* delete our gendisk from chain */
+	if (gendisk_ptr == &lvm_gendisk)
+		gendisk_ptr_prev->next = gendisk_ptr->next;
+
+	blk_size[MAJOR_NR] = NULL;
+	blksize_size[MAJOR_NR] = NULL;
+
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+	remove_proc_entry(LVM_NAME, &proc_root);
+#endif
+
+#ifdef LVM_HD_NAME
+	/* reference from linux/drivers/block/genhd.c */
+	lvm_hd_name_ptr = NULL;
+#endif
+
+	printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
+
+	return;
+}	/* void cleanup_module() */
+#endif	/* #ifdef MODULE */
+
+
+/*
+ * support function to initialize lvm variables
+ */
+#ifdef __initfunc
+__initfunc(void lvm_init_vars(void))
+#else
+void __init lvm_init_vars(void)
+#endif
+{
+	int v;
+
+	loadtime = CURRENT_TIME;
+
+	lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
+
+	pe_lock_req.lock = UNLOCK_PE;
+	pe_lock_req.data.lv_dev = \
+	    pe_lock_req.data.pv_dev = \
+	    pe_lock_req.data.pv_offset = 0;
+
+	/* Initialize VG pointers */
+	for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL;
+
+	/* Initialize LV -> VG association */
+	for (v = 0; v < ABS_MAX_LV; v++) {
+		/* index ABS_MAX_VG never used for real VG */
+		vg_lv_map[v].vg_number = ABS_MAX_VG;
+		vg_lv_map[v].lv_number = -1;
+	}
+
+	return;
+} /* lvm_init_vars() */
+
+
+/********************************************************************
+ *
+ * Character device functions
+ *
+ ********************************************************************/
+
+/*
+ * character device open routine
+ */
+static int lvm_chr_open(struct inode *inode,
+			struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG
+	 "%s -- lvm_chr_open MINOR: %d  VG#: %d  mode: 0x%X  lock: %d\n",
+	       lvm_name, minor, VG_CHR(minor), file->f_mode, lock);
+#endif
+
+	/* super user validation */
+	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+	/* Group special file open */
+	if (VG_CHR(minor) > MAX_VG) return -ENXIO;
+
+	MOD_INC_USE_COUNT;
+
+	lvm_chr_open_count++;
+	return 0;
+} /* lvm_chr_open() */
+
+
+/*
+ * character device i/o-control routine
+ *
+ * Only one changing process can do changing ioctl at one time,
+ * others will block.
+ *
+ */
+static int lvm_chr_ioctl(struct inode *inode, struct file *file,
+			 uint command, ulong a)
+{
+	int minor = MINOR(inode->i_rdev);
+	uint extendable, l, v;
+	void *arg = (void *) a;
+	lv_t lv;
+	vg_t* vg_ptr = vg[VG_CHR(minor)];
+
+	/* otherwise cc will complain about unused variables */
+	(void) lvm_lock;
+
+
+#ifdef DEBUG_IOCTL
+	printk(KERN_DEBUG
+	       "%s -- lvm_chr_ioctl: command: 0x%X  MINOR: %d  "
+	       "VG#: %d  mode: 0x%X\n",
+	       lvm_name, command, minor, VG_CHR(minor), file->f_mode);
+#endif
+
+#ifdef LVM_TOTAL_RESET
+	if (lvm_reset_spindown > 0) return -EACCES;
+#endif
+
+	/* Main command switch */
+	switch (command) {
+	case LVM_LOCK_LVM:
+		/* lock the LVM */
+		return lvm_do_lock_lvm();
+
+	case LVM_GET_IOP_VERSION:
+		/* check lvm version to ensure driver/tools+lib
+		   interoperability */
+		if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0)
+			return -EFAULT;
+		return 0;
+
+#ifdef LVM_TOTAL_RESET
+	case LVM_RESET:
+		/* lock reset function */
+		lvm_reset_spindown = 1;
+		for (v = 0; v < ABS_MAX_VG; v++) {
+			if (vg[v] != NULL) lvm_do_vg_remove(v);
+		}
+
+#ifdef MODULE
+		while (GET_USE_COUNT(&__this_module) < 1)
+			MOD_INC_USE_COUNT;
+		while (GET_USE_COUNT(&__this_module) > 1)
+			MOD_DEC_USE_COUNT;
+#endif				/* MODULE */
+		lock = 0;	/* release lock */
+		wake_up_interruptible(&lvm_wait);
+		return 0;
+#endif /* LVM_TOTAL_RESET */
+
+
+	case LE_REMAP:
+		/* remap a logical extent (after moving the physical extent) */
+		return lvm_do_le_remap(vg_ptr,arg);
+
+	case PE_LOCK_UNLOCK:
+		/* lock/unlock i/o to a physical extent to move it to another
+		   physical volume (move's done in user space's pvmove) */
+		return lvm_do_pe_lock_unlock(vg_ptr,arg);
+
+	case VG_CREATE:
+		/* create a VGDA */
+		return lvm_do_vg_create(minor, arg);
+
+	case VG_REMOVE:
+		/* remove an inactive VGDA */
+		return lvm_do_vg_remove(minor);
+
+	case VG_EXTEND:
+		/* extend a volume group */
+		return lvm_do_vg_extend(vg_ptr,arg);
+
+	case VG_REDUCE:
+		/* reduce a volume group */
+		return lvm_do_vg_reduce(vg_ptr,arg);
+
+
+	case VG_SET_EXTENDABLE:
+		/* set/clear extendability flag of volume group */
+		if (vg_ptr == NULL) return -ENXIO;
+		if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0)
+			return -EFAULT;
+
+		if (extendable == VG_EXTENDABLE ||
+		    extendable == ~VG_EXTENDABLE) {
+			if (extendable == VG_EXTENDABLE)
+				vg_ptr->vg_status |= VG_EXTENDABLE;
+			else
+				vg_ptr->vg_status &= ~VG_EXTENDABLE;
+		} else return -EINVAL;
+		return 0;
+
+
+	case VG_STATUS:
+		/* get volume group data (only the vg_t struct) */
+		if (vg_ptr == NULL) return -ENXIO;
+		if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0)
+			return -EFAULT;
+		return 0;
+
+
+	case VG_STATUS_GET_COUNT:
+		/* get volume group count */
+		if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0)
+			return -EFAULT;
+		return 0;
+
+
+	case VG_STATUS_GET_NAMELIST:
+		/* get volume group count */
+		for (l = v = 0; v < ABS_MAX_VG; v++) {
+			if (vg[v] != NULL) {
+				if (copy_to_user(arg + l++ * NAME_LEN,
+						 vg[v]->vg_name,
+						 NAME_LEN) != 0)
+					return -EFAULT;
+			}
+		}
+		return 0;
+
+
+	case LV_CREATE:
+	case LV_REMOVE:
+	case LV_EXTEND:
+	case LV_REDUCE:
+		/* create, remove, extend or reduce a logical volume */
+		if (vg_ptr == NULL) return -ENXIO;
+		if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0)
+			return -EFAULT;
+
+		if (command != LV_REMOVE) {
+			if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0)
+				return -EFAULT;
+		}
+		switch (command) {
+		case LV_CREATE:
+			return lvm_do_lv_create(minor, lv_req.lv_name, &lv);
+
+		case LV_REMOVE:
+			return lvm_do_lv_remove(minor, lv_req.lv_name, -1);
+
+		case LV_EXTEND:
+		case LV_REDUCE:
+			return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv);
+		}
+
+
+	case LV_STATUS_BYNAME:
+		/* get status of a logical volume by name */
+		return lvm_do_lv_status_byname(vg_ptr,arg);
+
+	case LV_STATUS_BYINDEX:
+		/* get status of a logical volume by index */
+		return lvm_do_lv_status_byindex(vg_ptr,arg);
+
+	case PV_CHANGE:
+		/* change a physical volume */
+		return lvm_do_pv_change(vg_ptr,arg);
+
+	case PV_STATUS:
+		/* get physical volume data (pv_t structure only) */
+		return lvm_do_pv_status(vg_ptr,arg);
+
+	case PV_FLUSH:
+		/* physical volume buffer flush/invalidate */
+		if (copy_from_user(&pv_flush_req, arg,
+				   sizeof(pv_flush_req)) != 0)
+			return -EFAULT;
+
+		fsync_dev(pv_flush_req.pv_dev);
+		invalidate_buffers(pv_flush_req.pv_dev);
+		return 0;
+
+	default:
+		printk(KERN_WARNING
+		       "%s -- lvm_chr_ioctl: unknown command %x\n",
+		       lvm_name, command);
+		return -EINVAL;
+	}
+
+	return 0;
+} /* lvm_chr_ioctl */
+
+
+/*
+ * character device close routine
+ */
+static int lvm_chr_close(struct inode *inode, struct file *file)
+{
+#ifdef DEBUG
+	int minor = MINOR(inode->i_rdev);
+	printk(KERN_DEBUG
+	     "%s -- lvm_chr_close   VG#: %d\n", lvm_name, VG_CHR(minor));
+#endif
+
+#ifdef LVM_TOTAL_RESET
+	if (lvm_reset_spindown > 0) {
+		lvm_reset_spindown = 0;
+		lvm_chr_open_count = 1;
+	}
+#endif
+
+	if (lvm_chr_open_count > 0) lvm_chr_open_count--;
+	if (lock == current->pid) {
+		lock = 0;	/* release lock */
+		wake_up_interruptible(&lvm_wait);
+	}
+
+#ifdef MODULE
+	if (GET_USE_COUNT(&__this_module) > 0) MOD_DEC_USE_COUNT;
+#endif
+
+	return 0;
+} /* lvm_chr_close() */
+
+
+
+/********************************************************************
+ *
+ * Block device functions
+ *
+ ********************************************************************/
+
+/*
+ * block device open routine
+ */
+static int lvm_blk_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	lv_t *lv_ptr;
+	vg_t *vg_ptr = vg[VG_BLK(minor)];
+
+#ifdef DEBUG_LVM_BLK_OPEN
+	printk(KERN_DEBUG
+	  "%s -- lvm_blk_open MINOR: %d  VG#: %d  LV#: %d  mode: 0x%X\n",
+	    lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode);
+#endif
+
+#ifdef LVM_TOTAL_RESET
+	if (lvm_reset_spindown > 0)
+		return -EPERM;
+#endif
+
+	if (vg_ptr != NULL &&
+	    (vg_ptr->vg_status & VG_ACTIVE) &&
+	    (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL &&
+	    LV_BLK(minor) >= 0 &&
+	    LV_BLK(minor) < vg_ptr->lv_max) {
+
+		/* Check parallel LV spindown (LV remove) */
+		if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM;
+
+		/* Check inactive LV and open for read/write */
+		if (file->f_mode & O_RDWR) {
+			if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM;
+			if (!(lv_ptr->lv_access & LV_WRITE))  return -EACCES;
+		}
+
+#ifdef BLOCK_DEVICE_OPERATIONS
+		file->f_op = &lvm_blk_fops;
+#endif
+
+                /* be sure to increment VG counter */
+		if (lv_ptr->lv_open == 0) vg_ptr->lv_open++;
+		lv_ptr->lv_open++;
+
+		MOD_INC_USE_COUNT;
+
+#ifdef DEBUG_LVM_BLK_OPEN
+		printk(KERN_DEBUG
+		       "%s -- lvm_blk_open MINOR: %d  VG#: %d  LV#: %d  size: %d\n",
+		       lvm_name, minor, VG_BLK(minor), LV_BLK(minor),
+		       lv_ptr->lv_size);
+#endif
+
+		return 0;
+	}
+	return -ENXIO;
+} /* lvm_blk_open() */
+
+
+/*
+ * block device read
+ */
+static ssize_t lvm_blk_read(struct file *file, char *buffer,
+	      		    size_t size, loff_t * offset)
+{
+	int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] =
+           vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead;
+	return block_read(file, buffer, size, offset);
+}
+
+
+/*
+ * block device write
+ */
+static ssize_t lvm_blk_write(struct file *file, const char *buffer,
+	      		     size_t size, loff_t * offset)
+{
+	int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] =
+           vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead;
+	return block_write(file, buffer, size, offset);
+}
+
+
+/*
+ * block device i/o-control routine
+ */
+static int lvm_blk_ioctl(struct inode *inode, struct file *file,
+			 uint command, ulong a)
+{
+	int minor = MINOR(inode->i_rdev);
+	vg_t *vg_ptr = vg[VG_BLK(minor)];
+	lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
+	void *arg = (void *) a;
+	struct hd_geometry *hd = (struct hd_geometry *) a;
+
+#ifdef DEBUG_IOCTL
+	printk(KERN_DEBUG
+	       "%s -- lvm_blk_ioctl MINOR: %d  command: 0x%X  arg: %X  "
+	       "VG#: %dl  LV#: %d\n",
+	       lvm_name, minor, command, (ulong) arg,
+	       VG_BLK(minor), LV_BLK(minor));
+#endif
+
+	switch (command) {
+	case BLKGETSIZE:
+		/* return device size */
+#ifdef DEBUG_IOCTL
+		printk(KERN_DEBUG
+		       "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n",
+		       lvm_name, lv_ptr->lv_size);
+#endif
+		copy_to_user((long *) arg, &lv_ptr->lv_size,
+			     sizeof(lv_ptr->lv_size));
+		break;
+
+
+	case BLKFLSBUF:
+		/* flush buffer cache */
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+#ifdef DEBUG_IOCTL
+		printk(KERN_DEBUG
+		       "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name);
+#endif
+		fsync_dev(inode->i_rdev);
+		break;
+
+
+	case BLKRASET:
+		/* set read ahead for block device */
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+#ifdef DEBUG_IOCTL
+		printk(KERN_DEBUG
+		       "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n",
+		       lvm_name, (long) arg, MAJOR(inode->i_rdev), minor);
+#endif
+		if ((long) arg < LVM_MIN_READ_AHEAD ||
+		    (long) arg > LVM_MAX_READ_AHEAD)
+			return -EINVAL;
+		lv_ptr->lv_read_ahead = (long) arg;
+		break;
+
+
+	case BLKRAGET:
+		/* get current read ahead setting */
+#ifdef DEBUG_IOCTL
+		printk(KERN_DEBUG
+		       "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
+#endif
+		copy_to_user((long *) arg, &lv_ptr->lv_read_ahead,
+			     sizeof(lv_ptr->lv_read_ahead));
+		break;
+
+
+	case HDIO_GETGEO:
+		/* get disk geometry */
+#ifdef DEBUG_IOCTL
+		printk(KERN_DEBUG
+		       "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
+#endif
+		if (hd == NULL)
+			return -EINVAL;
+		{
+			unsigned char heads = 64;
+			unsigned char sectors = 32;
+			long start = 0;
+			short cylinders = lv_ptr->lv_size / heads / sectors;
+
+			if (copy_to_user((char *) &hd->heads, &heads,
+					 sizeof(heads)) != 0 ||
+			    copy_to_user((char *) &hd->sectors, &sectors,
+					 sizeof(sectors)) != 0 ||
+			    copy_to_user((short *) &hd->cylinders,
+				   &cylinders, sizeof(cylinders)) != 0 ||
+			    copy_to_user((long *) &hd->start, &start,
+					 sizeof(start)) != 0)
+				return -EFAULT;
+		}
+
+#ifdef DEBUG_IOCTL
+		printk(KERN_DEBUG
+		       "%s -- lvm_blk_ioctl -- cylinders: %d\n",
+		       lvm_name, lv_ptr->lv_size / heads / sectors);
+#endif
+		break;
+
+
+	case LV_SET_ACCESS:
+		/* set access flags of a logical volume */
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		lv_ptr->lv_access = (ulong) arg;
+		break;
+
+
+	case LV_SET_STATUS:
+		/* set status flags of a logical volume */
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
+			return -EPERM;
+		lv_ptr->lv_status = (ulong) arg;
+		break;
+
+
+	case LV_SET_ALLOCATION:
+		/* set allocation flags of a logical volume */
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		lv_ptr->lv_allocation = (ulong) arg;
+		break;
+
+
+	default:
+		printk(KERN_WARNING
+		       "%s -- lvm_blk_ioctl: unknown command %d\n",
+		       lvm_name, command);
+		return -EINVAL;
+	}
+
+	return 0;
+} /* lvm_blk_ioctl() */
+
+
+/*
+ * block device close routine
+ */
+static int lvm_blk_close(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	vg_t *vg_ptr = vg[VG_BLK(minor)];
+	lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
+
+#ifdef DEBUG
+	printk(KERN_DEBUG
+	       "%s -- lvm_blk_close MINOR: %d  VG#: %d  LV#: %d\n",
+	       lvm_name, minor, VG_BLK(minor), LV_BLK(minor));
+#endif
+
+	sync_dev(inode->i_rdev);
+	if (lv_ptr->lv_open == 1) vg_ptr->lv_open--;
+	lv_ptr->lv_open--;
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+} /* lvm_blk_close() */
+
+
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+/*
+ * Support function /proc-Filesystem
+ */
+#define  LVM_PROC_BUF   ( i == 0 ? dummy_buf : &buf[sz])
+
+static int lvm_proc_get_info(char *page, char **start, off_t pos, int count)
+{
+	int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter,
+	 lv_open_total, pe_t_bytes, lv_block_exception_t_bytes, seconds;
+	static off_t sz;
+	off_t sz_last;
+	char allocation_flag, inactive_flag, rw_flag, stripes_flag;
+	char *lv_name, *pv_name;
+	static char *buf = NULL;
+	static char dummy_buf[160];	/* sized for 2 lines */
+	vg_t *vg_ptr;
+	lv_t *lv_ptr;
+	pv_t *pv_ptr;
+
+
+#ifdef DEBUG_LVM_PROC_GET_INFO
+	printk(KERN_DEBUG
+	       "%s - lvm_proc_get_info CALLED  pos: %lu  count: %d  whence: %d\n",
+	       lvm_name, pos, count, whence);
+#endif
+
+	if (pos == 0 || buf == NULL) {
+		sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \
+		    lv_open_total = pe_t_bytes = lv_block_exception_t_bytes = 0;
+
+		/* search for activity */
+		for (v = 0; v < ABS_MAX_VG; v++) {
+			if ((vg_ptr = vg[v]) != NULL) {
+				vg_counter++;
+				pv_counter += vg_ptr->pv_cur;
+				lv_counter += vg_ptr->lv_cur;
+				if (vg_ptr->lv_cur > 0) {
+					for (l = 0; l < vg[v]->lv_max; l++) {
+						if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
+							pe_t_bytes += lv_ptr->lv_allocated_le;
+							if (lv_ptr->lv_block_exception != NULL)
+								lv_block_exception_t_bytes += lv_ptr->lv_remap_end;
+							if (lv_ptr->lv_open > 0) {
+								lv_open_counter++;
+								lv_open_total += lv_ptr->lv_open;
+							}
+						}
+					}
+				}
+			}
+		}
+		pe_t_bytes *= sizeof(pe_t);
+		lv_block_exception_t_bytes *= sizeof(lv_block_exception_t);
+
+		if (buf != NULL) {
+#ifdef DEBUG_KFREE
+			printk(KERN_DEBUG
+			       "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+			kfree(buf);
+			buf = NULL;
+		}
+		/* 2 times: first to get size to allocate buffer,
+		   2nd to fill the malloced buffer */
+		for (i = 0; i < 2; i++) {
+			sz = 0;
+			sz += sprintf(LVM_PROC_BUF,
+				      "LVM "
+#ifdef MODULE
+				      "module"
+#else
+				      "driver"
+#endif
+				      " %s\n\n"
+				    "Total:  %d VG%s  %d PV%s  %d LV%s ",
+				      lvm_short_version,
+				  vg_counter, vg_counter == 1 ? "" : "s",
+				  pv_counter, pv_counter == 1 ? "" : "s",
+				 lv_counter, lv_counter == 1 ? "" : "s");
+			sz += sprintf(LVM_PROC_BUF,
+				      "(%d LV%s open",
+				      lv_open_counter,
+				      lv_open_counter == 1 ? "" : "s");
+			if (lv_open_total > 0)
+				sz += sprintf(LVM_PROC_BUF,
+					      " %d times)\n",
+					      lv_open_total);
+			else
+				sz += sprintf(LVM_PROC_BUF, ")");
+			sz += sprintf(LVM_PROC_BUF,
+				      "\nGlobal: %lu bytes malloced   IOP version: %d   ",
+				      vg_counter * sizeof(vg_t) +
+				      pv_counter * sizeof(pv_t) +
+				      lv_counter * sizeof(lv_t) +
+			pe_t_bytes + lv_block_exception_t_bytes + sz_last,
+				      lvm_iop_version);
+
+			seconds = CURRENT_TIME - loadtime;
+			if (seconds < 0)
+				loadtime = CURRENT_TIME + seconds;
+			if (seconds / 86400 > 0) {
+				sz += sprintf(LVM_PROC_BUF, "%d day%s ",
+					      seconds / 86400,
+					      seconds / 86400 == 0 ||
+					 seconds / 86400 > 1 ? "s" : "");
+			}
+			sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
+				      (seconds % 86400) / 3600,
+				      (seconds % 3600) / 60,
+				      seconds % 60);
+
+			if (vg_counter > 0) {
+				for (v = 0; v < ABS_MAX_VG; v++) {
+					/* volume group */
+					if ((vg_ptr = vg[v]) != NULL) {
+						inactive_flag = ' ';
+						if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I';
+						sz += sprintf(LVM_PROC_BUF,
+							      "\nVG: %c%s  [%d PV, %d LV/%d open] "
+							      " PE Size: %d KB\n"
+							      "  Usage [KB/PE]: %d /%d total  "
+							      "%d /%d used  %d /%d free",
+							      inactive_flag,
+							      vg_ptr->vg_name,
+							      vg_ptr->pv_cur,
+							      vg_ptr->lv_cur,
+							      vg_ptr->lv_open,
+						     	      vg_ptr->pe_size >> 1,
+							      vg_ptr->pe_size * vg_ptr->pe_total >> 1,
+							      vg_ptr->pe_total,
+							      vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
+						     	      vg_ptr->pe_allocated,
+							      (vg_ptr->pe_total - vg_ptr->pe_allocated) *
+						     	      vg_ptr->pe_size >> 1,
+							      vg_ptr->pe_total - vg_ptr->pe_allocated);
+
+						/* physical volumes */
+						sz += sprintf(LVM_PROC_BUF,
+							      "\n  PV%s ",
+							      vg_ptr->pv_cur == 1 ? ": " : "s:");
+						c = 0;
+						for (p = 0; p < vg_ptr->pv_max; p++) {
+							if ((pv_ptr = vg_ptr->pv[p]) != NULL) {
+								inactive_flag = 'A';
+								if (!(pv_ptr->pv_status & PV_ACTIVE))
+									inactive_flag = 'I';
+								allocation_flag = 'A';
+								if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE))
+									allocation_flag = 'N';
+								pv_name = strchr(pv_ptr->pv_name+1,'/');
+								if ( pv_name == 0) pv_name = pv_ptr->pv_name;
+								else               pv_name++;
+								sz += sprintf(LVM_PROC_BUF,
+									      "[%c%c] %-21s %8d /%-6d  "
+									      "%8d /%-6d  %8d /%-6d",
+									      inactive_flag,
+									      allocation_flag,
+									      pv_name,
+									      pv_ptr->pe_total *
+									      pv_ptr->pe_size >> 1,
+									      pv_ptr->pe_total,
+									      pv_ptr->pe_allocated *
+									      pv_ptr->pe_size >> 1,
+									      pv_ptr->pe_allocated,
+									      (pv_ptr->pe_total -
+									       pv_ptr->pe_allocated) *
+									      pv_ptr->pe_size >> 1,
+									      pv_ptr->pe_total -
+									      pv_ptr->pe_allocated);
+								c++;
+								if (c < vg_ptr->pv_cur)
+									sz += sprintf(LVM_PROC_BUF,
+										      "\n       ");
+							}
+						}
+
+						/* logical volumes */
+						sz += sprintf(LVM_PROC_BUF,
+							   "\n    LV%s ",
+							      vg_ptr->lv_cur == 1 ? ": " : "s:");
+						c = 0;
+						for (l = 0; l < vg[v]->lv_max; l++) {
+							if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
+								inactive_flag = 'A';
+								if (!(lv_ptr->lv_status & LV_ACTIVE))
+									inactive_flag = 'I';
+								rw_flag = 'R';
+								if (lv_ptr->lv_access & LV_WRITE)
+									rw_flag = 'W';
+								allocation_flag = 'D';
+								if (lv_ptr->lv_allocation & LV_CONTIGUOUS)
+									allocation_flag = 'C';
+								stripes_flag = 'L';
+								if (lv_ptr->lv_stripes > 1)
+									stripes_flag = 'S';
+								sz += sprintf(LVM_PROC_BUF,
+									      "[%c%c%c%c",
+									      inactive_flag,
+								 rw_flag,
+									      allocation_flag,
+									      stripes_flag);
+								if (lv_ptr->lv_stripes > 1)
+									sz += sprintf(LVM_PROC_BUF, "%-2d",
+										      lv_ptr->lv_stripes);
+								else
+									sz += sprintf(LVM_PROC_BUF, "  ");
+								lv_name = strrchr(lv_ptr->lv_name, '/');
+								if ( lv_name == 0) lv_name = lv_ptr->lv_name;
+								else               lv_name++;
+								sz += sprintf(LVM_PROC_BUF, "] %-25s", lv_name);
+								if (strlen(lv_name) > 25)
+									sz += sprintf(LVM_PROC_BUF,
+										      "\n                              ");
+								sz += sprintf(LVM_PROC_BUF, "%9d /%-6d   ",
+									      lv_ptr->lv_size >> 1,
+									      lv_ptr->lv_size / vg[v]->pe_size);
+
+								if (lv_ptr->lv_open == 0)
+									sz += sprintf(LVM_PROC_BUF, "close");
+								else
+									sz += sprintf(LVM_PROC_BUF, "%dx open",
+										      lv_ptr->lv_open);
+								c++;
+								if (c < vg_ptr->lv_cur)
+									sz += sprintf(LVM_PROC_BUF,
+										      "\n         ");
+							}
+						}
+						if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none");
+						sz += sprintf(LVM_PROC_BUF, "\n");
+					}
+				}
+			}
+			if (buf == NULL) {
+				if ((buf = vmalloc(sz)) == NULL) {
+					sz = 0;
+					return sprintf(page, "%s - vmalloc error at line %d\n",
+						     lvm_name, __LINE__);
+				}
+			}
+			sz_last = sz;
+		}
+	}
+	if (pos > sz - 1) {
+		vfree(buf);
+		buf = NULL;
+		return 0;
+	}
+	*start = &buf[pos];
+	if (sz - pos < count)
+		return sz - pos;
+	else
+		return count;
+} /* lvm_proc_get_info() */
+#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */
+
+
+/*
+ * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c
+ * (see init_module/lvm_init)
+ */
+static int lvm_map(struct buffer_head *bh, int rw)
+{
+	int minor = MINOR(bh->b_dev);
+	int ret = 0;
+	ulong index;
+	ulong pe_start;
+	ulong size = bh->b_size >> 9;
+	ulong rsector_tmp = bh->b_blocknr * size;
+	ulong rsector_sav;
+	kdev_t rdev_tmp = bh->b_dev;
+	kdev_t rdev_sav;
+	lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)];
+
+
+	if (!(lv->lv_status & LV_ACTIVE)) {
+		printk(KERN_ALERT
+		       "%s - lvm_map: ll_rw_blk for inactive LV %s\n",
+		       lvm_name, lv->lv_name);
+		return -1;
+	}
+/*
+   if ( lv->lv_access & LV_SNAPSHOT)
+   printk ( "%s -- %02d:%02d  block: %lu  rw: %d\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), bh->b_blocknr, rw);
+ */
+
+	/* take care of snapshot chunk writes before
+	   check for writable logical volume */
+	if ((lv->lv_access & LV_SNAPSHOT) &&
+	    MAJOR(bh->b_rdev) != 0 &&
+	    MAJOR(bh->b_rdev) != MAJOR_NR &&
+	    (rw == WRITEA || rw == WRITE))
+	{
+   printk ( "%s -- doing snapshot write for %02d:%02d[%02d:%02d]  b_blocknr: %lu  b_rsector: %lu\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), MAJOR ( bh->b_rdev), MINOR ( bh->b_rdev), bh->b_blocknr, bh->b_rsector);
+		return 0;
+	}
+
+	if ((rw == WRITE || rw == WRITEA) &&
+	    !(lv->lv_access & LV_WRITE)) {
+		printk(KERN_CRIT
+		    "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
+		       lvm_name, lv->lv_name);
+		return -1;
+	}
+#ifdef DEBUG_MAP
+	printk(KERN_DEBUG
+	       "%s - lvm_map minor:%d  *rdev: %02d:%02d  *rsector: %lu  "
+	       "size:%lu\n",
+	       lvm_name, minor,
+	       MAJOR(rdev_tmp),
+	       MINOR(rdev_tmp),
+	       rsector_tmp, size);
+#endif
+
+	if (rsector_tmp + size > lv->lv_size) {
+		printk(KERN_ALERT
+		       "%s - lvm_map *rsector: %lu or size: %lu wrong for"
+		    " minor: %2d\n", lvm_name, rsector_tmp, size, minor);
+		return -1;
+	}
+	rsector_sav = rsector_tmp;
+	rdev_sav = rdev_tmp;
+
+lvm_second_remap:
+	/* linear mapping */
+	if (lv->lv_stripes < 2) {
+		/* get the index */
+		index = rsector_tmp / vg[VG_BLK(minor)]->pe_size;
+		pe_start = lv->lv_current_pe[index].pe;
+		rsector_tmp = lv->lv_current_pe[index].pe +
+		    (rsector_tmp % vg[VG_BLK(minor)]->pe_size);
+		rdev_tmp = lv->lv_current_pe[index].dev;
+
+#ifdef DEBUG_MAP
+		printk(KERN_DEBUG
+		       "lv_current_pe[%ld].pe: %ld  rdev: %02d:%02d  rsector:%ld\n",
+		       index,
+		       lv->lv_current_pe[index].pe,
+		       MAJOR(rdev_tmp),
+		       MINOR(rdev_tmp),
+		       rsector_tmp);
+#endif
+
+		/* striped mapping */
+	} else {
+		ulong stripe_index;
+		ulong stripe_length;
+
+		stripe_length = vg[VG_BLK(minor)]->pe_size * lv->lv_stripes;
+		stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize;
+		index = rsector_tmp / stripe_length +
+		    (stripe_index % lv->lv_stripes) *
+		    (lv->lv_allocated_le / lv->lv_stripes);
+		pe_start = lv->lv_current_pe[index].pe;
+		rsector_tmp = lv->lv_current_pe[index].pe +
+		    (rsector_tmp % stripe_length) -
+		    (stripe_index % lv->lv_stripes) * lv->lv_stripesize -
+		    stripe_index / lv->lv_stripes *
+		    (lv->lv_stripes - 1) * lv->lv_stripesize;
+		rdev_tmp = lv->lv_current_pe[index].dev;
+	}
+
+#ifdef DEBUG_MAP
+	printk(KERN_DEBUG
+	     "lv_current_pe[%ld].pe: %ld  rdev: %02d:%02d  rsector:%ld\n"
+	       "stripe_length: %ld  stripe_index: %ld\n",
+	       index,
+	       lv->lv_current_pe[index].pe,
+	       MAJOR(rdev_tmp),
+	       MINOR(rdev_tmp),
+	       rsector_tmp,
+	       stripe_length,
+	       stripe_index);
+#endif
+
+	/* handle physical extents on the move */
+	if (pe_lock_req.lock == LOCK_PE) {
+		if (rdev_tmp == pe_lock_req.data.pv_dev &&
+		    rsector_tmp >= pe_lock_req.data.pv_offset &&
+		    rsector_tmp < (pe_lock_req.data.pv_offset +
+				   vg[VG_BLK(minor)]->pe_size)) {
+			sleep_on(&lvm_map_wait);
+			rsector_tmp = rsector_sav;
+			rdev_tmp = rdev_sav;
+			goto lvm_second_remap;
+		}
+	}
+	/* statistic */
+	if (rw == WRITE || rw == WRITEA)
+		lv->lv_current_pe[index].writes++;
+	else
+		lv->lv_current_pe[index].reads++;
+
+	/* snapshot volume exception handling on physical device address base */
+	if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) {
+		/* original logical volume */
+		if (lv->lv_access & LV_SNAPSHOT_ORG) {
+			if (rw == WRITE || rw == WRITEA)
+			{
+				lv_t *lv_ptr;
+
+				/* start with first snapshot and loop thrugh all of them */
+				for (lv_ptr = lv->lv_snapshot_next;
+				     lv_ptr != NULL;
+				     lv_ptr = lv_ptr->lv_snapshot_next) {
+					down(&lv->lv_snapshot_org->lv_snapshot_sem);
+					/* do we still have exception storage for this snapshot free? */
+					if (lv_ptr->lv_block_exception != NULL) {
+						rdev_sav = rdev_tmp;
+						rsector_sav = rsector_tmp;
+						if (!lvm_snapshot_remap_block(&rdev_tmp,
+									      &rsector_tmp,
+									      pe_start,
+									      lv_ptr)) {
+							/* create a new mapping */
+							ret = lvm_snapshot_COW(rdev_tmp,
+									       rsector_tmp,
+									       pe_start,
+									       rsector_sav,
+									       lv_ptr); 
+						}
+						rdev_tmp = rdev_sav;
+						rsector_tmp = rsector_sav;
+					}
+					up(&lv->lv_snapshot_org->lv_snapshot_sem);
+				}
+			}
+		} else {
+			/* remap snapshot logical volume */
+			down(&lv->lv_snapshot_sem);
+			if (lv->lv_block_exception != NULL)
+				lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv);
+			up(&lv->lv_snapshot_sem);
+		}
+	}
+	bh->b_rdev = rdev_tmp;
+	bh->b_rsector = rsector_tmp;
+
+	return ret;
+} /* lvm_map() */
+
+
+/*
+ * internal support functions
+ */
+
+#ifdef LVM_HD_NAME
+/*
+ * generate "hard disk" name
+ */
+void lvm_hd_name(char *buf, int minor)
+{
+	int len = 0;
+	lv_t *lv_ptr;
+
+	if (vg[VG_BLK(minor)] == NULL ||
+	    (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL)
+		return;
+	len = strlen(lv_ptr->lv_name) - 5;
+	memcpy(buf, &lv_ptr->lv_name[5], len);
+	buf[len] = 0;
+	return;
+}
+#endif
+
+
+/*
+ * this one never should be called...
+ */
+static void lvm_dummy_device_request(request_queue_t * t)
+{
+	printk(KERN_EMERG
+	     "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n",
+	       lvm_name,
+	       MAJOR(CURRENT->rq_dev),
+	       MINOR(CURRENT->rq_dev),
+	       CURRENT->sector);
+	return;
+}
+
+
+/*
+ * make request function
+ */
+static void lvm_make_request_fn(int rw, struct buffer_head *bh)
+{
+	lvm_map(bh, rw);
+	if (bh->b_rdev != MD_MAJOR) generic_make_request(rw, bh); 
+	return;
+}
+
+
+/********************************************************************
+ *
+ * Character device support functions
+ *
+ ********************************************************************/
+/*
+ * character device support function logical volume manager lock
+ */
+static int lvm_do_lock_lvm(void)
+{
+lock_try_again:
+	spin_lock(&lvm_lock);
+	if (lock != 0 && lock != current->pid) {
+#ifdef DEBUG_IOCTL
+		printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n",
+		       lvm_name, lock);
+#endif
+		spin_unlock(&lvm_lock);
+		interruptible_sleep_on(&lvm_wait);
+		if (current->sigpending != 0)
+			return -EINTR;
+#ifdef LVM_TOTAL_RESET
+		if (lvm_reset_spindown > 0)
+			return -EACCES;
+#endif
+		goto lock_try_again;
+	}
+	lock = current->pid;
+	spin_unlock(&lvm_lock);
+	return 0;
+} /* lvm_do_lock_lvm */
+
+
+/*
+ * character device support function lock/unlock physical extend
+ */
+static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg)
+{
+	uint p;
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (copy_from_user(&pe_lock_req, arg,
+			   sizeof(pe_lock_req_t)) != 0) return -EFAULT;
+
+	switch (pe_lock_req.lock) {
+	case LOCK_PE:
+		for (p = 0; p < vg_ptr->pv_max; p++) {
+			if (vg_ptr->pv[p] != NULL &&
+			    pe_lock_req.data.pv_dev ==
+			    vg_ptr->pv[p]->pv_dev)
+				break;
+		}
+		if (p == vg_ptr->pv_max) return -ENXIO;
+
+		pe_lock_req.lock = UNLOCK_PE;
+		fsync_dev(pe_lock_req.data.lv_dev);
+		pe_lock_req.lock = LOCK_PE;
+		break;
+
+	case UNLOCK_PE:
+		pe_lock_req.lock = UNLOCK_PE;
+		pe_lock_req.data.lv_dev = \
+		pe_lock_req.data.pv_dev = \
+		pe_lock_req.data.pv_offset = 0;
+		wake_up(&lvm_map_wait);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/*
+ * character device support function logical extend remap
+ */
+static int lvm_do_le_remap(vg_t *vg_ptr, void *arg)
+{
+	uint l, le;
+	lv_t *lv_ptr;
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (copy_from_user(&le_remap_req, arg,
+			   sizeof(le_remap_req_t)) != 0)
+		return -EFAULT;
+
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		lv_ptr = vg_ptr->lv[l];
+		if (lv_ptr != NULL &&
+		    strcmp(lv_ptr->lv_name,
+			       le_remap_req.lv_name) == 0) {
+			for (le = 0; le < lv_ptr->lv_allocated_le;
+			     le++) {
+				if (lv_ptr->lv_current_pe[le].dev ==
+				    le_remap_req.old_dev &&
+				    lv_ptr->lv_current_pe[le].pe ==
+				    le_remap_req.old_pe) {
+					lv_ptr->lv_current_pe[le].dev =
+					    le_remap_req.new_dev;
+					lv_ptr->lv_current_pe[le].pe =
+					    le_remap_req.new_pe;
+					return 0;
+				}
+			}
+			return -EINVAL;
+		}
+	}
+	return -ENXIO;
+} /* lvm_do_le_remap() */
+
+
+/*
+ * character device support function VGDA create
+ */
+int lvm_do_vg_create(int minor, void *arg)
+{
+	int snaporg_minor = 0;
+	ulong l, p;
+	lv_t lv;
+	vg_t *vg_ptr;
+	pv_t *pv_ptr;
+	lv_t *lv_ptr;
+
+	if (vg[VG_CHR(minor)] != NULL) return -EPERM;
+
+	if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
+		printk(KERN_CRIT
+		       "%s -- VG_CREATE: kmalloc error VG at line %d\n",
+		       lvm_name, __LINE__);
+		return -ENOMEM;
+	}
+	/* get the volume group structure */
+	if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
+		kfree(vg_ptr);
+		return -EFAULT;
+	}
+	/* we are not that active so far... */
+	vg_ptr->vg_status &= ~VG_ACTIVE;
+	vg[VG_CHR(minor)] = vg_ptr;
+
+	vg[VG_CHR(minor)]->pe_allocated = 0;
+	if (vg_ptr->pv_max > ABS_MAX_PV) {
+		printk(KERN_WARNING
+		       "%s -- Can't activate VG: ABS_MAX_PV too small\n",
+		       lvm_name);
+		kfree(vg_ptr);
+		vg[VG_CHR(minor)] = NULL;
+		return -EPERM;
+	}
+	if (vg_ptr->lv_max > ABS_MAX_LV) {
+		printk(KERN_WARNING
+		"%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
+		       lvm_name, vg_ptr->lv_max);
+		kfree(vg_ptr);
+		vg_ptr = NULL;
+		return -EPERM;
+	}
+	/* get the physical volume structures */
+	vg_ptr->pv_act = vg_ptr->pv_cur = 0;
+	for (p = 0; p < vg_ptr->pv_max; p++) {
+		/* user space address */
+		if ((pvp = vg_ptr->pv[p]) != NULL) {
+			pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL);
+			if (pv_ptr == NULL) {
+				printk(KERN_CRIT
+				       "%s -- VG_CREATE: kmalloc error PV at line %d\n",
+				       lvm_name, __LINE__);
+				lvm_do_vg_remove(minor);
+				return -ENOMEM;
+			}
+			if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) {
+				lvm_do_vg_remove(minor);
+				return -EFAULT;
+			}
+			/* We don't need the PE list
+			   in kernel space as with LVs pe_t list (see below) */
+			pv_ptr->pe = NULL;
+			pv_ptr->pe_allocated = 0;
+			pv_ptr->pv_status = PV_ACTIVE;
+			vg_ptr->pv_act++;
+			vg_ptr->pv_cur++;
+
+#ifdef LVM_GET_INODE
+			/* insert a dummy inode for fs_may_mount */
+			pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev);
+#endif
+		}
+	}
+
+	/* get the logical volume structures */
+	vg_ptr->lv_cur = 0;
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		/* user space address */
+		if ((lvp = vg_ptr->lv[l]) != NULL) {
+			if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
+				lvm_do_vg_remove(minor);
+				return -EFAULT;
+			}
+			vg_ptr->lv[l] = NULL;
+			if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
+				lvm_do_vg_remove(minor);
+				return -EFAULT;
+			}
+		}
+	}
+
+	/* Second path to correct snapshot logical volumes which are not
+	   in place during first path above */
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		if ((lv_ptr = vg_ptr->lv[l]) != NULL &&
+		    vg_ptr->lv[l]->lv_access & LV_SNAPSHOT) {
+			snaporg_minor = lv_ptr->lv_snapshot_minor;
+			if (vg_ptr->lv[LV_BLK(snaporg_minor)] != NULL) {
+				/* get pointer to original logical volume */
+				lv_ptr = vg_ptr->lv[l]->lv_snapshot_org =
+				vg_ptr->lv[LV_BLK(snaporg_minor)];
+
+				/* set necessary fields of original logical volume */
+				lv_ptr->lv_access |= LV_SNAPSHOT_ORG;
+				lv_ptr->lv_snapshot_minor = 0;
+				lv_ptr->lv_snapshot_org = lv_ptr;
+				lv_ptr->lv_snapshot_prev = NULL;
+
+				/* find last snapshot logical volume in the chain */
+				while (lv_ptr->lv_snapshot_next != NULL)
+					lv_ptr = lv_ptr->lv_snapshot_next;
+
+				/* set back pointer to this last one in our new logical volume */
+				vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr;
+
+				/* last logical volume now points to our new snapshot volume */
+				lv_ptr->lv_snapshot_next = vg_ptr->lv[l];
+
+				/* now point to the new one */
+				lv_ptr = lv_ptr->lv_snapshot_next;
+
+				/* set necessary fields of new snapshot logical volume */
+				lv_ptr->lv_snapshot_next = NULL;
+				lv_ptr->lv_current_pe =
+				    vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_pe;
+				lv_ptr->lv_allocated_le =
+				    vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_allocated_le;
+				lv_ptr->lv_current_le =
+				    vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_le;
+				lv_ptr->lv_size =
+				    vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_size;
+			}
+		}
+	}
+
+	vg_count++;
+
+	/* let's go active */
+	vg_ptr->vg_status |= VG_ACTIVE;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+} /* lvm_do_vg_create() */
+
+
+/*
+ * character device support function VGDA extend
+ */
+static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg)
+{
+	uint p;
+	pv_t *pv_ptr;
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr->pv_cur < vg_ptr->pv_max) {
+		for (p = 0; p < vg_ptr->pv_max; p++) {
+			if (vg_ptr->pv[p] == NULL) {
+				if ((pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL)) == NULL) {
+					printk(KERN_CRIT
+					       "%s -- VG_EXTEND: kmalloc error PV at line %d\n",
+					     lvm_name, __LINE__);
+					return -ENOMEM;
+				}
+				if (copy_from_user(pv_ptr, arg, sizeof(pv_t)) != 0) {
+					kfree(pv_ptr);
+					vg_ptr->pv[p] = NULL;
+				 	return -EFAULT;
+				}
+	
+				pv_ptr->pv_status = PV_ACTIVE;
+				/* We don't need the PE list
+				   in kernel space like LVs pe_t list */
+				pv_ptr->pe = NULL;
+				vg_ptr->pv_cur++;
+				vg_ptr->pv_act++;
+				vg_ptr->pe_total +=
+				    pv_ptr->pe_total;
+#ifdef LVM_GET_INODE
+				/* insert a dummy inode for fs_may_mount */
+				pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev);
+#endif
+				return 0;
+			}
+		}
+	}
+return -EPERM;
+} /* lvm_do_vg_extend() */
+
+
+/*
+ * character device support function VGDA reduce
+ */
+static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg)
+{
+	uint p;
+	pv_t *pv_ptr;
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0)
+		return -EFAULT;
+
+	for (p = 0; p < vg_ptr->pv_max; p++) {
+		pv_ptr = vg_ptr->pv[p];
+		if (pv_ptr != NULL &&
+		    strcmp(pv_ptr->pv_name,
+			       pv_name) == 0) {
+			if (pv_ptr->lv_cur > 0) return -EPERM;
+			vg_ptr->pe_total -=
+			    pv_ptr->pe_total;
+			vg_ptr->pv_cur--;
+			vg_ptr->pv_act--;
+#ifdef LVM_GET_INODE
+			lvm_clear_inode(pv_ptr->inode);
+#endif
+			kfree(pv_ptr);
+			/* Make PV pointer array contiguous */
+			for (; p < vg_ptr->pv_max - 1; p++)
+				vg_ptr->pv[p] = vg_ptr->pv[p + 1];
+			vg_ptr->pv[p + 1] = NULL;
+			return 0;
+		}
+	}
+	return -ENXIO;
+} /* lvm_do_vg_reduce */
+
+
+/*
+ * character device support function VGDA remove
+ */
+static int lvm_do_vg_remove(int minor)
+{
+	int i;
+	vg_t *vg_ptr = vg[VG_CHR(minor)];
+	pv_t *pv_ptr;
+
+	if (vg_ptr == NULL) return -ENXIO;
+
+#ifdef LVM_TOTAL_RESET
+	if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0)
+#else
+	if (vg_ptr->lv_open > 0)
+#endif
+		return -EPERM;
+
+	/* let's go inactive */
+	vg_ptr->vg_status &= ~VG_ACTIVE;
+
+	/* free LVs */
+	/* first free snapshot logical volumes */
+	for (i = 0; i < vg_ptr->lv_max; i++) {
+		if (vg_ptr->lv[i] != NULL &&
+		    vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) {
+			lvm_do_lv_remove(minor, NULL, i);
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+	}
+	/* then free the rest of the LVs */
+	for (i = 0; i < vg_ptr->lv_max; i++) {
+		if (vg_ptr->lv[i] != NULL) {
+			lvm_do_lv_remove(minor, NULL, i);
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+	}
+
+	/* free PVs */
+	for (i = 0; i < vg_ptr->pv_max; i++) {
+		if ((pv_ptr = vg_ptr->pv[i]) != NULL) {
+#ifdef DEBUG_KFREE
+			printk(KERN_DEBUG
+			       "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+#ifdef LVM_GET_INODE
+			lvm_clear_inode(pv_ptr->inode);
+#endif
+			kfree(pv_ptr);
+			vg[VG_CHR(minor)]->pv[i] = NULL;
+		}
+	}
+
+#ifdef DEBUG_KFREE
+	printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+	kfree(vg_ptr);
+	vg[VG_CHR(minor)] = NULL;
+
+	vg_count--;
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+} /* lvm_do_vg_remove() */
+
+
+/*
+ * character device support function logical volume create
+ */
+static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
+{
+	int l, le, l_new, p, size;
+	ulong lv_status_save;
+	lv_block_exception_t *lvbe = lv->lv_block_exception;
+	vg_t *vg_ptr = vg[VG_CHR(minor)];
+	lv_t *lv_ptr = NULL;
+
+	if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
+	if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK)
+		return -EINVAL;
+
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		if (vg_ptr->lv[l] != NULL &&
+		    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
+			return -EEXIST;
+	}
+
+	/* in case of lv_remove(), lv_create() pair; for eg. lvrename does this */
+	l_new = -1;
+	if (vg_ptr->lv[lv->lv_number] == NULL)
+		l_new = lv->lv_number;
+	else {
+		for (l = 0; l < vg_ptr->lv_max; l++) {
+			if (vg_ptr->lv[l] == NULL)
+				if (l_new == -1) l_new = l;
+		}
+	}
+	if (l_new == -1) return -EPERM;
+	else            l = l_new;
+
+	if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {;
+		printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n",
+		       lvm_name, __LINE__);
+		return -ENOMEM;
+	}
+	/* copy preloaded LV */
+	memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
+
+	lv_status_save = lv_ptr->lv_status;
+	lv_ptr->lv_status &= ~LV_ACTIVE;
+	lv_ptr->lv_snapshot_org = \
+	    lv_ptr->lv_snapshot_prev = \
+	    lv_ptr->lv_snapshot_next = NULL;
+	lv_ptr->lv_block_exception = NULL;
+	init_MUTEX(&lv_ptr->lv_snapshot_sem);
+	vg_ptr->lv[l] = lv_ptr;
+
+	/* get the PE structures from user space if this
+	   is no snapshot logical volume */
+	if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
+		size = lv_ptr->lv_allocated_le * sizeof(pe_t);
+		if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) {
+			printk(KERN_CRIT
+			       "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte "
+			       "at line %d\n",
+			       lvm_name, size, __LINE__);
+#ifdef DEBUG_KFREE
+			printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+			kfree(lv_ptr);
+			vg[VG_CHR(minor)]->lv[l] = NULL;
+			return -ENOMEM;
+		}
+		if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) {
+			vfree(lv_ptr->lv_current_pe);
+			kfree(lv_ptr);
+			vg_ptr->lv[l] = NULL;
+			return -EFAULT;
+		}
+		/* correct the PE count in PVs */
+		for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+			vg_ptr->pe_allocated++;
+			for (p = 0; p < vg_ptr->pv_cur; p++) {
+				if (vg_ptr->pv[p]->pv_dev ==
+				    lv_ptr->lv_current_pe[le].dev)
+					vg_ptr->pv[p]->pe_allocated++;
+			}
+		}
+	} else {
+		/* Get snapshot exception data and block list */
+		if (lvbe != NULL) {
+			lv_ptr->lv_snapshot_org =
+			    vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
+			if (lv_ptr->lv_snapshot_org != NULL) {
+				size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
+				if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) {
+					printk(KERN_CRIT
+					       "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION "
+					       "of %d byte at line %d\n",
+					       lvm_name, size, __LINE__);
+#ifdef DEBUG_KFREE
+					printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+					kfree(lv_ptr);
+					vg_ptr->lv[l] = NULL;
+					return -ENOMEM;
+				}
+				if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) {
+					vfree(lv_ptr->lv_block_exception);
+					kfree(lv_ptr);
+					vg[VG_CHR(minor)]->lv[l] = NULL;
+					return -EFAULT;
+				}
+				/* get pointer to original logical volume */
+				lv_ptr = lv_ptr->lv_snapshot_org;
+
+				lv_ptr->lv_snapshot_minor = 0;
+				lv_ptr->lv_snapshot_org = lv_ptr;
+				lv_ptr->lv_snapshot_prev = NULL;
+				/* walk thrugh the snapshot list */
+				while (lv_ptr->lv_snapshot_next != NULL)
+					lv_ptr = lv_ptr->lv_snapshot_next;
+				/* now lv_ptr points to the last existing snapshot in the chain */
+				vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr;
+				/* our new one now back points to the previous last in the chain */
+				lv_ptr = vg_ptr->lv[l];
+				/* now lv_ptr points to our new last snapshot logical volume */
+				lv_ptr->lv_snapshot_org = lv_ptr->lv_snapshot_prev->lv_snapshot_org;
+				lv_ptr->lv_snapshot_next = NULL;
+				lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
+				lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
+				lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
+				lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
+				lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes;
+				lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize;
+				{
+					int err = lvm_snapshot_alloc(lv_ptr);
+					if (err)
+					{
+						vfree(lv_ptr->lv_block_exception);
+						kfree(lv_ptr);
+						vg[VG_CHR(minor)]->lv[l] = NULL;
+						 return err;
+					}
+				}
+			} else {
+				vfree(lv_ptr->lv_block_exception);
+				kfree(lv_ptr);
+				vg_ptr->lv[l] = NULL;
+				return -EFAULT;
+			}
+		} else {
+			kfree(vg_ptr->lv[l]);
+			vg_ptr->lv[l] = NULL;
+			return -EINVAL;
+		}
+	} /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
+
+	lv_ptr = vg_ptr->lv[l];
+	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
+	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
+	lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
+	vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number;
+	vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number;
+	LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
+	vg_ptr->lv_cur++;
+	lv_ptr->lv_status = lv_status_save;
+
+	/* optionally add our new snapshot LV */
+	if (lv_ptr->lv_access & LV_SNAPSHOT) {
+		/* sync the original logical volume */
+		fsync_dev(lv_ptr->lv_snapshot_org->lv_dev);
+		/* put ourselve into the chain */
+		lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr;
+		lv_ptr->lv_snapshot_org->lv_access |= LV_SNAPSHOT_ORG;
+	}
+	return 0;
+} /* lvm_do_lv_create() */
+
+
+/*
+ * character device support function logical volume remove
+ */
+static int lvm_do_lv_remove(int minor, char *lv_name, int l)
+{
+	uint le, p;
+	vg_t *vg_ptr = vg[VG_CHR(minor)];
+	lv_t *lv_ptr;
+
+	if (l == -1) {
+		for (l = 0; l < vg_ptr->lv_max; l++) {
+			if (vg_ptr->lv[l] != NULL &&
+			    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) {
+				break;
+			}
+		}
+	}
+	if (l == vg_ptr->lv_max) return -ENXIO;
+
+	lv_ptr = vg_ptr->lv[l];
+#ifdef LVM_TOTAL_RESET
+	if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0)
+#else
+	if (lv_ptr->lv_open > 0)
+#endif
+		return -EBUSY;
+
+	/* check for deletion of snapshot source while
+	   snapshot volume still exists */
+	if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) &&
+	    lv_ptr->lv_snapshot_next != NULL)
+		return -EPERM;
+
+	lv_ptr->lv_status |= LV_SPINDOWN;
+
+	/* sync the buffers */
+	fsync_dev(lv_ptr->lv_dev);
+
+	lv_ptr->lv_status &= ~LV_ACTIVE;
+
+	/* invalidate the buffers */
+	invalidate_buffers(lv_ptr->lv_dev);
+
+	/* reset generic hd */
+	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1;
+	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0;
+	lvm_size[MINOR(lv_ptr->lv_dev)] = 0;
+
+	/* reset VG/LV mapping */
+	vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG;
+	vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1;
+
+	/* correct the PE count in PVs if this is no snapshot logical volume */
+	if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
+		/* only if this is no snapshot logical volume because
+		   we share the lv_current_pe[] structs with the
+		   original logical volume */
+		for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+			vg_ptr->pe_allocated--;
+			for (p = 0; p < vg_ptr->pv_cur; p++) {
+				if (vg_ptr->pv[p]->pv_dev ==
+				    lv_ptr->lv_current_pe[le].dev)
+					vg_ptr->pv[p]->pe_allocated--;
+			}
+		}
+		vfree(lv_ptr->lv_current_pe);
+		/* LV_SNAPSHOT */
+	} else {
+		/* remove this snapshot logical volume from the chain */
+		lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next;
+		if (lv_ptr->lv_snapshot_next != NULL) {
+			lv_ptr->lv_snapshot_next->lv_snapshot_prev =
+			    lv_ptr->lv_snapshot_prev;
+		}
+		/* no more snapshots? */
+		if (lv_ptr->lv_snapshot_org->lv_snapshot_next == NULL)
+			lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG;
+		lvm_snapshot_release(lv_ptr);
+	}
+
+#ifdef DEBUG_KFREE
+	printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+	kfree(lv_ptr);
+	vg_ptr->lv[l] = NULL;
+	vg_ptr->lv_cur--;
+	return 0;
+} /* lvm_do_lv_remove() */
+
+
+/*
+ * character device support function logical volume extend / reduce
+ */
+static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv)
+{
+	int l, le, p, size, old_allocated_le;
+	uint32_t end, lv_status_save;
+	vg_t *vg_ptr = vg[VG_CHR(minor)];
+	lv_t *lv_ptr;
+	pe_t *pe;
+
+	if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
+
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		if (vg_ptr->lv[l] != NULL &&
+		    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
+			break;
+	}
+	if (l == vg_ptr->lv_max) return -ENXIO;
+	lv_ptr = vg_ptr->lv[l];
+
+	/* check for active snapshot */
+	if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) return -EPERM;
+
+	if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) {
+		printk(KERN_CRIT
+		"%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE "
+		       "of %d Byte at line %d\n",
+		       lvm_name, size, __LINE__);
+		return -ENOMEM;
+	}
+	/* get the PE structures from user space */
+	if (copy_from_user(pe, pep, size)) {
+		vfree(pe);
+		return -EFAULT;
+	}
+
+#ifdef DEBUG
+	printk(KERN_DEBUG
+	       "%s -- fsync_dev and "
+	       "invalidate_buffers for %s [%s] in %s\n",
+	       lvm_name, lv_ptr->lv_name,
+	       kdevname(lv_ptr->lv_dev),
+	       vg_ptr->vg_name);
+#endif
+
+	lv_ptr->lv_status |= LV_SPINDOWN;
+	fsync_dev(lv_ptr->lv_dev);
+	lv_ptr->lv_status &= ~LV_ACTIVE;
+	invalidate_buffers(lv_ptr->lv_dev);
+
+	/* reduce allocation counters on PV(s) */
+	for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+		vg_ptr->pe_allocated--;
+		for (p = 0; p < vg_ptr->pv_cur; p++) {
+			if (vg_ptr->pv[p]->pv_dev ==
+			lv_ptr->lv_current_pe[le].dev) {
+				vg_ptr->pv[p]->pe_allocated--;
+				break;
+			}
+		}
+	}
+
+
+	/* save pointer to "old" lv/pe pointer array */
+	pep1 = lv_ptr->lv_current_pe;
+	end = lv_ptr->lv_current_le;
+
+	/* save open counter */
+	lv_open = lv_ptr->lv_open;
+
+	/* save # of old allocated logical extents */
+	old_allocated_le = lv_ptr->lv_allocated_le;
+
+	/* copy preloaded LV */
+	lv_status_save = lv->lv_status;
+	lv->lv_status |= LV_SPINDOWN;
+	lv->lv_status &= ~LV_ACTIVE;
+	memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
+	lv_ptr->lv_current_pe = pe;
+	lv_ptr->lv_open = lv_open;
+
+	/* save availiable i/o statistic data */
+	/* linear logical volume */
+	if (lv_ptr->lv_stripes < 2) {
+		/* Check what last LE shall be used */
+		if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le;
+		for (le = 0; le < end; le++) {
+			lv_ptr->lv_current_pe[le].reads  = pep1[le].reads;
+			lv_ptr->lv_current_pe[le].writes = pep1[le].writes;
+		}
+		/* striped logical volume */
+	} else {
+		uint i, j, source, dest, end, old_stripe_size, new_stripe_size;
+
+		old_stripe_size = old_allocated_le / lv_ptr->lv_stripes;
+		new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes;
+		end = old_stripe_size;
+		if (end > new_stripe_size) end = new_stripe_size;
+		for (i = source = dest = 0;
+		     i < lv_ptr->lv_stripes; i++) {
+			for (j = 0; j < end; j++) {
+				lv_ptr->lv_current_pe[dest + j].reads =
+				    pep1[source + j].reads;
+				lv_ptr->lv_current_pe[dest + j].writes =
+				    pep1[source + j].writes;
+			}
+			source += old_stripe_size;
+			dest += new_stripe_size;
+		}
+	}
+	vfree(pep1);
+	pep1 = NULL;
+
+
+	/* extend the PE count in PVs */
+	for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+		vg_ptr->pe_allocated++;
+		for (p = 0; p < vg_ptr->pv_cur; p++) {
+			if (vg_ptr->pv[p]->pv_dev ==
+			vg_ptr->lv[l]->lv_current_pe[le].dev) {
+				vg_ptr->pv[p]->pe_allocated++;
+				break;
+			}
+		}
+	}
+
+	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
+	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
+	lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
+	/* vg_lv_map array doesn't have to be changed here */
+
+	LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
+	lv_ptr->lv_status = lv_status_save;
+
+	return 0;
+} /* lvm_do_lv_extend_reduce() */
+
+
+/*
+ * character device support function logical volume status by name
+ */
+static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg)
+{
+	uint l;
+	ulong size;
+	lv_t lv;
+	lv_t *lv_ptr;
+	lv_status_byname_req_t lv_status_byname_req;
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (copy_from_user(&lv_status_byname_req, arg,
+			   sizeof(lv_status_byname_req_t)) != 0)
+		return -EFAULT;
+
+	if (lv_status_byname_req.lv == NULL) return -EINVAL;
+	if (copy_from_user(&lv, lv_status_byname_req.lv,
+			   sizeof(lv_t)) != 0)
+		return -EFAULT;
+
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		lv_ptr = vg_ptr->lv[l];
+		if (lv_ptr != NULL &&
+		    strcmp(lv_ptr->lv_name,
+			    lv_status_byname_req.lv_name) == 0) {
+			if (copy_to_user(lv_status_byname_req.lv,
+					 lv_ptr,
+					 sizeof(lv_t)) != 0)
+				return -EFAULT;
+
+			if (lv.lv_current_pe != NULL) {
+				size = lv_ptr->lv_allocated_le *
+				       sizeof(pe_t);
+				if (copy_to_user(lv.lv_current_pe,
+						 lv_ptr->lv_current_pe,
+						 size) != 0)
+					return -EFAULT;
+			}
+			return 0;
+		}
+	}
+	return -ENXIO;
+} /* lvm_do_lv_status_byname() */
+
+
+/*
+ * character device support function logical volume status by index
+ */
+static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg)
+{
+	ulong size;
+	lv_t lv;
+	lv_t *lv_ptr;
+	lv_status_byindex_req_t lv_status_byindex_req;
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (copy_from_user(&lv_status_byindex_req, arg,
+			   sizeof(lv_status_byindex_req)) != 0)
+		return -EFAULT;
+
+	if ((lvp = lv_status_byindex_req.lv) == NULL)
+		return -EINVAL;
+	if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
+		return -ENXIO;
+
+	if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0)
+		return -EFAULT;
+
+	if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0)
+		return -EFAULT;
+
+	if (lv.lv_current_pe != NULL) {
+		size = lv_ptr->lv_allocated_le * sizeof(pe_t);
+		if (copy_to_user(lv.lv_current_pe,
+			 	 lv_ptr->lv_current_pe,
+				 size) != 0)
+			return -EFAULT;
+	}
+	return 0;
+} /* lvm_do_lv_status_byindex() */
+
+
+/*
+ * character device support function physical volume change
+ */
+static int lvm_do_pv_change(vg_t *vg_ptr, void *arg)
+{
+	uint p;
+	pv_t *pv_ptr;
+#ifdef LVM_GET_INODE
+	struct inode *inode_sav;
+#endif
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (copy_from_user(&pv_change_req, arg,
+			   sizeof(pv_change_req)) != 0)
+		return -EFAULT;
+
+	for (p = 0; p < vg_ptr->pv_max; p++) {
+		pv_ptr = vg_ptr->pv[p];
+		if (pv_ptr != NULL &&
+		    strcmp(pv_ptr->pv_name,
+			       pv_change_req.pv_name) == 0) {
+#ifdef LVM_GET_INODE
+			inode_sav = pv_ptr->inode;
+#endif
+			if (copy_from_user(pv_ptr,
+					   pv_change_req.pv,
+					   sizeof(pv_t)) != 0)
+				return -EFAULT;
+
+			/* We don't need the PE list
+			   in kernel space as with LVs pe_t list */
+			pv_ptr->pe = NULL;
+#ifdef LVM_GET_INODE
+			pv_ptr->inode = inode_sav;
+#endif
+			return 0;
+		}
+	}
+	return -ENXIO;
+} /* lvm_do_pv_change() */
+
+/*
+ * character device support function get physical volume status
+ */
+static int lvm_do_pv_status(vg_t *vg_ptr, void *arg)
+{
+	uint p;
+	pv_t *pv_ptr;
+
+	if (vg_ptr == NULL) return -ENXIO;
+	if (copy_from_user(&pv_status_req, arg,
+			   sizeof(pv_status_req)) != 0)
+		return -EFAULT;
+
+	for (p = 0; p < vg_ptr->pv_max; p++) {
+		pv_ptr = vg_ptr->pv[p];
+		if (pv_ptr != NULL &&
+		    strcmp(pv_ptr->pv_name,
+			       pv_status_req.pv_name) == 0) {
+			if (copy_to_user(pv_status_req.pv,
+					 pv_ptr,
+				         sizeof(pv_t)) != 0)
+				return -EFAULT;
+			return 0;
+		}
+	}
+	return -ENXIO;
+} /* lvm_do_pv_status() */
+
+
+/*
+ * support function initialize gendisk variables
+ */
+#ifdef __initfunc
+__initfunc(void lvm_geninit(struct gendisk *lvm_gdisk))
+#else
+void __init
+ lvm_geninit(struct gendisk *lvm_gdisk)
+#endif
+{
+	int i = 0;
+
+#ifdef DEBUG_GENDISK
+	printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name);
+#endif
+
+	for (i = 0; i < MAX_LV; i++) {
+		lvm_gendisk.part[i].start_sect = -1;	/* avoid partition check */
+		lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0;
+		lvm_blocksizes[i] = BLOCK_SIZE;
+	}
+
+	blksize_size[MAJOR_NR] = lvm_blocksizes;
+	blk_size[MAJOR_NR] = lvm_size;
+
+	return;
+} /* lvm_gen_init() */
+
+
+#ifdef LVM_GET_INODE
+/*
+ * support function to get an empty inode
+ *
+ * Gets an empty inode to be inserted into the inode hash,
+ * so that a physical volume can't be mounted.
+ * This is analog to drivers/block/md.c
+ *
+ * Is this the real thing?
+ *
+ */
+struct inode *lvm_get_inode(int dev)
+{
+	struct inode *inode_this = NULL;
+
+	/* Lock the device by inserting a dummy inode. */
+	inode_this = get_empty_inode();
+	inode_this->i_dev = dev;
+	insert_inode_hash(inode_this);
+	return inode_this;
+}
+
+
+/*
+ * support function to clear an inode
+ *
+ */
+void lvm_clear_inode(struct inode *inode)
+{
+#ifdef I_FREEING
+	inode->i_state |= I_FREEING;
+#endif
+	clear_inode(inode);
+	return;
+}
+#endif /* #ifdef LVM_GET_INODE */
diff -u --recursive --new-file v2.3.46/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.3.46/linux/drivers/block/md.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/md.c	Thu Feb 17 15:24:52 2000
@@ -3314,7 +3314,7 @@
 		return (-1);
 	}
 	devfs_handle = devfs_mk_dir (NULL, "md", 0, NULL);
-	devfs_register_series (devfs_handle, "%u", MAX_MD_DEV,DEVFS_FL_DEFAULT,
+	devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT,
 			       MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
 			       &md_fops, NULL);
 
diff -u --recursive --new-file v2.3.46/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.3.46/linux/drivers/block/nbd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/nbd.c	Thu Feb 17 09:09:27 2000
@@ -248,7 +248,6 @@
 void nbd_clear_que(struct nbd_device *lo)
 {
 	struct request *req;
-	unsigned long flags;
 
 	while (!list_empty(&lo->queue_head)) {
 		req = blkdev_entry_prev_request(&lo->queue_head);
@@ -405,8 +404,8 @@
 		return 0;
 #ifdef PARANOIA
 	case NBD_PRINT_DEBUG:
-		printk(KERN_INFO "NBD device %d: queue_head = %p. Global: in %d, out %d\n",
-		       dev, lo->queue_head, requests_in, requests_out);
+		printk(KERN_INFO "NBD device %d: next = %p, prev = %p. Global: in %d, out %d\n",
+		       dev, lo->queue_head.next, lo->queue_head.prev, requests_in, requests_out);
 		return 0;
 #endif
 	case BLKGETSIZE:
diff -u --recursive --new-file v2.3.46/linux/drivers/block/raid1.c linux/drivers/block/raid1.c
--- v2.3.46/linux/drivers/block/raid1.c	Thu Aug 12 10:16:28 1999
+++ linux/drivers/block/raid1.c	Sun Feb 20 20:23:20 2000
@@ -211,7 +211,11 @@
 	while (!( /* FIXME: now we are rather fault tolerant than nice */
 	r1_bh = kmalloc (sizeof (struct raid1_bh), GFP_KERNEL)
 	) )
+	{
 		printk ("raid1_make_request(#1): out of memory\n");
+		current->policy |= SCHED_YIELD;
+		schedule();
+	}
 	memset (r1_bh, 0, sizeof (struct raid1_bh));
 
 /*
@@ -298,7 +302,11 @@
 		while (!( /* FIXME: now we are rather fault tolerant than nice */
 		mirror_bh[i] = kmalloc (sizeof (struct buffer_head), GFP_KERNEL)
 		) )
+		{
 			printk ("raid1_make_request(#2): out of memory\n");
+			current->policy |= SCHED_YIELD;
+			schedule();
+		}
 		memset (mirror_bh[i], 0, sizeof (struct buffer_head));
 
 	/*
@@ -710,7 +718,11 @@
 	while (!( /* FIXME: now we are rather fault tolerant than nice */
 	mddev->private = kmalloc (sizeof (struct raid1_data), GFP_KERNEL)
 	) )
+	{
 		printk ("raid1_run(): out of memory\n");
+		current->policy |= SCHED_YIELD;
+		schedule();
+	}
 	raid_conf = mddev->private;
 	memset(raid_conf, 0, sizeof(*raid_conf));
 
diff -u --recursive --new-file v2.3.46/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.46/linux/drivers/char/Makefile	Wed Feb 16 17:03:51 2000
+++ linux/drivers/char/Makefile	Sun Feb 20 20:37:09 2000
@@ -36,7 +36,7 @@
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
-export-objs     :=	busmouse.o console.o i2c-old.o keyboard.o \
+export-objs     :=	busmouse.o console.o i2c-old.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o videodev.o \
 			tty_io.o
 
@@ -144,13 +144,14 @@
 obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
 obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
 obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
-obj-$(CONFIG_ADBMOUSE) += adbmouse.o
+obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o
 obj-$(CONFIG_PC110_PAD) += pc110pad.o
 obj-$(CONFIG_WDT) += wdt.o
 obj-$(CONFIG_RTC) += rtc.o
 ifeq ($(CONFIG_PPC),)
   obj-$(CONFIG_NVRAM) += nvram.o
 endif
+obj-$(CONFIG_I810_RNG) += i810_rng.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o
 
diff -u --recursive --new-file v2.3.46/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.3.46/linux/drivers/char/console.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/char/console.c	Sun Feb 20 20:37:09 2000
@@ -1816,6 +1816,8 @@
 	unsigned long draw_from = 0, draw_to = 0;
 	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
 	u16 himask, charmask;
+	const unsigned char *orig_buf = NULL;
+	int orig_count;
 
 	currcons = vt->vc_num;
 	if (!vc_cons_allocated(currcons)) {
@@ -1828,9 +1830,13 @@
 	    return 0;
 	}
 
-	down(&con_buf_sem);
+	orig_buf = buf;
+	orig_count = count;
 
 	if (from_user) {
+		down(&con_buf_sem);
+
+again:
 		if (count > CON_BUF_SIZE)
 			count = CON_BUF_SIZE;
 		if (copy_from_user(con_buf, buf, count)) {
@@ -1969,7 +1975,21 @@
 	spin_unlock_irq(&console_lock);
 
 out:
-	up(&con_buf_sem);
+	if (from_user) {
+		/* If the user requested something larger than
+		 * the CON_BUF_SIZE, and the tty is not stopped,
+		 * keep going.
+		 */
+		if ((orig_count > CON_BUF_SIZE) && !tty->stopped) {
+			orig_count -= CON_BUF_SIZE;
+			orig_buf += CON_BUF_SIZE;
+			count = orig_count;
+			buf = orig_buf;
+			goto again;
+		}
+
+		up(&con_buf_sem);
+	}
 
 	return n;
 #undef FLUSH
@@ -2911,6 +2931,7 @@
 EXPORT_SYMBOL(video_scan_lines);
 EXPORT_SYMBOL(vc_resize);
 EXPORT_SYMBOL(fg_console);
+EXPORT_SYMBOL(console_blank_hook);
 
 #ifndef VT_SINGLE_DRIVER
 EXPORT_SYMBOL(take_over_console);
diff -u --recursive --new-file v2.3.46/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c
--- v2.3.46/linux/drivers/char/ftape/zftape/zftape-init.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/char/ftape/zftape/zftape-init.c	Thu Feb 17 09:56:46 2000
@@ -436,7 +436,7 @@
 	TRACE_CATCH(devfs_register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
 
 	for (i = 0; i < 4; i++) {
-		char devname[8];
+		char devname[9];
 
 		sprintf (devname, "qft%i", i);
 		devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
@@ -510,7 +510,7 @@
 void cleanup_module(void)
 {
 	int i;
-	char devname[8];
+	char devname[9];
 
 	TRACE_FUN(ft_t_flow);
 
diff -u --recursive --new-file v2.3.46/linux/drivers/char/h8.c linux/drivers/char/h8.c
--- v2.3.46/linux/drivers/char/h8.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/char/h8.c	Sun Feb 20 14:14:16 2000
@@ -260,7 +260,7 @@
 	        return;
 	    } else if (data_reg == H8_SYNC_BYTE) {
 	        h8_state = H8_IDLE;
-		if (!QUEUE_EMPTY(&h8_actq, link))
+		if (!QUEUE_IS_EMPTY(&h8_actq, link))
 		    h8_send_next_cmd_byte();
 	    } else {
 	        Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
@@ -279,7 +279,7 @@
 		    QUEUE_REMOVE(&h8_actq, qp, link);
 		    h8_cmd_done (qp);
 		    /* More commands to send over? */
-		    if (!QUEUE_EMPTY(&h8_cmdq, link))
+		    if (!QUEUE_IS_EMPTY(&h8_cmdq, link))
 		        h8_start_new_cmd();
 		}
 		return;
@@ -458,7 +458,7 @@
 
         /* get cmd buf */
 	save_flags(flags); cli();
-        while (QUEUE_EMPTY(&h8_freeq, link)) {
+        while (QUEUE_IS_EMPTY(&h8_freeq, link)) {
                 Dprintk("H8: need to allocate more cmd buffers\n");
                 restore_flags(flags);
                 h8_alloc_queues();
@@ -500,13 +500,13 @@
                 return;
         }
 
-        if (!QUEUE_EMPTY(&h8_actq, link)) {
+        if (!QUEUE_IS_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)) {
+        if (QUEUE_IS_EMPTY(&h8_cmdq, link)) {
                 Dprintk("h8_start_new_cmd: no command to dequeue\n");
                 restore_flags(flags);
                 return;
diff -u --recursive --new-file v2.3.46/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c
--- v2.3.46/linux/drivers/char/joystick/joystick.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/joystick/joystick.c	Sun Feb 20 20:23:20 2000
@@ -738,12 +738,6 @@
 
 	curd->name = all += axes * sizeof(struct js_corr);
 	strcpy(curd->name, name);
-	sprintf (devfs_name, "analogue%d", number);
-	curd->devfs_handle = devfs_register (devfs_handle, devfs_name, 0,
-					     DEVFS_FL_DEFAULT,
-					     JOYSTICK_MAJOR, number,
-					     S_IFCHR | S_IRUGO | S_IWUSR, 0, 0,
-					     &js_fops, NULL);
 
 	port->devs[number] = curd;
 	port->axes[number] = curd->new.axes;
@@ -757,6 +751,13 @@
 
 	spin_unlock_irqrestore(&js_lock, flags);	
 
+	sprintf(devfs_name, "js%d", i);
+	curd->devfs_handle = devfs_register(devfs_handle, devfs_name, 0,
+					    DEVFS_FL_DEFAULT,
+					    JOYSTICK_MAJOR, i,
+					    S_IFCHR | S_IRUGO | S_IWUSR, 0, 0,
+					    &js_fops, NULL);
+
 	return i;
 }
 
@@ -772,7 +773,7 @@
 
 	spin_unlock_irqrestore(&js_lock, flags);	
 
-	devfs_unregister (dev->devfs_handle);
+	devfs_unregister(dev->devfs_handle);
 	kfree(dev);
 }
 
@@ -805,7 +806,7 @@
 		printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
 		return -EBUSY;
 	}
-	devfs_handle = devfs_mk_dir (NULL, "joysticks", 9, NULL);
+	devfs_handle = devfs_mk_dir(NULL, "joysticks", 9, NULL);
 
 	printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik <vojtech@suse.cz>\n",
 		JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
@@ -885,9 +886,9 @@
 void cleanup_module(void)
 {
 	del_timer(&js_timer);
-	devfs_unregister (devfs_handle);
+	devfs_unregister(devfs_handle);
 	if (devfs_unregister_chrdev(JOYSTICK_MAJOR, "js"))
-	printk(KERN_ERR "js: can't unregister device\n");
+		printk(KERN_ERR "js: can't unregister device\n");
 }
 #endif
 
diff -u --recursive --new-file v2.3.46/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.3.46/linux/drivers/char/lp.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/lp.c	Thu Feb 17 15:24:52 2000
@@ -237,7 +237,6 @@
 	ssize_t retv = 0;
 	ssize_t written;
 	size_t copy_size = count;
-	long old_to;
 
 #ifdef LP_STATS
 	if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
@@ -263,8 +262,8 @@
 	/* Go to compatibility mode. */
 	parport_negotiate (port, IEEE1284_MODE_COMPAT);
 
-	old_to = parport_set_timeout (lp_table[minor].dev,
-				      lp_table[minor].timeout);
+	parport_set_timeout (lp_table[minor].dev,
+			     lp_table[minor].timeout);
 
 	do {
 		/* Write the data. */
@@ -310,9 +309,6 @@
 		}	
 	} while (count > 0);
 
-	/* Not really necessary, but polite. */
-	parport_set_timeout (lp_table[minor].dev, old_to);
-
  	parport_release (lp_table[minor].dev);
 
 	up (&lp_table[minor].port_mutex);
@@ -564,13 +560,12 @@
 	struct pardevice *dev = lp_table[CONSOLE_LP].dev;
 	struct parport *port = dev->port;
 	ssize_t written;
-	signed long old_to;
 
 	if (parport_claim (dev))
 		/* Nothing we can do. */
 		return;
 
-	old_to = parport_set_timeout (dev, 0);
+	parport_set_timeout (dev, 0);
 
 	/* Go to compatibility mode. */
 	parport_negotiate (port, IEEE1284_MODE_COMPAT);
@@ -608,7 +603,6 @@
 		}
 	} while (count > 0 && (CONSOLE_LP_STRICT || written > 0));
 
-	parport_set_timeout (dev, old_to);
 	parport_release (dev);
 }
 
@@ -680,6 +674,8 @@
 
 static int lp_register(int nr, struct parport *port)
 {
+	char name[8];
+
 	lp_table[nr].dev = parport_register_device(port, "lp", 
 						   NULL, NULL, NULL, 0,
 						   (void *) &lp_table[nr]);
@@ -690,6 +686,12 @@
 	if (reset)
 		lp_reset(nr);
 
+	sprintf (name, "%d", nr);
+	devfs_register (devfs_handle, name, 0,
+			DEVFS_FL_DEFAULT, LP_MAJOR, nr,
+			S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+			&lp_fops, NULL);
+
 	printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
 	       (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
 
@@ -787,26 +789,12 @@
 	}
 
 	devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL);
-	if (lp_count) {
-		for (i = 0; i < LP_NO; ++i)
-		{
-		    char name[8];
-
-		    if (!(lp_table[i].flags & LP_EXIST)) 
-			continue; /* skip this entry: it doesn't exist. */
-		    sprintf (name, "%d", i);
-		    devfs_register (devfs_handle, name, 0,
-				    DEVFS_FL_DEFAULT, LP_MAJOR, i,
-				    S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
-				    &lp_fops, NULL);
-		}
-	}
 
 	if (!lp_count) {
 		printk (KERN_INFO "lp: driver loaded but no devices found\n");
-#ifndef CONFIG_PARPORT_12843
+#ifndef CONFIG_PARPORT_1284
 		if (parport_nr[0] == LP_PARPORT_AUTO)
-			printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n");
+			printk (KERN_INFO "lp: (is IEEE 1284 support enabled?)\n");
 #endif
 	}
 
diff -u --recursive --new-file v2.3.46/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.46/linux/drivers/char/ppdev.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/ppdev.c	Thu Feb 17 15:29:44 2000
@@ -45,7 +45,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/ioctl.h>
 #include <linux/parport.h>
diff -u --recursive --new-file v2.3.46/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.3.46/linux/drivers/char/pty.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/pty.c	Thu Feb 17 15:29:44 2000
@@ -10,7 +10,6 @@
 #include <linux/config.h>
 #include <linux/module.h>	/* For EXPORT_SYMBOL */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.3.46/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.3.46/linux/drivers/char/rtc.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/rtc.c	Thu Feb 17 09:44:11 2000
@@ -97,14 +97,18 @@
 static int rtc_ioctl(struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg);
 
+#ifndef __alpha__
 static unsigned int rtc_poll(struct file *file, poll_table *wait);
+#endif
 
 static void get_rtc_time (struct rtc_time *rtc_tm);
 static void get_rtc_alm_time (struct rtc_time *alm_tm);
+#ifndef __alpha__
 static void rtc_dropped_irq(unsigned long data);
 
 static void set_rtc_irq_bit(unsigned char bit);
 static void mask_rtc_irq_bit(unsigned char bit);
+#endif
 
 static inline unsigned char rtc_is_updating(void);
 
@@ -132,6 +136,7 @@
 static const unsigned char days_in_mo[] = 
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
+#ifndef __alpha__
 /*
  *	A very tiny interrupt handler. It runs with SA_INTERRUPT set,
  *	so that there is no possibility of conflicting with the
@@ -162,6 +167,7 @@
 	if (atomic_read(&rtc_status) & RTC_TIMER_ON)
 		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
 }
+#endif
 
 /*
  *	Now all the various file operations that we export.
@@ -175,6 +181,9 @@
 static ssize_t rtc_read(struct file *file, char *buf,
 			size_t count, loff_t *ppos)
 {
+#ifdef __alpha__
+	return -EIO;
+#else
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long data;
 	ssize_t retval;
@@ -206,6 +215,7 @@
 	remove_wait_queue(&rtc_wait, &wait);
 
 	return retval;
+#endif
 }
 
 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -216,6 +226,7 @@
 	struct rtc_time wtime; 
 
 	switch (cmd) {
+#ifndef __alpha__
 	case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
 	{
 		mask_rtc_irq_bit(RTC_AIE);
@@ -265,6 +276,7 @@
 		set_rtc_irq_bit(RTC_UIE);
 		return 0;
 	}
+#endif
 	case RTC_ALM_READ:	/* Read the present alarm time */
 	{
 		/*
@@ -398,6 +410,7 @@
 		spin_unlock_irqrestore(&rtc_lock, flags);
 		return 0;
 	}
+#ifndef __alpha__
 	case RTC_IRQP_READ:	/* Read the periodic IRQ rate.	*/
 	{
 		return put_user(rtc_freq, (unsigned long *)arg);
@@ -437,7 +450,7 @@
 		spin_unlock_irqrestore(&rtc_lock, flags);
 		return 0;
 	}
-#ifdef __alpha__
+#else
 	case RTC_EPOCH_READ:	/* Read the epoch.	*/
 	{
 		return put_user (epoch, (unsigned long *)arg);
@@ -494,13 +507,14 @@
 
 static int rtc_release(struct inode *inode, struct file *file)
 {
+	unsigned long flags;
+#ifndef __alpha__
 	/*
 	 * Turn off all interrupts once the device is no longer
 	 * in use, and clear the data.
 	 */
 
 	unsigned char tmp;
-	unsigned long flags;
 
 	spin_lock_irqsave(&rtc_lock, flags);
 	tmp = CMOS_READ(RTC_CONTROL);
@@ -520,6 +534,7 @@
 		rtc_fasync (-1, file, 0);
 	}
 
+#endif
 	MOD_DEC_USE_COUNT;
 
 	spin_lock_irqsave (&rtc_lock, flags);
@@ -529,6 +544,7 @@
 	return 0;
 }
 
+#ifndef __alpha__
 static unsigned int rtc_poll(struct file *file, poll_table *wait)
 {
 	unsigned long l, flags;
@@ -543,6 +559,7 @@
 		return POLLIN | POLLRDNORM;
 	return 0;
 }
+#endif
 
 /*
  *	The various file operations we support.
@@ -551,7 +568,9 @@
 static struct file_operations rtc_fops = {
 	llseek:		rtc_llseek,
 	read:		rtc_read,
+#ifndef __alpha__
 	poll:		rtc_poll,
+#endif
 	ioctl:		rtc_ioctl,
 	open:		rtc_open,
 	release:	rtc_release,
@@ -612,12 +631,14 @@
 		return -EIO;
 	}
 
+#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(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
 		return -EIO;
 	}
+#endif
 
 	request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
 #endif /* __sparc__ vs. others */
@@ -654,12 +675,14 @@
 	if (guess)
 		printk("rtc: %s epoch (%lu) detected\n", guess, epoch);
 #endif
+#ifndef __alpha__
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
 	spin_lock_irqsave(&rtc_lock, flags);
 	/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
 	spin_unlock_irqrestore(&rtc_lock, flags);
+#endif
 	rtc_freq = 1024;
 
 	printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
@@ -689,6 +712,7 @@
 module_exit(rtc_exit);
 EXPORT_NO_SYMBOLS;
 
+#ifndef __alpha__
 /*
  * 	At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
  *	(usually during an IDE disk interrupt, with IRQ unmasking off)
@@ -714,6 +738,7 @@
 	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */
 	spin_unlock_irqrestore(&rtc_lock, flags);
 }
+#endif
 
 /*
  *	Info exported via "/proc/driver/rtc".
@@ -902,6 +927,7 @@
 	}
 }
 
+#ifndef __alpha__
 /*
  * Used to disable/enable interrupts for any one of UIE, AIE, PIE.
  * Rumour has it that if you frob the interrupt enable/disable
@@ -939,3 +965,4 @@
 	rtc_irq_data = 0;
 	spin_unlock_irqrestore(&rtc_lock, flags);
 }
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.3.46/linux/drivers/char/stallion.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/stallion.c	Sun Feb 20 20:23:20 2000
@@ -751,6 +751,8 @@
 
 /*****************************************************************************/
 
+static devfs_handle_t devfs_handle = NULL;
+
 #ifdef MODULE
 
 /*
@@ -774,8 +776,6 @@
 }
 
 /*****************************************************************************/
-
-static devfs_handle_t devfs_handle = NULL;
 
 void cleanup_module()
 {
diff -u --recursive --new-file v2.3.46/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.3.46/linux/drivers/char/sysrq.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/char/sysrq.c	Sun Feb 20 20:37:09 2000
@@ -21,6 +21,7 @@
 #include <linux/kbd_kern.h>
 #include <linux/quotaops.h>
 #include <linux/smp_lock.h>
+#include <linux/module.h>
 
 #include <asm/ptrace.h>
 
@@ -31,6 +32,8 @@
 
 /* Machine specific power off function */
 void (*sysrq_power_off)(void) = NULL;
+
+EXPORT_SYMBOL(sysrq_power_off);
 
 /* Send a signal to all user processes */
 
diff -u --recursive --new-file v2.3.46/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.3.46/linux/drivers/char/vc_screen.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/vc_screen.c	Sun Feb 20 20:19:12 2000
@@ -21,6 +21,7 @@
  *	 - making it shorter - scr_readw are macros which expand in PRETTY long code
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/errno.h>
@@ -37,6 +38,7 @@
 #include <linux/console.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #undef attr
 #undef org
@@ -175,71 +177,58 @@
 				con_buf0[1] = (char) video_num_columns;
 				getconsxy(currcons, con_buf0 + 2);
 
-				tmp_count = HEADER_SIZE - p;
+				con_buf_start += p;
+				this_round += p;
+				if (this_round > CON_BUF_SIZE) {
+					this_round = CON_BUF_SIZE;
+					orig_count = this_round - p;
+				}
+
+				tmp_count = HEADER_SIZE;
 				if (tmp_count > this_round)
 					tmp_count = this_round;
 
 				/* Advance state pointers and move on. */
 				this_round -= tmp_count;
-				con_buf_start += p;
-				orig_count -= p;
-				p += tmp_count;
-				con_buf0 = con_buf + p;
+				p = HEADER_SIZE;
+				con_buf0 = con_buf + HEADER_SIZE;
+				/* If this_round >= 0, then p is even... */
+			} else if (p & 1) {
+				/* Skip first byte for output if start address is odd
+				 * Update region sizes up/down depending on free
+				 * space in buffer.
+				 */
+				con_buf_start++;
+				if (this_round < CON_BUF_SIZE)
+					this_round++;
+				else
+					orig_count--;
 			}
-			p -= HEADER_SIZE;
-			col = (p/2) % maxcol;
 			if (this_round > 0) {
-				char tmp_byte;
-
-				org = screen_pos(currcons, p/2, viewed);
-				if ((p & 1) && this_round > 0) {
-#ifdef __BIG_ENDIAN
-					tmp_byte = vcs_scr_readw(currcons, org++) & 0xff;
-#else
-					tmp_byte = vcs_scr_readw(currcons, org++) >> 8;
-#endif
-
-					*con_buf0++ = tmp_byte;
+				unsigned short *tmp_buf = (unsigned short *)con_buf0;
 
-					this_round--;   
-					p++;
-					if (++col == maxcol) {
-						org = screen_pos(currcons, p/2, viewed);
-						col = 0;
-					}
-				}
+				p -= HEADER_SIZE;
 				p /= 2;
+				col = p % maxcol;
+
+				org = screen_pos(currcons, p, viewed);
 				p += maxcol - col;
-			}
 
-			if (this_round > 1) {
-				size_t tmp_count = this_round;
-				unsigned short *tmp_buf = (unsigned short *)con_buf0;
+				/* Buffer has even length, so we can always copy
+				 * character + attribute. We do not copy last byte
+				 * to userspace if this_round is odd.
+				 */
+				this_round = (this_round + 1) >> 1;
 
-				while (tmp_count > 1) {
+				while (this_round) {
 					*tmp_buf++ = vcs_scr_readw(currcons, org++);
-					tmp_count -= 2;
+					this_round --;
 					if (++col == maxcol) {
 						org = screen_pos(currcons, p, viewed);
 						col = 0;
 						p += maxcol;
 					}
 				}
-
-				/* Advance pointers, and move on. */
-				this_round = tmp_count;
-				con_buf0 = (char*)tmp_buf;
-			}
-			if (this_round > 0) {
-				char tmp_byte;
-
-#ifdef __BIG_ENDIAN
-				tmp_byte = vcs_scr_readw(currcons, org) >> 8;
-#else
-				tmp_byte = vcs_scr_readw(currcons, org) & 0xff;
-#endif
-
-				*con_buf0++ = tmp_byte;
 			}
 		}
 
@@ -415,7 +404,7 @@
 			while (this_round > 1) {
 				unsigned short w;
 
-				w = *((const unsigned short *)con_buf0);
+				w = get_unaligned(((const unsigned short *)con_buf0));
 				vcs_scr_writew(currcons, w, org++);
 				con_buf0 += 2;
 				this_round -= 2;
diff -u --recursive --new-file v2.3.46/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.3.46/linux/drivers/char/vt.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/vt.c	Sun Feb 20 08:48:45 2000
@@ -106,12 +106,13 @@
 {
 	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
 						 kd_nosound };
-
 	unsigned int count = 0;
+	unsigned long flags;
 
 	if (hz > 20 && hz < 32767)
 		count = 1193180 / hz;
 	
+	save_flags(flags);
 	cli();
 	del_timer(&sound_timer);
 	if (count) {
@@ -129,7 +130,7 @@
 		}
 	} else
 		kd_nosound(0);
-	sti();
+	restore_flags(flags);
 	return;
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/fc4/fc.c linux/drivers/fc4/fc.c
--- v2.3.46/linux/drivers/fc4/fc.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/fc4/fc.c	Fri Feb 18 15:07:20 2000
@@ -56,17 +56,21 @@
 #ifdef __sparc__
 #define dma_alloc_consistent(d,s,p) sbus_alloc_consistent(d,s,p)
 #define dma_free_consistent(d,s,v,h) sbus_free_consistent(d,s,v,h)
-#define dma_map_single(d,v,s) sbus_map_single(d,v,s)
-#define dma_unmap_single(d,h,s) sbus_unmap_single(d,h,s)
-#define dma_map_sg(d,s,n) sbus_map_sg(d,s,n)
-#define dma_unmap_sg(d,s,n) sbus_unmap_sg(d,s,n)
+#define dma_map_single(d,v,s,dir) sbus_map_single(d,v,s,dir)
+#define dma_unmap_single(d,h,s,dir) sbus_unmap_single(d,h,s,dir)
+#define dma_map_sg(d,s,n,dir) sbus_map_sg(d,s,n,dir)
+#define dma_unmap_sg(d,s,n,dir) sbus_unmap_sg(d,s,n,dir)
+#define scsi_to_fc_dma_dir(dir)	scsi_to_sbus_dma_dir(dir)
+#define FC_DMA_BIDIRECTIONAL	SBUS_DMA_BIDIRECTIONAL
 #else
 #define dma_alloc_consistent(d,s,p) pci_alloc_consistent(d,s,p)
 #define dma_free_consistent(d,s,v,h) pci_free_consistent(d,s,v,h)
-#define dma_map_single(d,v,s) pci_map_single(d,v,s)
-#define dma_unmap_single(d,h,s) pci_unmap_single(d,h,s)
-#define dma_map_sg(d,s,n) pci_map_sg(d,s,n)
-#define dma_unmap_sg(d,s,n) pci_unmap_sg(d,s,n)
+#define dma_map_single(d,v,s,dir) pci_map_single(d,v,s,dir)
+#define dma_unmap_single(d,h,s,dir) pci_unmap_single(d,h,s,dir)
+#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir)
+#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir)
+#define scsi_to_fc_dma_dir(dir)	scsi_to_pci_dma_dir(dir)
+#define FC_DMA_BIDIRECTIONAL	PCI_DMA_BIDIRECTIONAL
 #endif							       
 
 #define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp))
@@ -163,7 +167,8 @@
 			fc->state = FC_STATE_FPORT_OK;
 			fcmd = l->fcmds + i;
 			plogi = l->logi + 3 * i;
-			dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi));
+			dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi),
+					  FC_DMA_BIDIRECTIONAL);
 			plogi->code = LS_PLOGI;
 			memcpy (&plogi->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn));
 			memcpy (&plogi->node_wwn, &fc->wwn_node, sizeof(fc_wwn));
@@ -183,7 +188,8 @@
 				printk ("\n");
 			}
 #endif			
-			fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi));
+			fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi),
+						    FC_DMA_BIDIRECTIONAL);
 			fcmd->rsp = fcmd->cmd + 2 * sizeof(logi);
 			if (fc->hw_enque (fc, fcmd))
 				printk ("FC: Cannot enque PLOGI packet on %s\n", fc->name);
@@ -206,7 +212,8 @@
 		switch (status) {
 		case FC_STATUS_OK:
 			plogi = l->logi + 3 * i;
-			dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+			dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
+					  FC_DMA_BIDIRECTIONAL);
 			if (!fc->wwn_dest.lo && !fc->wwn_dest.hi) {
 				memcpy (&fc->wwn_dest, &plogi[1].node_wwn, sizeof(fc_wwn)); 
 				FCD(("Dest WWN %08x%08x\n", *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo))
@@ -224,7 +231,8 @@
 			break;
 		case FC_STATUS_ERR_OFFLINE:
 			fc->state = FC_STATE_OFFLINE;
-			dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+			dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
+					  FC_DMA_BIDIRECTIONAL);
 			printk ("%s: FC is offline\n", fc->name);
 			if (atomic_dec_and_test (&l->todo))
 				up(&l->sem);
@@ -248,7 +256,8 @@
 	FCD(("Report map done %d %d\n", i, status))
 	switch (status) {
 	case FC_STATUS_OK: /* Ok, let's have a fun on a loop */
-		dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+		dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
+				  FC_DMA_BIDIRECTIONAL);
 		p = (fc_al_posmap *)(l->logi + 3 * i);
 #ifdef FCDEBUG
 		{
@@ -297,7 +306,8 @@
 	case FC_STATUS_POINTTOPOINT: /* We're Point-to-Point, no AL... */
 		FCD(("SID %d DID %d\n", fc->sid, fc->did))
 		fcmd = l->fcmds + i;
-		dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi));
+		dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi),
+				 FC_DMA_BIDIRECTIONAL);
 		fch = &fcmd->fch;
 		memset(l->logi + 3 * i, 0, 3 * sizeof(logi));
 		FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT);
@@ -307,7 +317,8 @@
 		FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
 		fch->param = 0;
 		l->logi [3 * i].code = LS_FLOGI;
-		fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi));
+		fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi),
+					    FC_DMA_BIDIRECTIONAL);
 		fcmd->rsp = fcmd->cmd + sizeof(logi);
 		fcmd->cmdlen = sizeof(logi);
 		fcmd->rsplen = sizeof(logi);
@@ -424,9 +435,11 @@
 		
 		if (fcmd->data) {
 			if (SCpnt->use_sg)
-				dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg);
+				dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg,
+					     scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
 			else
-				dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen);
+				dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen,
+						 scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
 		}
 		break;
 	default:
@@ -565,7 +578,8 @@
 		fc->login = fcmd;
 		fc->ls = (void *)l;
 		/* Assumes sizeof(fc_al_posmap) < 3 * sizeof(logi), which is true */
-		fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi));
+		fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi),
+					    FC_DMA_BIDIRECTIONAL);
 		fcmd->proto = PROTO_REPORT_AL_MAP;
 		fcmd->token = i;
 		fcmd->fc = fc;
@@ -584,7 +598,7 @@
 				} else {
 					fc->state = FC_STATE_OFFLINE;
 					enable_irq(fc->irq);
-					dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+					dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
 					if (atomic_dec_and_test (&l->todo))
 						goto all_done;
 				}
@@ -601,7 +615,7 @@
 
 				FCD(("SID %d DID %d\n", fc->sid, fc->did))
 				fcmd = l->fcmds + i;
-				dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi));
+				dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
 				fch = &fcmd->fch;
 				FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT);
 				FILL_FCHDR_SID(fch, 0);
@@ -610,7 +624,7 @@
 				FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
 				fch->param = 0;
 				l->logi [3 * i].code = LS_FLOGI;
-				fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi));
+				fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
 				fcmd->rsp = fcmd->cmd + sizeof(logi);
 				fcmd->cmdlen = sizeof(logi);
 				fcmd->rsplen = sizeof(logi);
@@ -638,7 +652,7 @@
 		switch (fc->state) {
 		case FC_STATE_ONLINE: break;
 		case FC_STATE_OFFLINE: break;
-		default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+		default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
 			break;
 		}
 	}
@@ -801,13 +815,15 @@
 			if (!SCpnt->use_sg) {
 				cmd->fcp_data_len = SCpnt->request_bufflen;
 				fcmd->data = dma_map_single (fc->dev, (char *)SCpnt->request_buffer,
-							     SCpnt->request_bufflen);
+							     SCpnt->request_bufflen,
+							     scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
 			} else {
 				struct scatterlist *sg = (struct scatterlist *)SCpnt->buffer;
 				int nents;
 
 				FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length))
-				nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg);
+				nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg,
+						    scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
 				if (nents > 1) printk ("%s: SG for nents %d (use_sg %d) not handled yet\n", fc->name, nents, SCpnt->use_sg);
 				fcmd->data = sg_dma_address(sg);
 				cmd->fcp_data_len = sg_dma_len(sg);
@@ -1048,7 +1064,7 @@
 	FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
 	FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
 	fch->param = 0;
-	fcmd->cmd = dma_map_single (fc->dev, data, 2 * len);
+	fcmd->cmd = dma_map_single (fc->dev, data, 2 * len, FC_DMA_BIDIRECTIONAL);
 	fcmd->rsp = fcmd->cmd + len;
 	fcmd->cmdlen = len;
 	fcmd->rsplen = len;
@@ -1083,7 +1099,7 @@
 	
 	clear_bit(fcmd->token, fc->scsi_bitmap);
 	fc->scsi_free++;
-	dma_unmap_single (fc->dev, fcmd->cmd, 2 * len);
+	dma_unmap_single (fc->dev, fcmd->cmd, 2 * len, FC_DMA_BIDIRECTIONAL);
 	return l.status;
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c
--- v2.3.46/linux/drivers/ieee1394/hosts.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/hosts.c	Sun Feb 20 20:32:50 2000
@@ -23,31 +23,6 @@
 static struct hpsb_host_template *templates = NULL;
 spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
 
-
-/*
- * The following function is exported for module usage.  It will
- * be called from high-level drivers such as the raw driver.
- */
-int hpsb_get_host_list(struct hpsb_host *list[], int list_size)
-{
-    struct hpsb_host *host, **ptr;
-    struct hpsb_host_template *tmpl;
-    int count=0;
-
-    ptr = list;
-
-    for (tmpl = templates ; tmpl != NULL; tmpl = tmpl->next) {
-        for (host = tmpl->hosts; (host != NULL) && (count < list_size); 
-             host = host->next) {
-            *ptr = host;
-            ptr++;
-            count++;
-        }
-    }
-
-    return count;
-}
-
 /*
  * This function calls the add_host/remove_host hooks for every host currently
  * registered.  Init == TRUE means add_host.
@@ -131,7 +106,7 @@
         h->timeout_tq.data = h;
 
         h->topology_map = h->csr.topology_map + 3;
-        h->speed_map = h->csr.speed_map + 2;
+        h->speed_map = (u8 *)(h->csr.speed_map + 2);
 
         h->template = tmpl;
         if (hd_size) {
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/hosts.h linux/drivers/ieee1394/hosts.h
--- v2.3.46/linux/drivers/ieee1394/hosts.h	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/hosts.h	Sun Feb 20 20:32:50 2000
@@ -27,7 +27,8 @@
         wait_queue_head_t tlabel_wait;
 
         int reset_retries;
-        quadlet_t *topology_map, *speed_map;
+        quadlet_t *topology_map;
+        u8 *speed_map;
         struct csr_control csr;
 
         unsigned char iso_listen_count[64];
@@ -172,14 +173,6 @@
  */
 struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, 
                                 size_t hostdata_size);
-
-/*
- * Write pointers to all available hpsb_hosts into list.
- * Return number of host adapters (i.e. elements in list).
- *
- * DEPRECATED - register with highlevel instead.
- */
-int hpsb_get_host_list(struct hpsb_host *list[], int max_list_size);
 
 /*
  * Increase / decrease host usage counter.  Increase function will return true
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- v2.3.46/linux/drivers/ieee1394/ieee1394_core.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/ieee1394_core.c	Sun Feb 20 20:32:50 2000
@@ -4,7 +4,7 @@
  * Core support: hpsb_packet management, packet handling and forwarding to
  *               csr or lowlevel code
  *
- * Copyright (C) 1999 Andreas E. Bombe
+ * Copyright (C) 1999, 2000 Andreas E. Bombe
  */
 
 #include <linux/kernel.h>
@@ -191,6 +191,74 @@
         return nodeid + 1;
 }
 
+static void build_speed_map(struct hpsb_host *host, int nodecount)
+{
+        char speedcap[nodecount];
+        char cldcnt[nodecount];
+        u8 *map = host->speed_map;
+        quadlet_t *sidp;
+        int i, j, n;
+
+        for (i = 0; i < (nodecount * 64); i += 64) {
+                for (j = 0; j < nodecount; j++) {
+                        map[i+j] = SPEED_400;
+                }
+        }
+
+        for (i = 0; i < nodecount; i++) {
+                cldcnt[i] = 0;
+        }
+
+        /* find direct children count and speed */
+        for (sidp = &host->topology_map[host->selfid_count-1],
+                     n = nodecount - 1;
+             sidp >= host->topology_map; sidp--) {
+                if (*sidp & 0x00800000 /* extended */) {
+                        for (i = 2; i < 18; i += 2) {
+                                if ((*sidp & (0x3 << i)) == (0x3 << i)) {
+                                        cldcnt[n]++;
+                                }
+                        }
+                } else {
+                        for (i = 2; i < 8; i += 2) {
+                                if ((*sidp & (0x3 << i)) == (0x3 << i)) {
+                                        cldcnt[n]++;
+                                }
+                        }
+                        speedcap[n] = (*sidp >> 14) & 0x3;
+                        n--;
+                }
+        }
+
+        /* set self mapping */
+        for (i = nodecount - 1; i; i--) {
+                map[64*i + i] = speedcap[i];
+        }
+
+        /* fix up direct children count to total children count;
+         * also fix up speedcaps for sibling and parent communication */
+        for (i = 1; i < nodecount; i++) {
+                for (j = cldcnt[i], n = i - 1; j > 0; j--) {
+                        cldcnt[i] += cldcnt[n];
+                        speedcap[n] = MIN(speedcap[n], speedcap[i]);
+                        n -= cldcnt[n] + 1;
+                }
+        }
+
+        for (n = 0; n < nodecount; n++) {
+                for (i = n - cldcnt[n]; i <= n; i++) {
+                        for (j = 0; j < (n - cldcnt[n]); j++) {
+                                map[j*64 + i] = map[i*64 + j] =
+                                        MIN(map[i*64 + j], speedcap[n]);
+                        }
+                        for (j = n + 1; j < nodecount; j++) {
+                                map[j*64 + i] = map[i*64 + j] =
+                                        MIN(map[i*64 + j], speedcap[n]);
+                        }
+                }
+        }
+}
+
 void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
 {
         if (host->in_bus_reset) {
@@ -204,8 +272,6 @@
 
 void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
 {
-        
-
         host->node_id = 0xffc0 | phyid;
         host->in_bus_reset = 0;
         host->is_root = isroot;
@@ -219,9 +285,11 @@
                         return;
                 } else {
                         HPSB_NOTICE("stopping out-of-control reset loop");
-                        HPSB_NOTICE("warning - topology map will therefore not "
-                                    "be valid");
+                        HPSB_NOTICE("warning - topology map and speed map will "
+                                    "therefore not be valid");
                 }
+        } else {
+                build_speed_map(host, host->node_count);
         }
 
         /* irm_id is kept up to date by check_selfids() */
@@ -275,8 +343,22 @@
         }
 
         packet->state = queued;
+        packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64
+                                            + (packet->node_id & NODE_MASK)];
 
-        dump_packet("send packet:", packet->header, packet->header_size);
+        switch (packet->speed_code) {
+        case 2:
+                dump_packet("send packet 400:", packet->header,
+                            packet->header_size);
+                break;
+        case 1:
+                dump_packet("send packet 200:", packet->header,
+                            packet->header_size);
+                break;
+        default:
+                dump_packet("send packet 100:", packet->header,
+                            packet->header_size);
+        }
 
         return host->template->transmit_packet(host, packet);
 }
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- v2.3.46/linux/drivers/ieee1394/ieee1394_syms.c	Tue Feb  1 01:35:43 2000
+++ linux/drivers/ieee1394/ieee1394_syms.c	Sun Feb 20 20:32:50 2000
@@ -19,7 +19,6 @@
 EXPORT_SYMBOL(hpsb_register_lowlevel);
 EXPORT_SYMBOL(hpsb_unregister_lowlevel);
 EXPORT_SYMBOL(hpsb_get_host);
-EXPORT_SYMBOL(hpsb_get_host_list);
 EXPORT_SYMBOL(hpsb_inc_host_usage);
 EXPORT_SYMBOL(hpsb_dec_host_usage);
 
@@ -53,8 +52,3 @@
 EXPORT_SYMBOL(highlevel_write);
 EXPORT_SYMBOL(highlevel_lock);
 EXPORT_SYMBOL(highlevel_lock64);
-
-/*
-EXPORT_SYMBOL(hpsb_dispatch_event);
-EXPORT_SYMBOL(hpsb_reg_event_handler);
-*/
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- v2.3.46/linux/drivers/ieee1394/ohci1394.c	Tue Feb  1 01:35:43 2000
+++ linux/drivers/ieee1394/ohci1394.c	Sun Feb 20 20:32:50 2000
@@ -18,6 +18,28 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+/*
+ * Things known to be working:
+ * . Async Request Transmit
+ * . Async Response Receive
+ * . Async Request Receive
+ * . Async Response Transmit
+ * . Iso Receive
+ * 
+ * Things not implemented:
+ * . Iso Transmit
+ * . DMA to user's space in iso receive mode
+ * . DMA error recovery
+ *
+ * Things to be fixed:
+ * . Config ROM
+ *
+ * Known bugs:
+ * . Self-id are not received properly if card 
+ *   is initialized with no other nodes on the
+ *   bus.
+ */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -35,12 +57,31 @@
 #include <linux/proc_fs.h>
 #include <linux/tqueue.h>
 
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "ohci1394.h"
 
+#ifdef DBGMSG
+#undef DBGMSG
+#endif
+
+#if OHCI1394_DEBUG
+#define DBGMSG(card, fmt, args...) \
+printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args)
+#else
+#define DBGMSG(card, fmt, args...)
+#endif
+
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) \
 printk(level "ohci1394: " fmt "\n" , ## args)
@@ -49,11 +90,18 @@
 #define PRINT(level, card, fmt, args...) \
 printk(level "ohci1394_%d: " fmt "\n" , card , ## args)
 
+#define FAIL(fmt, args...) \
+	PRINT_G(KERN_ERR, fmt , ## args); \
+	  num_of_cards--; \
+	    remove_card(ohci); \
+	      return 1;
+
 int supported_chips[][2] = {
-    { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
-    { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
-    { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
-    { -1, -1 }
+	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
+	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
+	{ PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 },
+	{ -1, -1 }
 };
 
 static struct ti_ohci cards[MAX_OHCI1394_CARDS];
@@ -62,6 +110,8 @@
 static int add_card(struct pci_dev *dev);
 static void remove_card(struct ti_ohci *ohci);
 static int init_driver(void);
+static void dma_trm_bh(void *data);
+static void dma_trm_reset(struct dma_trm_ctx *d);
 
 /***********************************
  * IEEE-1394 functionality section *
@@ -87,7 +137,7 @@
 
 	/* wait */
 	while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
-	  timeout--;
+		timeout--;
 
 
 	if (!timeout) {
@@ -120,7 +170,7 @@
 
 	/* wait */
 	while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
-	  timeout--;
+		timeout--;
 
 	spin_unlock(&ohci->phy_reg_lock);
 
@@ -150,31 +200,34 @@
 	if ((self_id_count&0x80000000) || 
 	    ((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) {
 		PRINT(KERN_ERR, ohci->id, 
-		      "Error in reception of self-id packets");
+		      "Error in reception of self-id packets"
+		      "Self-id count: %08x q[0]: %08x",
+		      self_id_count, q[0]);
 		return -1;
-	}    
-
+	}
+	
 	size = ((self_id_count&0x0000EFFC)>>2) - 1;
 	q++;
 
 	while (size > 0) {
 		if (q[0] == ~q[1]) {
-			printk("-%d- selfid packet 0x%x rcvd\n", 
-			       ohci->id, q[0]);
+			PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd", 
+			      q[0]);
 			hpsb_selfid_received(host, q[0]);
 			if (((q[0]&0x3f000000)>>24)==phyid) {
 				lsid=q[0];
-				printk("This node self-id is 0x%08x\n",lsid);
+				PRINT(KERN_INFO, ohci->id, 
+				      "This node self-id is 0x%08x", lsid);
 			}
 		} else {
-			printk("-%d- inconsistent selfid 0x%x/0x%x\n", ohci->id,
-			       q[0], q[1]);
+			PRINT(KERN_ERR, ohci->id,
+			      "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
 		}
 		q += 2;
 		size -= 2;
 	}
 
-	printk(" calling self-id complete\n");
+	PRINT(KERN_INFO, ohci->id, "calling self-id complete");
 
 	hpsb_selfid_complete(host, phyid, isroot);
 	return 0;
@@ -206,7 +259,7 @@
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
   
 	while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout) 
-	  timeout--;
+		timeout--;
 	if (!timeout) {
 		PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!");
 		return -EFAULT;
@@ -215,6 +268,108 @@
 	return 0;
 }
 
+static int run_context(struct ti_ohci *ohci, int reg, char *msg)
+{
+	u32 nodeId;
+
+	/* check that the node id is valid */
+	nodeId = reg_read(ohci, OHCI1394_NodeID);
+	if (!(nodeId&0x80000000)) {
+		PRINT(KERN_ERR, ohci->id, 
+		      "Running dma failed because Node ID not valid");
+		return -1;
+	}
+
+	/* check that the node number != 63 */
+	if ((nodeId&0x3f)==63) {
+		PRINT(KERN_ERR, ohci->id, 
+		      "Running dma failed because Node ID == 63");
+		return -1;
+	}
+	
+	/* Run the dma context */
+	reg_write(ohci, reg, 0x8000);
+	
+	if (msg) PRINT(KERN_INFO, ohci->id, "%s", msg);
+	
+	return 0;
+}
+
+static void stop_context(struct ti_ohci *ohci, int reg, char *msg)
+{
+	int i=0;
+
+	/* stop the channel program if it's still running */
+	reg_write(ohci, reg, 0x8000);
+   
+	/* Wait until it effectively stops */
+	while (reg_read(ohci, reg) & 0x400) {
+		i++;
+		if (i>5000) {
+			PRINT(KERN_ERR, ohci->id, 
+			      "runaway loop while stopping context...");
+			break;
+		}
+	}
+	if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg);
+}
+
+/* Generate the dma receive prgs and start the context */
+static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d)
+{
+	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+	int i;
+
+	stop_context(ohci, d->ctrlClear, NULL);
+
+	for (i=0; i<d->num_desc; i++) {
+		
+		/* end of descriptor list? */
+		if ((i+1) < d->num_desc) {
+			d->prg[i]->control = (0x283C << 16) | d->buf_size;
+			d->prg[i]->branchAddress =
+				(virt_to_bus(d->prg[i+1]) & 0xfffffff0) | 0x1;
+		} else {
+			d->prg[i]->control = (0x283C << 16) | d->buf_size;
+			d->prg[i]->branchAddress =
+				(virt_to_bus(d->prg[0]) & 0xfffffff0);
+		}
+
+		d->prg[i]->address = virt_to_bus(d->buf[i]);
+		d->prg[i]->status = d->buf_size;
+	}
+
+        d->buf_ind = 0;
+        d->buf_offset = 0;
+
+	/* Tell the controller where the first AR program is */
+	reg_write(ohci, d->cmdPtr, virt_to_bus(d->prg[0]) | 0x1);
+
+	/* Run AR context */
+	reg_write(ohci, d->ctrlSet, 0x00008000);
+
+	PRINT(KERN_INFO, ohci->id, "Receive DMA ctx=%d initialized", d->ctx);
+}
+
+/* Initialize the dma transmit context */
+static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
+{
+	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+
+	/* Stop the context */
+	stop_context(ohci, d->ctrlClear, NULL);
+
+        d->prg_ind = 0;
+	d->sent_ind = 0;
+	d->free_prgs = d->num_desc;
+        d->branchAddrPtr = NULL;
+	d->first = NULL;
+	d->last = NULL;
+
+	PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
+}
+
+/* Global initialization */
 static int ohci_initialize(struct hpsb_host *host)
 {
 	struct ti_ohci *ohci=host->hostdata;
@@ -255,109 +410,64 @@
 	reg_write(ohci, OHCI1394_ConfigROMmap, 
 		  virt_to_bus(ohci->csr_config_rom));
 
-#if 1				/* Why is this step necessary ? */
 	/* Write the config ROM header */
-	reg_write(ohci, OHCI1394_ConfigROMhdr,0x04040000);
+	reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->csr_config_rom[0]);
 
 	/* Set bus options */
-	reg_write(ohci, OHCI1394_BusOptions, 0xf064A002);
-#endif
+	reg_write(ohci, OHCI1394_BusOptions, ohci->csr_config_rom[2]);
 
-#if 1
-	/* Accept phy packets into AR request context */ 
-	reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
-#endif
+	/* Write the GUID into the csr config rom */
+	ohci->csr_config_rom[3] = reg_read(ohci, OHCI1394_GUIDHi);
+	ohci->csr_config_rom[4] = reg_read(ohci, OHCI1394_GUIDLo);
+	
+	/* Don't accept phy packets into AR request context */ 
+	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
 
 	/* Enable link */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
 
 	/* Initialize IR dma */
+	for (i=0;i<4;i++) { /* FIXME : how many contexts are available ? */
+		reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i,
+			  0xffffffff);
+		reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0);
+		reg_write(ohci, OHCI1394_IrRcvCommandPtr+32*i, 0);
+	}
+
+	/* Set bufferFill, isochHeader, multichannel for IR context */
+	reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000);
+			
+	/* Set the context match register to match on all tags */
+	reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000);
+
+	/* Clear the multi channel mask high and low registers */
+	reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
+
+	/* Clear the interrupt mask */
+	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+
+	/* Set up isoRecvIntMask to generate interrupts for context 0
+	   (thanks to Michael Greger for seeing that I forgot this) */
+	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);
 
-	/* make sure the context isn't running, dead, or active */
-	if (!(reg_read(ohci, OHCI1394_IrRcvContextControlSet) & 0x00008F00)) {
-
-                /* initialize IR program */
-                for (i= 0; i < IR_NUM_DESC; i++) {
-
-			/* end of descriptor list? */
-                        if ((i + 1) < IR_NUM_DESC) {
-                                ohci->IR_recv_prg[i]->control=
-                                        (0x283C << 16) | IR_RECV_BUF_SIZE;
-                                ohci->IR_recv_prg[i]->branchAddress=
-                                        (virt_to_bus(ohci->IR_recv_prg[i + 1])
-                                         & 0xfffffff0) | 0x1;
-                        } else {
-                                ohci->IR_recv_prg[i]->control=
-                                        (0x283C << 16) | IR_RECV_BUF_SIZE;
-                                ohci->IR_recv_prg[i]->branchAddress=
-                                        (virt_to_bus(ohci->IR_recv_prg[0])
-                                         & 0xfffffff0) | 0x1;
-                        }
-
-                        ohci->IR_recv_prg[i]->address=
-                                virt_to_bus(ohci->IR_recv_buf[i]);
-                        ohci->IR_recv_prg[i]->status= IR_RECV_BUF_SIZE;
-		}
-
-		/* Tell the controller where the first IR program is */
-		reg_write(ohci, OHCI1394_IrRcvCommandPtr,
-			  virt_to_bus(ohci->IR_recv_prg[0]) | 0x1 );
-
-		/* Set bufferFill, isochHeader, multichannel for IR context */
-		reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000);
-
-		/* Set the context match register to match on all tags */
-		reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000);
-
-		/* Clear the multi channel mask high and low registers */
-		reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
-		reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
-
-                /* Set up isoRecvIntMask to generate interrupts for context 0
-                   (thanks to Michael Greger for seeing that I forgot this) */
-                reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);
-
-		/* Run IR context */
-		reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0x00008000);
-	}
+	initialize_dma_rcv_ctx(ohci->ir_context);
 
 	/* Initialize AR dma */
-	/* make sure the context isn't running, dead, or active */
-	if (!(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x00008F00)) {
-
-                /* initialize AR program */
-                for (i= 0; i < AR_RESP_NUM_DESC; i++) {
-
-			/* end of descriptor list? */
-                        if ((i + 1) < AR_RESP_NUM_DESC) {
-                                ohci->AR_resp_prg[i]->control=
-				  (0x283C << 16) | AR_RESP_BUF_SIZE;
-                                ohci->AR_resp_prg[i]->branchAddress=
-				  (virt_to_bus(ohci->AR_resp_prg[i + 1])
-                                         & 0xfffffff0) | 0x1;
-                        } else {
-                                ohci->AR_resp_prg[i]->control=
-                                        (0x283C << 16) | AR_RESP_BUF_SIZE;
-                                ohci->AR_resp_prg[i]->branchAddress=
-                                        (virt_to_bus(ohci->AR_resp_prg[0])
-                                         & 0xfffffff0) | 0x1;
-                        }
+	initialize_dma_rcv_ctx(ohci->ar_req_context);
+	initialize_dma_rcv_ctx(ohci->ar_resp_context);
 
-                        ohci->AR_resp_prg[i]->address=
-                                virt_to_bus(ohci->AR_resp_buf[i]);
-                        ohci->AR_resp_prg[i]->status= AR_RESP_BUF_SIZE;
-		}
-
-		/* Tell the controller where the first AR program is */
-		reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
-			  virt_to_bus(ohci->AR_resp_prg[0]) | 0x1 );
-
-		/* Accept phy packets into AR request context */
-		reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
-
-		/* Run AR context */
-		reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
-	}
+	/* Initialize AT dma */
+	initialize_dma_trm_ctx(ohci->at_req_context);
+	initialize_dma_trm_ctx(ohci->at_resp_context);
+
+	/* 
+	 * Accept AT requests from all nodes. This probably 
+	 * will have to be controlled from the subsystem
+	 * on a per node basis.
+	 * (Tip by Emilie Chung <emilie.chung@axis.com>)
+	 */
+	reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
 
 	/* Specify AT retries */
 	reg_write(ohci, OHCI1394_ATRetries, 
@@ -384,7 +494,7 @@
 		  OHCI1394_respTxComplete |
 		  OHCI1394_reqTxComplete |
 		  OHCI1394_isochRx
-		  );
+		);
 
 	return 1;
 }
@@ -399,126 +509,144 @@
 	}
 }
 
-
-/* This must be called with the async_queue_lock held. */
-static void send_next_async(struct ti_ohci *ohci)
+/* Insert a packet in the AT DMA fifo and generate the DMA prg */
+static void insert_packet(struct ti_ohci *ohci,
+			  struct dma_trm_ctx *d, struct hpsb_packet *packet)
 {
-	int i=0;
-	struct hpsb_packet *packet = ohci->async_queue;
-	struct dma_cmd prg;
-#if 0
-	quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg;
-#endif
-	//HPSB_TRACE();
-
-        /* stop the channel program if it's still running */
-        reg_write(ohci, OHCI1394_AsReqTrContextControlClear, 0x8000);
-   
-        /* Wait until it effectively stops */
-        while (reg_read(ohci, OHCI1394_AsReqTrContextControlSet)
-               & 0x400) {
-                i++;
-                if (i>5000) {
-                        PRINT(KERN_ERR, ohci->id, 
-                              "runaway loop in DmaAT. bailing out...");
-                        break;
-                }
-        };
+	u32 cycleTimer;
+	int idx = d->prg_ind;
 
-        if (packet->type == async)
-        {
-
-                /* re-format packet header according to ohci specification */
-                packet->header[1] = (packet->header[1] & 0xFFFF) | 
-                        (packet->header[0] & 0xFFFF0000);
-                packet->header[0] = DMA_SPEED_200 |
-                        (packet->header[0] & 0xFFFF);
-
-                if (packet->data_size) { /* block transmit */
-                        prg.control = OUTPUT_MORE_IMMEDIATE | 0x10;
-                        prg.address = 0;
-                        prg.branchAddress = 0;
-                        prg.status = 0;
-                        memcpy(ohci->AT_req_prg, &prg, 16);
-                        memcpy(ohci->AT_req_prg + 1, packet->header, 16);
-                        prg.control = OUTPUT_LAST | packet->data_size;
-                        prg.address = virt_to_bus(packet->data);
-                        memcpy(ohci->AT_req_prg + 2, &prg, 16);
-
-                        reg_write(ohci, OHCI1394_AsReqTrCommandPtr, 
-                                  virt_to_bus(ohci->AT_req_prg)|0x3);
-                }
-                else { /* quadlet transmit */
-                        prg.control = OUTPUT_LAST_IMMEDIATE |
-                                packet->header_size;
-                        prg.address = 0;
-                        prg.branchAddress = 0;
-                        prg.status = 0;
-                        memcpy(ohci->AT_req_prg, &prg, 16);
-                        memcpy(ohci->AT_req_prg + 1, packet->header, 16);
-#if 0
-                        PRINT(KERN_INFO, ohci->id,
-                              "dma_cmd: %08x %08x %08x %08x",
-                              *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
-                        PRINT(KERN_INFO, ohci->id,
-                              "header: %08x %08x %08x %08x",
-                              *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7));
-#endif
-                        reg_write(ohci, OHCI1394_AsReqTrCommandPtr, 
-                                  virt_to_bus(ohci->AT_req_prg)|0x2);
-                }
-
-        }
-        else if (packet->type == raw)
-        {
-                prg.control = OUTPUT_LAST | packet->data_size;
-                prg.address = virt_to_bus(packet->data);
-                prg.branchAddress = 0;
-                prg.status = 0;
-                memcpy(ohci->AT_req_prg, &prg, 16);
-#if 0
-                PRINT(KERN_INFO, ohci->id,
-                      "dma_cmd: %08x %08x %08x %08x",
-                      *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
-#endif
-                reg_write(ohci, OHCI1394_AsReqTrCommandPtr, 
-                          virt_to_bus(ohci->AT_req_prg)|0x2);
-        }
-
-	/* run program */
-	reg_write(ohci, OHCI1394_AsReqTrContextControlSet, 0x00008000);
+	d->prg[idx].begin.address = 0;
+	d->prg[idx].begin.branchAddress = 0;
+	if (d->ctx==1) {
+		/* 
+		 * For response packets, we need to put a timeout value in
+		 * the 16 lower bits of the status... let's try 1 sec timeout 
+		 */ 
+		cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+		d->prg[idx].begin.status = 
+			(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | 
+			((cycleTimer&0x01fff000)>>12);
+
+		DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x",
+		       cycleTimer, d->prg[idx].begin.status);
+	}
+	else 
+		d->prg[idx].begin.status = 0;
+
+	d->prg[idx].data[0] = packet->speed_code<<16 |
+		(packet->header[0] & 0xFFFF);
+	d->prg[idx].data[1] = (packet->header[1] & 0xFFFF) | 
+		(packet->header[0] & 0xFFFF0000);
+	d->prg[idx].data[2] = packet->header[2];
+	d->prg[idx].data[3] = packet->header[3];
+
+	if (packet->data_size) { /* block transmit */
+		d->prg[idx].begin.control = OUTPUT_MORE_IMMEDIATE | 0x10;
+		d->prg[idx].end.control = OUTPUT_LAST | packet->data_size;
+		d->prg[idx].end.address = virt_to_bus(packet->data);
+		d->prg[idx].end.branchAddress = 0;
+		d->prg[idx].end.status = 0x4000;
+		if (d->branchAddrPtr) 
+			*(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x3;
+		d->branchAddrPtr = &(d->prg[idx].end.branchAddress);
+	}
+	else { /* quadlet transmit */
+		d->prg[idx].begin.control = 
+			OUTPUT_LAST_IMMEDIATE | packet->header_size;
+		if (d->branchAddrPtr) 
+			*(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x2;
+		d->branchAddrPtr = &(d->prg[idx].begin.branchAddress);
+	}
+	d->free_prgs--;
+
+	/* queue the packet in the appropriate context queue */
+	if (d->last) {
+		d->last->xnext = packet;
+		d->last = packet;
+	}
+	else {
+		d->first = packet;
+		d->last = packet;
+	}
 }
 
 static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
 {
 	struct ti_ohci *ohci = host->hostdata;
-	struct hpsb_packet *p;
-	unsigned long flags;
+	struct dma_trm_ctx *d;
+	unsigned char tcode;
+	int i=50;
 
 	if (packet->data_size >= 4096) {
 		PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)",
 		      packet->data_size);
 		return 0;
 	}
-
-	//HPSB_TRACE();
 	packet->xnext = NULL;
-    
-	spin_lock_irqsave(&ohci->async_queue_lock, flags);
 
-	if (ohci->async_queue == NULL) {
-		ohci->async_queue = packet;
-		send_next_async(ohci);
-	} else {
-		p = ohci->async_queue;
-		while (p->xnext != NULL) {
-			p = p->xnext;
+	/* Decide wether we have a request or a response packet */
+	tcode = (packet->header[0]>>4)&0xf;
+	if ((tcode==TCODE_READQ)||
+	    (tcode==TCODE_WRITEQ)||
+	    (tcode==TCODE_READB)||
+	    (tcode==TCODE_WRITEB)||
+	    (tcode==TCODE_LOCK_REQUEST))
+		d = ohci->at_req_context;
+
+	else if ((tcode==TCODE_WRITE_RESPONSE)||
+		 (tcode==TCODE_READQ_RESPONSE)||
+		 (tcode==TCODE_READB_RESPONSE)||
+		 (tcode==TCODE_LOCK_RESPONSE)) 
+		d = ohci->at_resp_context;
+
+	else {
+		PRINT(KERN_ERR, ohci->id, 
+		      "Unexpected packet tcode=%d in AT DMA", tcode);
+		return 0;
+	}
+
+	spin_lock(&d->lock);
+
+	if (d->free_prgs<1) {
+		PRINT(KERN_INFO, ohci->id, 
+		      "AT DMA ctx=%d Running out of prgs... waiting",d->ctx);
+	}
+	while (d->free_prgs<1) {
+		spin_unlock(&d->lock);
+		schedule();
+		if (i-- <0) {
+			stop_context(ohci, d->ctrlClear, 
+				     "AT DMA runaway loop... bailing out");
+			return 0;
 		}
-		
-		p->xnext = packet;
+		spin_lock(&d->lock);
+	}
+
+	insert_packet(ohci, d, packet);
+
+	/* Is the context running ? (should be unless it is 
+	   the first packet to be sent in this context) */
+	if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
+		DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx);
+		if (packet->data_size) 
+			reg_write(ohci, d->cmdPtr, 
+				  virt_to_bus(&(d->prg[d->prg_ind])) | 0x3);
+		else 
+			reg_write(ohci, d->cmdPtr, 
+				  virt_to_bus(&(d->prg[d->prg_ind])) | 0x2);
+
+		run_context(ohci, d->ctrlSet, NULL);
+	}
+	else {
+		DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx);
+		/* wake up the dma context if necessary */
+		if (!(reg_read(ohci, d->ctrlSet) & 0x400))
+			reg_write(ohci, d->ctrlSet, 0x1000);
 	}
-    
-	spin_unlock_irqrestore(&ohci->async_queue_lock, flags);
+
+	d->prg_ind = (d->prg_ind+1)%d->num_desc;
+	spin_unlock(&d->lock);
 
 	return 1;
 }
@@ -528,31 +656,29 @@
 	struct ti_ohci *ohci = host->hostdata;
 	int retval = 0;
 	unsigned long flags;
-        struct hpsb_packet *packet, *lastpacket;
-	u32 r;
 
 	switch (cmd) {
-	      case RESET_BUS:
+	case RESET_BUS:
 		PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
 		      (host->attempt_root ? " and attempting to become root"
 		       : ""));
-		r = (host->attempt_root) ? 0x000041ff : 0x0000417f;
-		reg_write(ohci, OHCI1394_PhyControl, r);
+		reg_write(ohci, OHCI1394_PhyControl, 
+			  (host->attempt_root) ? 0x000041ff : 0x0000417f);
 		break;
 
-	      case GET_CYCLE_COUNTER:
+	case GET_CYCLE_COUNTER:
 		retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 		break;
 	
-	      case SET_CYCLE_COUNTER:
+	case SET_CYCLE_COUNTER:
 		reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
 		break;
 	
-	      case SET_BUS_ID:
+	case SET_BUS_ID:
 		PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err");
 		break;
 
-	      case ACT_CYCLE_MASTER:
+	case ACT_CYCLE_MASTER:
 #if 0
 		if (arg) {
 			/* enable cycleTimer, cycleMaster, cycleSource */
@@ -564,23 +690,13 @@
 #endif
 		break;
 
-	      case CANCEL_REQUESTS:
-		spin_lock_irqsave(&ohci->async_queue_lock, flags);
-		/* stop any chip activity */
-		reg_write(ohci, OHCI1394_HCControlClear, 0x00020000);
-                packet = ohci->async_queue;
-		ohci->async_queue = NULL;                
-		spin_unlock_irqrestore(&ohci->async_queue_lock, flags);
-
-                while (packet != NULL) {
-                        lastpacket = packet;
-                        packet = packet->xnext;
-                        hpsb_packet_sent(host, lastpacket, ACKX_ABORTED);
-                }
-
+	case CANCEL_REQUESTS:
+		DBGMSG(ohci->id, "Cancel request received");
+		dma_trm_reset(ohci->at_req_context);
+		dma_trm_reset(ohci->at_resp_context);
 		break;
 
-              case MODIFY_USAGE:
+	case MODIFY_USAGE:
                 if (arg) {
                         MOD_INC_USE_COUNT;
                 } else {
@@ -588,7 +704,7 @@
                 }
                 break;
 
-              case ISO_LISTEN_CHANNEL:
+	case ISO_LISTEN_CHANNEL:
 
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
@@ -614,7 +730,7 @@
                 spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
                 break;
 
-              case ISO_UNLISTEN_CHANNEL:
+	case ISO_UNLISTEN_CHANNEL:
 
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
@@ -642,7 +758,7 @@
                 spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
                 break;
 
-	      default:
+	default:
 		PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet\n",
 			cmd);
 		break;
@@ -659,160 +775,118 @@
  * Global stuff (interrupt handler, init/shutdown code) *
  ********************************************************/
 
-static void stop_ar_resp_context(struct ti_ohci *ohci, char *msg)
+static void dma_trm_reset(struct dma_trm_ctx *d)
 {
-	int i=0;
+	struct ti_ohci *ohci;
 
-	/* stop the channel program if it's still running */
-	reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
-   
-	/* Wait until it effectively stops */
-	while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) 
-	       & 0x400) {
-		i++;
-		if (i>5000) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "runaway loop in Dma Ar Resp. bailing out...");
-			break;
-		}
-	}
-	PRINT(KERN_ERR, ohci->id, "%s\n async response receive dma stopped\n", msg);
+	if (d==NULL) {
+		PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg");
+		return;
+	}
+	ohci = (struct ti_ohci *)(d->ohci);
+	stop_context(ohci, d->ctrlClear, NULL);
+
+	spin_lock(&d->lock);
+
+	/* is there still any packet pending ? */
+	while(d->first) {
+		PRINT(KERN_INFO, ohci->id, 
+		      "AT dma reset ctx=%d, aborting transmission", 
+		      d->ctx);
+		hpsb_packet_sent(ohci->host, d->first, ACKX_ABORTED);
+		d->first = d->first->xnext;
+	}
+	d->first = d->last = NULL;
+	d->branchAddrPtr=NULL;
+	d->sent_ind = d->prg_ind;
+	d->free_prgs = d->num_desc;
+	spin_unlock(&d->lock);
 }
 
 static void ohci_irq_handler(int irq, void *dev_id,
                              struct pt_regs *regs_are_unused)
 {
-	//int i;
-	static quadlet_t event,node_id;
+	quadlet_t event,node_id;
 	struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
 	struct hpsb_host *host = ohci->host;
 	int phyid = -1, isroot = 0;
 
 	event=reg_read(ohci, OHCI1394_IntEventSet);
 
-	/* Clear the interrupt register */
-	reg_write(ohci, OHCI1394_IntEventClear, event);
-
-	/* PRINT(KERN_INFO, ohci->id, "int event %08X mask %08X",
-	   event,reg_read(ohci, OHCI1394_IntMaskSet)); */
-
 	if (event & OHCI1394_busReset) {
-#if 0
-		PRINT(KERN_INFO, ohci->id, "bus reset interrupt");
-#endif
 		if (!host->in_bus_reset) {
-			hpsb_bus_reset(host);
+			PRINT(KERN_INFO, ohci->id, "Bus reset");
+
+			/* Wait for the AT fifo to be flushed */
+			dma_trm_reset(ohci->at_req_context);
+			dma_trm_reset(ohci->at_resp_context);
+
+			/* Subsystem call */
+			hpsb_bus_reset(ohci->host);
+
+			ohci->NumBusResets++;
 		}
-		ohci->NumBusResets++;
 	}
-	if (event & OHCI1394_RQPkt) {
-		PRINT(KERN_INFO, ohci->id, "RQPkt int received");
+	/*
+	 * Problem: How can I ensure that the AT bottom half will be
+	 * executed before the AR bottom half (both events may have
+	 * occured within a single irq event)
+	 * Quick hack: just launch it within the IRQ handler
+	 */
+	if (event & OHCI1394_reqTxComplete) { 
+		struct dma_trm_ctx *d = ohci->at_req_context;
+		DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X",
+		       reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			stop_context(ohci, d->ctrlClear, "reqTxComplete");
+		else
+			dma_trm_bh((void *)d);
+	}
+	if (event & OHCI1394_respTxComplete) { 
+		struct dma_trm_ctx *d = ohci->at_resp_context;
+		DBGMSG(ohci->id, "Got respTxComplete interrupt status=0x%08X",
+		       reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			stop_context(ohci, d->ctrlClear, "respTxComplete");
+		else
+			dma_trm_bh((void *)d);
 	}
 	if (event & OHCI1394_RQPkt) {
-		PRINT(KERN_INFO, ohci->id, "ControlContext: %08X",
-		      reg_read(ohci, OHCI1394_AsReqRcvContextControlSet));
+		struct dma_rcv_ctx *d = ohci->ar_req_context;
+		DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",
+		       reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			stop_context(ohci, d->ctrlClear, "RQPkt");
+		else {
+			queue_task(&d->task, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+		}
 	}
 	if (event & OHCI1394_RSPkt) {
-		unsigned int idx,offset,rescount;
-
-                spin_lock(&ohci->AR_resp_lock);
-
-		idx = ohci->AR_resp_buf_th_ind;
-		offset = ohci->AR_resp_buf_th_offset;
-
-		rescount = ohci->AR_resp_prg[idx]->status&0xffff;
-		ohci->AR_resp_bytes_left +=  AR_RESP_BUF_SIZE - rescount - offset;
-		offset = AR_RESP_BUF_SIZE - rescount;
-
-		if (!rescount) { /* We cross a buffer boundary */
-			idx = (idx+1) % AR_RESP_NUM_DESC;
-
-#if 0 
-			/* This bit of code does not work */
-			/* Let's see how many bytes were written in the async response 
-			   receive buf since last interrupt. This is done by finding 
-			   the next active context (See OHCI Spec p91) */
-			while (ohci->AR_resp_bytes_left <= AR_RESP_TOTAL_BUF_SIZE) {
-				if (ohci->AR_resp_prg[idx]->status&0x04000000) break;
-				idx = (idx+1) % AR_RESP_NUM_DESC;
-				PRINT(KERN_INFO,ohci->id,"crossing more than one buffer boundary !!!");
-				ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE;
-			}
-#endif 
-			/* ASSUMPTION: only one buffer boundary is crossed */
-			rescount = ohci->AR_resp_prg[idx]->status&0xffff;
-			offset = AR_RESP_BUF_SIZE - rescount;
-			ohci->AR_resp_bytes_left += offset;
-		}
-		if (offset==AR_RESP_BUF_SIZE) {
-			offset=0;
-			idx = (idx+1) % AR_RESP_NUM_DESC;
-		}
-		ohci->AR_resp_buf_th_ind = idx;
-		ohci->AR_resp_buf_th_offset = offset;
-
-                /* is buffer processing too slow? (all buffers used) */
-		if (ohci->AR_resp_bytes_left > AR_RESP_TOTAL_BUF_SIZE) {
-			stop_ar_resp_context(ohci,"async response receive processing too slow");
-                        spin_unlock(&ohci->AR_resp_lock);
-			return;
+		struct dma_rcv_ctx *d = ohci->ar_resp_context;
+		DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",
+		       reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			stop_context(ohci, d->ctrlClear, "RSPkt");
+		else {
+			queue_task(&d->task, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
 		}
-                spin_unlock(&ohci->AR_resp_lock);
-
-		/* queue bottom half in immediate queue */
-		queue_task(&ohci->AR_resp_pdl_task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
 	}
 	if (event & OHCI1394_isochRx) {
 		quadlet_t isoRecvIntEvent;
-
-		/* ASSUMPTION: We assume there is only one context for now. */
-
-                spin_lock(&ohci->IR_recv_lock);
-
-                /* Clear the isoRecvIntEvent register (very important!) */
-                isoRecvIntEvent= reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
+		struct dma_rcv_ctx *d = ohci->ir_context;
+                isoRecvIntEvent = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
 		reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
 			  isoRecvIntEvent);
-
-                ohci->IR_buf_used++;
-                ohci->IR_buf_next_ind=
-                        (ohci->IR_buf_next_ind + 1) % IR_NUM_DESC;
-
-                /* is buffer processing too slow? (all buffers used) */
-		if (ohci->IR_buf_next_ind == ohci->IR_buf_last_ind) {
-                        int i= 0;
-
-                        /* stop the context */
-			reg_write(ohci,
-				  OHCI1394_IrRcvContextControlClear, 0x8000);
-
-			while (reg_read(ohci, OHCI1394_IrRcvContextControlSet) 
-			       & 0x400) {
-				i++;
-
-				if (i>5000) {
-					PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out...");
-					break;
-				}
-
-			}
-
-                        spin_unlock(&ohci->IR_recv_lock);
-			PRINT(KERN_ERR, ohci->id,
-                              "iso receive processing too slow... stopped");
-			return;
+		DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X",
+		       reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			stop_context(ohci, d->ctrlClear, "isochRx");
+		else {
+			queue_task(&d->task, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
 		}
-
-                /* reset status field of next descriptor */
-                ohci->IR_recv_prg[ohci->IR_buf_next_ind]->status=
-                        IR_RECV_BUF_SIZE;
-
-                spin_unlock(&ohci->IR_recv_lock);
-
-		/* queue bottom half in immediate queue */
-		queue_task(&ohci->IR_pdl_task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
 	}
 	if (event & OHCI1394_selfIDComplete) {
 		if (host->in_bus_reset) {
@@ -828,9 +902,13 @@
 				handle_selfid(ohci, host, phyid, isroot);
 			}
 			else 
-			  PRINT(KERN_ERR, ohci->id, 
-				"SelfID process finished but NodeID"
-				" not valid: %08X",node_id);
+				PRINT(KERN_ERR, ohci->id, 
+				      "SelfID process finished but NodeID"
+				      " not valid: %08X",node_id);
+
+			/* Accept Physical requests from all nodes. */
+			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff);
+			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff);
 		} 
 		else PRINT(KERN_INFO, ohci->id, 
 			   "phy reg received without reset\n");
@@ -840,316 +918,424 @@
 		if (host->in_bus_reset) {
 			PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", 
 			      reg_read(ohci, OHCI1394_PhyControl));
-		} else printk("-%d- phy reg received without reset\n",
-			      ohci->id);
+		} else 
+			PRINT(KERN_ERR, ohci->id, 
+			      "phy reg received without reset");
 #endif
 	}
-	if (event & OHCI1394_reqTxComplete) { 
-		/* async packet sent - transmitter ready */
-		u32 ack;
-		struct hpsb_packet *packet;
-
-		if (ohci->async_queue) {
-
-			spin_lock(&ohci->async_queue_lock);
-	    
-			ack=reg_read(ohci, OHCI1394_AsReqTrContextControlSet) 
-			  & 0xF;
-
-			packet = ohci->async_queue;
-			ohci->async_queue = packet->xnext;
-	    
-			if (ohci->async_queue != NULL) {
-				send_next_async(ohci);
-			}
-			spin_unlock(&ohci->async_queue_lock);
-#if 0
-			PRINT(KERN_INFO,ohci->id,
-			      "packet sent with ack code %d",ack);
-#endif
-			hpsb_packet_sent(host, packet, ack);	    
-		} else 
-		  PRINT(KERN_INFO,ohci->id,
-			"packet sent without async_queue (self-id?)");
 
-		ohci->TxRdy++;
+	/* clear the interrupt event register */
+	reg_write(ohci, OHCI1394_IntEventClear, event);
+}
+
+/* Put the buffer back into the dma context */
+static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
+{
+	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+	DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
+
+	d->prg[idx]->status = d->buf_size;
+	d->prg[idx]->branchAddress &= 0xfffffff0;
+	idx = (idx + d->num_desc - 1 ) % d->num_desc;
+	d->prg[idx]->branchAddress |= 0x1;
+
+	/* wake up the dma context if necessary */
+	if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
+		PRINT(KERN_INFO, ohci->id, 
+		      "Waking dma cxt=%d ... processing is probably too slow",
+		      d->ctx);
+		reg_write(ohci, d->ctrlSet, 0x1000);
 	}
+}	
 
-	ohci->NumInterrupts++;
+static int block_length(struct dma_rcv_ctx *d, int idx, 
+			 quadlet_t *buf_ptr, int offset)
+{
+	int length=0;
+
+	/* Where is the data length ? */
+	if (offset+12>=d->buf_size) 
+		length = (d->buf[(idx+1)%d->num_desc]
+			  [3-(d->buf_size-offset)/4]>>16);
+	else 
+		length = (buf_ptr[3]>>16);
+	if (length % 4) length += 4 - (length % 4);
+	return length;
 }
 
+static int packet_length(struct dma_rcv_ctx *d, int idx, 
+			 quadlet_t *buf_ptr, int offset)
+{
+	unsigned char tcode;
+	int length;
+
+	/* Let's see what kind of packet is in there */
+	tcode = (buf_ptr[0]>>4)&0xf;
 
-/* This is the bottom half that processes async response receive descriptor buffers. */
-static void ohci_ar_resp_proc_desc(void *data)
+	if (d->ctx==0) { /* Async Receive Request */
+		if (tcode==TCODE_READQ) return 16;
+		else if (tcode==TCODE_WRITEQ ||
+			 tcode==TCODE_READB) return 20;
+		else if (tcode==TCODE_WRITEB ||
+			 tcode==TCODE_LOCK_REQUEST) {
+			return block_length(d, idx, buf_ptr, offset) + 20;
+		}
+		else if (tcode==0xE) { /* Phy packet */
+			return 16;
+		}
+		else return -1;
+	}
+	else if (d->ctx==1) { /* Async Receive Response */
+		if (tcode==TCODE_WRITE_RESPONSE) return 16;
+		else if (tcode==TCODE_READQ_RESPONSE) return 20;
+		else if (tcode==TCODE_READB_RESPONSE ||
+			 tcode==TCODE_LOCK_RESPONSE) {
+			return block_length(d, idx, buf_ptr, offset) + 20;
+		}
+		else return -1;
+	}
+	else if (d->ctx==2) { /* Iso receive */
+		/* Assumption: buffer fill mode with header/trailer */
+		length = (buf_ptr[0]>>16);
+		if (length % 4) length += 4 - (length % 4);
+		return length+8;
+	}
+	return -1;
+}
+
+/* Bottom half that processes dma receive buffers */
+static void dma_rcv_bh(void *data)
 {
+	struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
+	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+	unsigned int split_left, idx, offset, rescount;
+	unsigned char tcode;
+	int length, bytes_left;
 	quadlet_t *buf_ptr;
 	char *split_ptr;
-	unsigned int split_left;
-	struct ti_ohci *ohci= (struct ti_ohci*)data;
-        unsigned int packet_length;
-        unsigned int idx,offset,tcode;
-        unsigned long flags;
 	char msg[256];
 
-        spin_lock_irqsave(&ohci->AR_resp_lock, flags);
+	spin_lock(&d->lock);
 
-	idx = ohci->AR_resp_buf_bh_ind;
-	offset = ohci->AR_resp_buf_bh_offset;
+	idx = d->buf_ind;
+	offset = d->buf_offset;
+	buf_ptr = d->buf[idx] + offset/4;
 
-	buf_ptr = ohci->AR_resp_buf[idx];
-	buf_ptr += offset/4;
+	rescount = d->prg[idx]->status&0xffff;
+	bytes_left = d->buf_size - rescount - offset;
 
-        while(ohci->AR_resp_bytes_left > 0) {
-
-                /* check to see if a fatal error occurred */
-                if ((ohci->AR_resp_prg[idx]->status >> 16) & 0x800) {
-			sprintf(msg,"fatal async response receive error -- status is %d",
-				ohci->AR_resp_prg[idx]->status & 0x1F);
-			stop_ar_resp_context(ohci, msg);
-                        spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
-                        return;
-                }
-
-                spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
-
-		/* Let's see what kind of packet is in there */
+	while (bytes_left>0) {
 		tcode = (buf_ptr[0]>>4)&0xf;
-		if (tcode==2) /* no-data receive */
-		  packet_length=16;
-		else if (tcode==6) /* quadlet receive */
-		  packet_length=20;
-		else if (tcode==7) { /* block receive */
-			/* Where is the data length ? */
-			if (offset+12>=AR_RESP_BUF_SIZE) 
-			  packet_length=(ohci->AR_resp_buf[(idx+1)%AR_RESP_NUM_DESC]
-					 [3-(AR_RESP_BUF_SIZE-offset)/4]>>16)+20;
-			else 
-			  packet_length=(buf_ptr[3]>>16)+20;
-                        if (packet_length % 4)
-			  packet_length += 4 - (packet_length % 4);
-		}
-		else /* something is wrong */ {
-			sprintf(msg,"unexpected packet tcode %d in async response receive buffer",tcode);
-			stop_ar_resp_context(ohci,msg);
+		length = packet_length(d, idx, buf_ptr, offset);
+
+		if (length<4) { /* something is wrong */
+			sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d",
+				tcode, d->ctx);
+			stop_context(ohci, d->ctrlClear, msg);
+			spin_unlock(&d->lock);
 			return;
 		}
-		if ((offset+packet_length)>AR_RESP_BUF_SIZE) {
-			/* we have a split packet */
-			if (packet_length>AR_RESP_SPLIT_PACKET_BUF_SIZE) {
-				sprintf(msg,"packet size %d bytes exceed split packet buffer size %d bytes",
-					packet_length,AR_RESP_SPLIT_PACKET_BUF_SIZE);
-				stop_ar_resp_context(ohci, msg);
+
+		if ((offset+length)>d->buf_size) { /* Split packet */
+			if (length>d->split_buf_size) {
+				stop_context(ohci, d->ctrlClear,
+					     "split packet size exceeded");
+				d->buf_ind = idx;
+				d->buf_offset = offset;
+				spin_unlock(&d->lock);
 				return;
 			}
-			split_left = packet_length;
-			split_ptr = (char *)ohci->AR_resp_spb;
-			while (split_left>0) {
-				memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE-offset);
-				split_left -= AR_RESP_BUF_SIZE-offset;
-				split_ptr += AR_RESP_BUF_SIZE-offset;
-				ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
-				idx = (idx+1) % AR_RESP_NUM_DESC;
-				buf_ptr = ohci->AR_resp_buf[idx];
-				offset=0;
-				while (split_left >= AR_RESP_BUF_SIZE) {
-					memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE);
-					split_ptr += AR_RESP_BUF_SIZE;
-					split_left -= AR_RESP_BUF_SIZE;
-					ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
-					idx = (idx+1) % AR_RESP_NUM_DESC;
-					buf_ptr = ohci->AR_resp_buf[idx];
-				}
-				if (split_left>0) {
-					memcpy(split_ptr,buf_ptr,split_left);
-					offset = split_left;
-					split_left=0;
-					buf_ptr += split_left/4;
-				}
+			if (d->prg[(idx+1)%d->num_desc]->status==d->buf_size) {
+				/* other part of packet not written yet */
+				/* this should never happen I think */
+				/* anyway we'll get it on the next call */
+				PRINT(KERN_INFO, ohci->id,
+				      "Got only half a packet !!!");
+				d->buf_ind = idx;
+				d->buf_offset = offset;
+				spin_unlock(&d->lock);
+				return;
 			}
-#if 0
-			PRINT(KERN_INFO,ohci->id,"AR resp: received split packet tcode=%d length=%d",
-			      tcode,packet_length);
-#endif
-			hpsb_packet_received(ohci->host, ohci->AR_resp_spb, packet_length);
-			ohci->AR_resp_bytes_left -= packet_length;
+			split_left = length;
+			split_ptr = (char *)d->spb;
+			memcpy(split_ptr,buf_ptr,d->buf_size-offset);
+			split_left -= d->buf_size-offset;
+			split_ptr += d->buf_size-offset;
+			insert_dma_buffer(d, idx);
+			idx = (idx+1) % d->num_desc;
+			buf_ptr = d->buf[idx];
+			offset=0;
+			while (split_left >= d->buf_size) {
+				memcpy(split_ptr,buf_ptr,d->buf_size);
+				split_ptr += d->buf_size;
+				split_left -= d->buf_size;
+				insert_dma_buffer(d, idx);
+				idx = (idx+1) % d->num_desc;
+				buf_ptr = d->buf[idx];
+			}
+			if (split_left>0) {
+				memcpy(split_ptr, buf_ptr, split_left);
+				offset = split_left;
+				buf_ptr += offset/4;
+			}
+
+			/* 
+			 * We get one phy packet for each bus reset. 
+			 * we know that from now on the bus topology may
+			 * have changed. Just ignore it for the moment
+			 */
+			if (tcode != 0xE) {
+				DBGMSG(ohci->id, "Split packet received from"
+				       " node %d ack=0x%02X spd=%d tcode=0x%X"
+				       " length=%d data=0x%08x ctx=%d",
+				       (d->spb[1]>>16)&0x3f,
+				       (d->spb[length/4-1]>>16)&0x1f,
+				       (d->spb[length/4-1]>>21)&0x3,
+				       tcode, length, d->spb[3], d->ctx);
+				hpsb_packet_received(ohci->host, d->spb, 
+						     length);
+			}
+			else 
+				PRINT(KERN_INFO, ohci->id, 
+				      "Got phy packet ctx=%d ... discarded",
+				      d->ctx);
 		}
 		else {
-#if 0
-			PRINT(KERN_INFO,ohci->id,"AR resp: received packet tcode=%d length=%d",
-			      tcode,packet_length);
-#endif
-			hpsb_packet_received(ohci->host, buf_ptr, packet_length);
-			offset += packet_length;
-			buf_ptr += packet_length/4;
-			ohci->AR_resp_bytes_left -= packet_length;
-			if (offset==AR_RESP_BUF_SIZE) {
-				ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
-				idx = (idx+1) % AR_RESP_NUM_DESC;
-				buf_ptr = ohci->AR_resp_buf[idx];
+			/* 
+			 * We get one phy packet for each bus reset. 
+			 * we know that from now on the bus topology may
+			 * have changed. Just ignore it for the moment
+			 */
+			if (tcode != 0xE) {
+				DBGMSG(ohci->id, "Packet received from node"
+				       " %d ack=0x%02X spd=%d tcode=0x%X"
+				       " length=%d data=0x%08x ctx=%d",
+				       (buf_ptr[1]>>16)&0x3f,
+				       (buf_ptr[length/4-1]>>16)&0x1f,
+				       (buf_ptr[length/4-1]>>21)&0x3,
+				       tcode, length, buf_ptr[3], d->ctx);
+				hpsb_packet_received(ohci->host, buf_ptr, 
+						     length);
+			}
+			else 
+				PRINT(KERN_INFO, ohci->id, 
+				      "Got phy packet ctx=%d ... discarded",
+				      d->ctx);
+			offset += length;
+			buf_ptr += length/4;
+			if (offset==d->buf_size) {
+				insert_dma_buffer(d, idx);
+				idx = (idx+1) % d->num_desc;
+				buf_ptr = d->buf[idx];
 				offset=0;
 			}
 		}
-		
+		rescount = d->prg[idx]->status & 0xffff;
+		bytes_left = d->buf_size - rescount - offset;
+
 	}
+
+	d->buf_ind = idx;
+	d->buf_offset = offset;
+
+	spin_unlock(&d->lock);
+}
+
+/* Bottom half that processes sent packets */
+static void dma_trm_bh(void *data)
+{
+	struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
+	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+	struct hpsb_packet *packet;
+	u32 ack;
+
+	spin_lock(&d->lock);
+
+	if (d->first==NULL) {
+		stop_context(ohci, d->ctrlClear, 
+			     "Packet sent ack received but queue is empty");
+		spin_unlock(&d->lock);
+		return;
+	}
+	packet = d->first;
+	d->first = d->first->xnext;
+	if (d->first==NULL) d->last=NULL;
+	if (packet->data_size) 
+		ack = d->prg[d->sent_ind].end.status>>16;
+	else 
+		ack = d->prg[d->sent_ind].begin.status>>16;
+	d->sent_ind = (d->sent_ind+1)%d->num_desc;
+	d->free_prgs++;
+	spin_unlock(&d->lock);
 	
-	if (ohci->AR_resp_bytes_left<0) 
-	  stop_ar_resp_context(ohci, "Sync problem in AR resp dma buffer");
+	DBGMSG(ohci->id, "Packet sent to node %d ack=0x%X spd=%d ctx=%d",
+	       (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, d->ctx);
+	hpsb_packet_sent(ohci->host, packet, ack&0xf);
+}
+
+static int free_dma_rcv_ctx(struct dma_rcv_ctx *d)
+{
+	int i;
 
-	ohci->AR_resp_buf_bh_ind = idx;
-	ohci->AR_resp_buf_bh_offset = offset;
+	if (d==NULL) return -1;
 
-        spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+	if (d->buf) {
+		for (i=0; i<d->num_desc; i++) 
+			if (d->buf[i]) kfree(d->buf[i]);
+		kfree(d->buf);
+	}
+	if (d->prg) {
+		for (i=0; i<d->num_desc; i++) 
+			if (d->prg[i]) kfree(d->prg[i]);
+		kfree(d->prg);
+	}
+	if (d->spb) kfree(d->spb);
+	
+	kfree(d);
+	
+	return 0;
 }
 
-/* This is the bottom half that processes iso receive descriptor buffers. */
-static void ohci_ir_proc_desc(void *data)
+static struct dma_rcv_ctx *
+alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
+		  int buf_size, int split_buf_size, 
+		  int ctrlSet, int ctrlClear, int cmdPtr)
 {
-	quadlet_t *buf_ptr;
-	struct ti_ohci *ohci= (struct ti_ohci*)data;
-        int bytes_left, data_length;
-        unsigned int idx;
-        unsigned long flags;
-
-        spin_lock_irqsave(&ohci->IR_recv_lock, flags);
-
-        while(ohci->IR_buf_used > 0)
-        {
-                idx= ohci->IR_buf_last_ind;
-
-                /* check to see if a fatal error occurred */
-                if ((ohci->IR_recv_prg[idx]->status >> 16) & 0x800) {
-                        int i= 0;
-
-                        /* stop the context */
-			reg_write(ohci, OHCI1394_IrRcvContextControlClear,
-                                  0x8000);
-
-			while (reg_read(ohci, OHCI1394_IrRcvContextControlSet) 
-			       & 0x400) {
-				i++;
-
-				if (i > 5000) {
-					PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out...");
-					break;
-				}
+	struct dma_rcv_ctx *d=NULL;
+	int i;
 
-			}
+	d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), 
+					  GFP_KERNEL);
 
-                        spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
-                        PRINT(KERN_ERR, ohci->id,
-                              "fatal iso receive error -- status is %d",
-                              ohci->IR_recv_prg[idx]->status & 0x1F);
-                        return;
-                }
+	if (d==NULL) {
+		PRINT(KERN_ERR, ohci->id, "failed to allocate dma_rcv_ctx");
+		return NULL;
+	}
 
-                spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
+	d->ohci = (void *)ohci;
+	d->ctx = ctx;
 
-                buf_ptr= bus_to_virt(ohci->IR_recv_prg[idx]->address);
-                bytes_left= IR_RECV_BUF_SIZE;
+	d->num_desc = num_desc;
+	d->buf_size = buf_size;
+	d->split_buf_size = split_buf_size;
+	d->ctrlSet = ctrlSet;
+	d->ctrlClear = ctrlClear;
+	d->cmdPtr = cmdPtr;
 
-                /* are we processing a split packet from last buffer */
-                if (ohci->IR_sp_bytes_left) {
+	d->buf = NULL;
+	d->prg = NULL;
+	d->spb = NULL;
 
-                        if (!ohci->IR_spb_bytes_used) {
-                                /* packet is in process of being dropped */
-                                if (ohci->IR_sp_bytes_left > bytes_left) {
-                                        ohci->IR_sp_bytes_left-= bytes_left;
-                                        bytes_left= 0;
-                                } else {
-                                        buf_ptr= bus_to_virt((unsigned long)
-                                                &((quadlet_t*)ohci->IR_recv_prg
-                                                [idx]->address)
-                                                [ohci->IR_sp_bytes_left / 4]);
-                                        bytes_left-= ohci->IR_sp_bytes_left;
-                                        ohci->IR_sp_bytes_left= 0;
-                                }
+	d->buf = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
 
-                        } else {
-                                /* packet is being assembled */
-                                if (ohci->IR_sp_bytes_left > bytes_left) {
-                                        memcpy(&ohci->IR_spb
-                                               [ohci->IR_spb_bytes_used / 4],
-                                               buf_ptr, bytes_left);
-                                        ohci->IR_spb_bytes_used+= bytes_left;
-                                        ohci->IR_sp_bytes_left-= bytes_left;
-                                        bytes_left= 0;
-                                } else {
-                                        memcpy(&ohci->IR_spb
-                                               [ohci->IR_spb_bytes_used / 4],
-                                               buf_ptr,
-                                               ohci->IR_sp_bytes_left);
-                                        ohci->IR_spb_bytes_used+=
-                                                ohci->IR_sp_bytes_left;
-                                        hpsb_packet_received(ohci->host,
-                                                      ohci->IR_spb,
-                                                      ohci->IR_spb_bytes_used);
-                                        buf_ptr=
-                                                bus_to_virt((unsigned long)
-					       &((quadlet_t*)ohci->IR_recv_prg
-						 [idx]->address)
-					         [ohci->IR_sp_bytes_left / 4]);
-                                        bytes_left-= ohci->IR_sp_bytes_left;
-                                        ohci->IR_sp_bytes_left= 0;
-                                        ohci->IR_spb_bytes_used= 0;
-                                }
+	if (d->buf == NULL) {
+		PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer");
+		free_dma_rcv_ctx(d);
+		return NULL;
+	}
+	memset(d->buf, 0, d->num_desc * sizeof(quadlet_t*));
 
-                        }
+	d->prg = kmalloc(d->num_desc * 	sizeof(struct dma_cmd*), GFP_KERNEL);
 
-                }
+	if (d->prg == NULL) {
+		PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg");
+		free_dma_rcv_ctx(d);
+		return NULL;
+	}
+	memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd*));
 
-                while(bytes_left > 0) {
-                        data_length= (int)((buf_ptr[0] >> 16) & 0xffff);
+	d->spb = kmalloc(d->split_buf_size, GFP_KERNEL);
+
+	if (d->spb == NULL) {
+		PRINT(KERN_ERR, ohci->id, "failed to allocate split buffer");
+		free_dma_rcv_ctx(d);
+		return NULL;
+	}
 
-                        if (data_length % 4)
-                                data_length+= 4 - (data_length % 4);
+	for (i=0; i<d->num_desc; i++) {
+                d->buf[i] = kmalloc(d->buf_size, GFP_KERNEL);
+		
+                if (d->buf[i] != NULL) {
+			memset(d->buf[i], 0, d->buf_size);
+		} else {
+			PRINT(KERN_ERR, ohci->id, 
+			      "failed to allocate dma buffer");
+			free_dma_rcv_ctx(d);
+			return NULL;
+		}
 
-                        /* is this a split packet? */
-                        if ( (bytes_left - (data_length + 8)) < 0 ) {
+                d->prg[i]= kmalloc(sizeof(struct dma_cmd), GFP_KERNEL);
 
-                                if ( (data_length + 8) <=
-                                     IR_SPLIT_PACKET_BUF_SIZE ) {
-                                        memcpy(ohci->IR_spb, buf_ptr,
-                                               bytes_left);
-                                        ohci->IR_spb_bytes_used= bytes_left;
-                                } else {
-                                        PRINT(KERN_ERR, ohci->id, "Packet too large for split packet buffer... dropping it");
-                                        PRINT(KERN_DEBUG, ohci->id, "Header: %8.8x\n", buf_ptr[0]);
-                                        ohci->IR_spb_bytes_used= 0;
-                                }
+                if (d->prg[i] != NULL) {
+                        memset(d->prg[i], 0, sizeof(struct dma_cmd));
+		} else {
+			PRINT(KERN_ERR, ohci->id, 
+			      "failed to allocate dma prg");
+			free_dma_rcv_ctx(d);
+			return NULL;
+		}
+	}
 
-                                ohci->IR_sp_bytes_left=
-                                        (data_length + 8) - bytes_left;
-                        } else {
-                                hpsb_packet_received(ohci->host, buf_ptr,
-                                                     (data_length + 8));
-                                buf_ptr= bus_to_virt((unsigned long)
-                                               &((quadlet_t*)ohci->IR_recv_prg
-                                                [idx]->address)
-                                                [(IR_RECV_BUF_SIZE - bytes_left
-                                                  + data_length + 8) / 4]);
-                        }
+        spin_lock_init(&d->lock);
 
-                        bytes_left-= (data_length + 8);
-                }
+        /* initialize bottom handler */
+        d->task.routine = dma_rcv_bh;
+        d->task.data = (void*)d;
 
-                spin_lock_irqsave(&ohci->IR_recv_lock, flags);
-                ohci->IR_buf_last_ind= (idx + 1) % IR_NUM_DESC;
-                ohci->IR_buf_used--;
-        }
+	return d;
+}
 
-        spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
+static int free_dma_trm_ctx(struct dma_trm_ctx *d)
+{
+	if (d==NULL) return -1;
+	if (d->prg) kfree(d->prg);
+	kfree(d);
+	return 0;
 }
 
-static int add_card(struct pci_dev *dev)
+static struct dma_trm_ctx *
+alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
+		  int ctrlSet, int ctrlClear, int cmdPtr)
 {
-#define FAIL(fmt, args...) \
-	PRINT_G(KERN_ERR, fmt , ## args); \
-	  num_of_cards--; \
-	    remove_card(ohci); \
-	      return 1;
+	struct dma_trm_ctx *d=NULL;
 
+	d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx), 
+					  GFP_KERNEL);
+
+	if (d==NULL) {
+		PRINT(KERN_ERR, ohci->id, "failed to allocate dma_trm_ctx");
+		return NULL;
+	}
+
+	d->ohci = (void *)ohci;
+	d->ctx = ctx;
+	d->num_desc = num_desc;
+	d->ctrlSet = ctrlSet;
+	d->ctrlClear = ctrlClear;
+	d->cmdPtr = cmdPtr;
+	d->prg = NULL;
+
+	d->prg = kmalloc(d->num_desc * sizeof(struct at_dma_prg), GFP_KERNEL);
+
+	if (d->prg == NULL) {
+		PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg");
+		free_dma_trm_ctx(d);
+		return NULL;
+	}
+	memset(d->prg, 0, d->num_desc * sizeof(struct at_dma_prg));
+
+        spin_lock_init(&d->lock);
+
+        /* initialize bottom handler */
+        d->task.routine = dma_trm_bh;
+        d->task.data = (void*)d;
+
+	return d;
+}
+
+static int add_card(struct pci_dev *dev)
+{
 	struct ti_ohci *ohci;	/* shortcut to currently handled device */
-	int i;
 
 	if (num_of_cards == MAX_OHCI1394_CARDS) {
 		PRINT_G(KERN_WARNING, "cannot handle more than %d cards.  "
@@ -1185,124 +1371,51 @@
 		FAIL("failed to allocate DMA buffer for self-id packets");
 	}
 
-	/* AR dma buffer and program allocation */
-	ohci->AR_resp_buf=
-	        kmalloc(AR_RESP_NUM_DESC * sizeof(quadlet_t*),
-			GFP_KERNEL);
-
-	if (ohci->AR_resp_buf == NULL) {
-		FAIL("failed to allocate AR response receive DMA buffer");
-	}
-
-	ohci->AR_resp_prg=
-		kmalloc(AR_RESP_NUM_DESC * sizeof(struct dma_cmd*),
-			GFP_KERNEL);
-
-	if (ohci->AR_resp_prg == NULL) {
-		FAIL("failed to allocate AR response receive DMA program");
-	}
-
-	ohci->AR_resp_spb= kmalloc(AR_RESP_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
-
-	if (ohci->AR_resp_spb == NULL) {
-		FAIL("failed to allocate AR response split packet buffer");
-	}
-
-	for (i= 0; i < AR_RESP_NUM_DESC; i++) {
-                ohci->AR_resp_buf[i]= kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
-
-                if (ohci->AR_resp_buf[i] != NULL) {
-                        memset(ohci->AR_resp_buf[i], 0, AR_RESP_BUF_SIZE);
-                } else {
-                        FAIL("failed to allocate AR response DMA buffer");
-                }
-
-                ohci->AR_resp_prg[i]= kmalloc(sizeof(struct dma_cmd),
-                                                   GFP_KERNEL);
-
-                if (ohci->AR_resp_prg[i] != NULL) {
-                        memset(ohci->AR_resp_prg[i], 0,
-                               sizeof(struct dma_cmd));
-                } else {
-                        FAIL("failed to allocate AR response DMA buffer");
-                }
-
-	}
-
-        ohci->AR_resp_buf_th_ind = 0;
-        ohci->AR_resp_buf_th_offset = 0;
-        ohci->AR_resp_buf_bh_ind = 0;
-        ohci->AR_resp_buf_bh_offset = 0;
-        ohci->AR_resp_bytes_left = 0;
-        spin_lock_init(&ohci->AR_resp_lock);
-
-        /* initialize AR response receive task */
-        ohci->AR_resp_pdl_task.routine= ohci_ar_resp_proc_desc;
-        ohci->AR_resp_pdl_task.data= (void*)ohci;
-
-	/* AT dma program allocation */
-	ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE, 
-						      GFP_KERNEL);
-	if (ohci->AT_req_prg != NULL) {
-		memset(ohci->AT_req_prg, 0, AT_REQ_PRG_SIZE);
-	} else {
-		FAIL("failed to allocate AT request DMA program");
-	}
-
-	/* IR dma buffer and program allocation */
-	ohci->IR_recv_buf=
-		kmalloc(IR_NUM_DESC * sizeof(quadlet_t*),
-			GFP_KERNEL);
-
-	if (ohci->IR_recv_buf == NULL) {
-		FAIL("failed to allocate IR receive DMA buffer");
-	}
-
-	ohci->IR_recv_prg=
-		kmalloc(IR_NUM_DESC * sizeof(struct dma_cmd*),
-			GFP_KERNEL);
-
-	if (ohci->IR_recv_prg == NULL) {
-		FAIL("failed to allocate IR receive DMA program");
-	}
-
-	ohci->IR_spb= kmalloc(IR_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
-
-	if (ohci->IR_spb == NULL) {
-		FAIL("failed to allocate IR split packet buffer");
-	}
-
-	for (i= 0; i < IR_NUM_DESC; i++) {
-                ohci->IR_recv_buf[i]= kmalloc(IR_RECV_BUF_SIZE, GFP_KERNEL);
-
-                if (ohci->IR_recv_buf[i] != NULL) {
-                        memset(ohci->IR_recv_buf[i], 0, IR_RECV_BUF_SIZE);
-                } else {
-                        FAIL("failed to allocate IR DMA buffer");
-                }
+	ohci->ar_req_context = 
+		alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,
+				  AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
+				  OHCI1394_AsReqRcvContextControlSet,
+				  OHCI1394_AsReqRcvContextControlClear,
+				  OHCI1394_AsReqRcvCommandPtr);
+
+	if (ohci->ar_req_context == NULL) return 1;
+
+	ohci->ar_resp_context = 
+		alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC,
+				  AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
+				  OHCI1394_AsRspRcvContextControlSet,
+				  OHCI1394_AsRspRcvContextControlClear,
+				  OHCI1394_AsRspRcvCommandPtr);
+	
+	if (ohci->ar_resp_context == NULL) return 1;
 
-                ohci->IR_recv_prg[i]= kmalloc(sizeof(struct dma_cmd),
-                                              GFP_KERNEL);
+	ohci->at_req_context = 
+		alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC,
+				  OHCI1394_AsReqTrContextControlSet,
+				  OHCI1394_AsReqTrContextControlClear,
+				  OHCI1394_AsReqTrCommandPtr);
+	
+	if (ohci->at_req_context == NULL) return 1;
 
-                if (ohci->IR_recv_prg[i] != NULL) {
-                        memset(ohci->IR_recv_prg[i], 0,
-                               sizeof(struct dma_cmd));
-                } else {
-                        FAIL("failed to allocate IR DMA buffer");
-                }
+	ohci->at_resp_context = 
+		alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC,
+				  OHCI1394_AsRspTrContextControlSet,
+				  OHCI1394_AsRspTrContextControlClear,
+				  OHCI1394_AsRspTrCommandPtr);
+	
+	if (ohci->at_resp_context == NULL) return 1;
+				      
+	ohci->ir_context =
+		alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
+				  IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
+				  OHCI1394_IrRcvContextControlSet,
+				  OHCI1394_IrRcvContextControlClear,
+				  OHCI1394_IrRcvCommandPtr);
 
-	}
+	if (ohci->ir_context == NULL) return 1;
 
-        ohci->IR_buf_used= 0;
-        ohci->IR_buf_last_ind= 0;
-        ohci->IR_buf_next_ind= 0;
-        spin_lock_init(&ohci->IR_recv_lock);
-        spin_lock_init(&ohci->IR_channel_lock);
         ohci->IR_channel_usage= 0x0000000000000000;
-
-        /* initialize iso receive task */
-        ohci->IR_pdl_task.routine= ohci_ir_proc_desc;
-        ohci->IR_pdl_task.data= (void*)ohci;
+        spin_lock_init(&ohci->IR_channel_lock);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
 	ohci->registers = ioremap_nocache(dev->base_address[0],
@@ -1342,6 +1455,8 @@
 	//unsigned char phyreg;
 	//int i, nports;
 	int i;
+	struct dma_rcv_ctx *d=NULL;
+	struct dma_trm_ctx *dt=NULL;
 
 	p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n");
 	p += sprintf(p,"  bus number: 0x%x Node ID: 0x%x\n", 
@@ -1370,22 +1485,93 @@
 		     host->is_busmgr ? "bus_mgr" : "");
   
 	p += sprintf(p,"\n---Iso Receive DMA---\n");
-        for (i= 0; i < IR_NUM_DESC; i++) {
-                p += sprintf(p, "IR_recv_buf[%d] : %p  IR_recv_prg[%d]: %p\n",
-                             i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]);
+	d = ohci->ir_context;
+#if 0
+	for (i=0; i<d->num_desc; i++) {
+		p += sprintf(p, "IR buf[%d] : %p prg[%d]: %p\n",
+			     i, d->buf[i], i, d->prg[i]);
 	}
+#endif
+	p += sprintf(p, "Current buf: %d offset: %d\n",
+		     d->buf_ind,d->buf_offset);
+
+	p += sprintf(p,"\n---Async Receive DMA---\n");
+	d = ohci->ar_req_context;
+#if 0
+	for (i=0; i<d->num_desc; i++) {
+		p += sprintf(p, "AR req buf[%d] : %p prg[%d]: %p\n",
+			     i, d->buf[i], i, d->prg[i]);
+	}
+#endif
+	p += sprintf(p, "Ar req current buf: %d offset: %d\n",
+		     d->buf_ind,d->buf_offset);
+
+	d = ohci->ar_resp_context;
+#if 0
+	for (i=0; i<d->num_desc; i++) {
+		p += sprintf(p, "AR resp buf[%d] : %p prg[%d]: %p\n",
+			     i, d->buf[i], i, d->prg[i]);
+	}
+#endif
+	p += sprintf(p, "AR resp current buf: %d offset: %d\n",
+		     d->buf_ind,d->buf_offset);
+
+	p += sprintf(p,"\n---Async Transmit DMA---\n");
+	dt = ohci->at_req_context;
+	p += sprintf(p, "AT req prg: %d sent: %d free: %d branchAddrPtr: %p\n",
+		     dt->prg_ind, dt->sent_ind, dt->free_prgs, 
+		     dt->branchAddrPtr);
+	p += sprintf(p, "AT req queue: first: %p last: %p\n",
+		     dt->first, dt->last);
+	dt = ohci->at_resp_context;
+#if 0
+	for (i=0; i<dt->num_desc; i++) {
+		p += sprintf(p, "------- AT resp prg[%02d] ------\n",i);
+		p += sprintf(p, "%p: control  : %08x\n",
+			     &(dt->prg[i].begin.control),
+			     dt->prg[i].begin.control);
+		p += sprintf(p, "%p: address  : %08x\n",
+			     &(dt->prg[i].begin.address),
+			     dt->prg[i].begin.address);
+		p += sprintf(p, "%p: brancAddr: %08x\n",
+			     &(dt->prg[i].begin.branchAddress),
+			     dt->prg[i].begin.branchAddress);
+		p += sprintf(p, "%p: status   : %08x\n",
+			     &(dt->prg[i].begin.status),
+			     dt->prg[i].begin.status);
+		p += sprintf(p, "%p: header[0]: %08x\n",
+			     &(dt->prg[i].data[0]),
+			     dt->prg[i].data[0]);
+		p += sprintf(p, "%p: header[1]: %08x\n",
+			     &(dt->prg[i].data[1]),
+			     dt->prg[i].data[1]);
+		p += sprintf(p, "%p: header[2]: %08x\n",
+			     &(dt->prg[i].data[2]),
+			     dt->prg[i].data[2]);
+		p += sprintf(p, "%p: header[3]: %08x\n",
+			     &(dt->prg[i].data[3]),
+			     dt->prg[i].data[3]);
+		p += sprintf(p, "%p: control  : %08x\n",
+			     &(dt->prg[i].end.control),
+			     dt->prg[i].end.control);
+		p += sprintf(p, "%p: address  : %08x\n",
+			     &(dt->prg[i].end.address),
+			     dt->prg[i].end.address);
+		p += sprintf(p, "%p: brancAddr: %08x\n",
+			     &(dt->prg[i].end.branchAddress),
+			     dt->prg[i].end.branchAddress);
+		p += sprintf(p, "%p: status   : %08x\n",
+			     &(dt->prg[i].end.status),
+			     dt->prg[i].end.status);
+	}
+#endif
+	p += sprintf(p, "AR resp prg: %d sent: %d free: %d"
+		     " branchAddrPtr: %p\n",
+		     dt->prg_ind, dt->sent_ind, dt->free_prgs, 
+		     dt->branchAddrPtr);
+	p += sprintf(p, "AT resp queue: first: %p last: %p\n",
+		     dt->first, dt->last);
 
-	
-	p += sprintf(p,"\n---Async Reponse Receive DMA---\n");
-        for (i= 0; i < AR_RESP_NUM_DESC; i++) {
-                p += sprintf(p, "AR_resp_buf[%d] : %p  AR_resp_prg[%d]: %p\n",
-                             i, ohci->AR_resp_buf[i], i, ohci->AR_resp_prg[i]);
-	}
-	p += sprintf(p, "Current AR resp buf in irq handler: %d offset: %d\n",
-		     ohci->AR_resp_buf_th_ind,ohci->AR_resp_buf_th_offset);
-	p += sprintf(p, "Current AR resp buf in bottom half: %d offset: %d\n",
-		     ohci->AR_resp_buf_bh_ind,ohci->AR_resp_buf_bh_offset);
-	
 	/* ----- Register Dump ----- */
 	p += sprintf(p,"\n### HC Register dump ###\n");
 	SR("Version     : %08x  GUID_ROM    : %08x  ATRetries   : %08x\n",
@@ -1427,20 +1613,32 @@
 	SR("AsRsRvCtxCtl: %08x  AsRsRvCmdPtr: %08x  IntEvent    : %08x\n",
 	   OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr, 
 	   OHCI1394_IntEventSet);
-	
+	for (i=0;i<4;i++) {
+		p += sprintf(p,"IsoRCtxCtl%02d: %08x  IsoRCmdPtr%02d: %08x"
+			     "  IsoRCxtMch%02d: %08x\n", i,
+			     reg_read(ohci, 
+				      OHCI1394_IrRcvContextControlSet+32*i),
+			     i,reg_read(ohci, OHCI1394_IrRcvCommandPtr+32*i),
+			     i,reg_read(ohci, 
+					OHCI1394_IrRcvContextMatch+32*i));
+	}
+
 #if 0
 	p += sprintf(p,"\n### Phy Register dump ###\n");
 	phyreg=get_phy_reg(ohci,1);
-	p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d IBR: %d Gap_count: %d\n",
-		     1,phyreg,(phyreg&0x80) != 0, (phyreg&0x40) !=0, phyreg&0x3f);
+	p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d"
+		     "IBR: %d Gap_count: %d\n",
+		     1,phyreg,(phyreg&0x80) != 0, 
+		     (phyreg&0x40) !=0, phyreg&0x3f);
 	phyreg=get_phy_reg(ohci,2);
 	nports=phyreg&0x1f;
-	p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d E  : %d Ports    : %2d\n",
-		     2,phyreg,
-		     (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports);
+	p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d"
+		     " E  : %d Ports    : %2d\n",
+		     2,phyreg, (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports);
 	for (i=0;i<nports;i++) {
 		phyreg=get_phy_reg(ohci,3+i);
-		p += sprintf(p,"offset: %d val: 0x%02x -> [port %d] TPA: %d TPB: %d | %s %s\n",
+		p += sprintf(p,"offset: %d val: 0x%02x -> [port %d]"
+			     " TPA: %d TPB: %d | %s %s\n",
 			     3+i,phyreg,
 			     i, (phyreg&0xC0)>>6, (phyreg&0x30)>>4,
 			     (phyreg&0x08) ? "child" : "parent",
@@ -1454,11 +1652,6 @@
 		     phyreg&0x3f);
 #endif
 
-#if 0
-	p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control);
-	p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status);
-#endif
-
 	return  p - buf;
 }
 
@@ -1494,53 +1687,26 @@
 static void remove_card(struct ti_ohci *ohci)
 {
 	if (ohci->registers) 
-	  iounmap(ohci->registers);
+		iounmap(ohci->registers);
 
-	/* Free AR response buffers and programs */
-	if (ohci->AR_resp_buf) {
-		int i;
-                for (i= 0; i < AR_RESP_NUM_DESC; i++) {
-			kfree(ohci->AR_resp_buf[i]);
-		}
-		kfree(ohci->AR_resp_buf);
-	}
-	if (ohci->AR_resp_prg) {
-		int i;
-		for (i= 0; i < AR_RESP_NUM_DESC; i++) {
-			kfree(ohci->AR_resp_prg[i]);
-		}
-		kfree(ohci->AR_resp_prg);
-	}
-	kfree(ohci->AR_resp_spb);
+	/* Free AR dma */
+	free_dma_rcv_ctx(ohci->ar_req_context);
+	free_dma_rcv_ctx(ohci->ar_resp_context);
+
+	/* Free AT dma */
+	free_dma_trm_ctx(ohci->at_req_context);
+	free_dma_trm_ctx(ohci->at_resp_context);
 
-	/* Free AT request buffer and program */
-	if (ohci->AT_req_prg) 
-	  kfree(ohci->AT_req_prg);
-
-	/* Free Iso receive buffers and programs */
-	if (ohci->IR_recv_buf) {
-		int i;
-                for (i= 0; i < IR_NUM_DESC; i++) {
-			kfree(ohci->IR_recv_buf[i]);
-		}
-		kfree(ohci->IR_recv_buf);
-	}
-	if (ohci->IR_recv_prg) {
-		int i;
-		for (i= 0; i < IR_NUM_DESC; i++) {
-			kfree(ohci->IR_recv_prg[i]);
-		}
-		kfree(ohci->IR_recv_prg);
-	}
-	kfree(ohci->IR_spb);
+	/* Free IR dma */
+	free_dma_rcv_ctx(ohci->ir_context);
 
 	/* Free self-id buffer */
 	if (ohci->self_id_buffer)
-	  kfree(ohci->self_id_buffer);
+		kfree(ohci->self_id_buffer);
 	
 	/* Free config rom */
 	if (ohci->csr_config_rom)
-	  kfree(ohci->csr_config_rom);
+		kfree(ohci->csr_config_rom);
 
 	/* Free the IRQ */
 	free_irq(ohci->dev->irq, ohci);
@@ -1562,13 +1728,13 @@
 	PRINT_G(KERN_INFO, "looking for Ohci1394 cards");
 
 	for (i = 0; supported_chips[i][0] != -1; i++) {
-	    while ((dev = pci_find_device(supported_chips[i][0],
-					  supported_chips[i][1], dev)) 
-		   != NULL) {
-		if (add_card(dev) == 0) {
-		    success = 1;
+		while ((dev = pci_find_device(supported_chips[i][0],
+					      supported_chips[i][1], dev)) 
+		       != NULL) {
+			if (add_card(dev) == 0) {
+				success = 1;
+			}
 		}
-	    }
 	}
 
 	if (success == 0) {
@@ -1593,10 +1759,8 @@
 {
 	struct ti_ohci *ohci=host->hostdata;
 
-#if 0
-	PRINT(KERN_INFO, ohci->id, "request csr_rom address: %08X",
-	      (u32)ohci->csr_config_rom);
-#endif
+	DBGMSG(ohci->id, "request csr_rom address: %08X",
+	       (u32)ohci->csr_config_rom);
 
 	*ptr = ohci->csr_config_rom;
 	return sizeof(ohci_csr_rom);
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h
--- v2.3.46/linux/drivers/ieee1394/ohci1394.h	Tue Feb  1 01:35:43 2000
+++ linux/drivers/ieee1394/ohci1394.h	Sun Feb 20 20:32:50 2000
@@ -4,6 +4,8 @@
 
 #include "ieee1394_types.h"
 
+#define OHCI1394_DEBUG 1
+
 #define OHCI1394_DRIVER_NAME      "ohci1394"
 
 #ifndef PCI_DEVICE_ID_TI_OHCI1394
@@ -18,21 +20,34 @@
 #define PCI_DEVICE_ID_VIA_OHCI1394 0x3044
 #endif
 
+#ifndef PCI_VENDOR_ID_SONY
+#define PCI_VENDOR_ID_SONY 0x104d
+#endif
+
+#ifndef PCI_DEVICE_ID_SONY_CXD3222
+#define PCI_DEVICE_ID_SONY_CXD3222 0x8039
+#endif
+
 #define MAX_OHCI1394_CARDS        4
 
-#define OHCI1394_MAX_AT_REQ_RETRIES       1
-#define OHCI1394_MAX_AT_RESP_RETRIES      1
-#define OHCI1394_MAX_PHYS_RESP_RETRIES    4
+#define OHCI1394_MAX_AT_REQ_RETRIES       0x2
+#define OHCI1394_MAX_AT_RESP_RETRIES      0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES    0x8
+
+#define AR_REQ_NUM_DESC                   4 /* number of AR req descriptors */
+#define AR_REQ_BUF_SIZE                4096 /* size of AR req buffers */
+#define AR_REQ_SPLIT_BUF_SIZE          4096 /* split packet buffer */
 
 #define AR_RESP_NUM_DESC                  4 /* number of AR resp descriptors */
 #define AR_RESP_BUF_SIZE               4096 /* size of AR resp buffers */
-#define AR_RESP_SPLIT_PACKET_BUF_SIZE   256 /* split packet buffer */
-#define AR_RESP_TOTAL_BUF_SIZE         (AR_RESP_BUF_SIZE * AR_RESP_NUM_DESC)
-#define AT_REQ_PRG_SIZE                256
-
-#define IR_RECV_BUF_SIZE          4096 /* 4096 bytes/buffer */
-#define IR_SPLIT_PACKET_BUF_SIZE  8192 /* size of buffer for split packets */
-#define IR_NUM_DESC               16   /* number of ISO recv descriptors */
+#define AR_RESP_SPLIT_BUF_SIZE         4096 /* split packet buffer */
+
+#define IR_NUM_DESC                      16 /* number of IR descriptors */
+#define IR_BUF_SIZE                    6480 /* 6480 bytes/buffer */
+#define IR_SPLIT_BUF_SIZE              8192 /* split packet buffer */
+
+#define AT_REQ_NUM_DESC                  32 /* number of AT req descriptors */
+#define AT_RESP_NUM_DESC                 32 /* number of AT resp descriptors */
 
 struct dma_cmd {
         u32 control;
@@ -41,6 +56,50 @@
         u32 status;
 };
 
+struct at_dma_prg {
+	struct dma_cmd begin;
+	quadlet_t data[4];
+	struct dma_cmd end;
+};
+
+/* DMA receive context */
+struct dma_rcv_ctx {
+	void *ohci;
+	int ctx;
+	unsigned int num_desc;
+	unsigned int buf_size;
+	unsigned int split_buf_size;
+        struct dma_cmd **prg;
+        quadlet_t **buf;
+        unsigned int buf_ind;
+        unsigned int buf_offset;
+        quadlet_t *spb;
+        spinlock_t lock;
+        struct tq_struct task;
+	int ctrlClear;
+	int ctrlSet;
+	int cmdPtr;
+};
+
+/* DMA transmit context */	
+struct dma_trm_ctx {
+	void *ohci;
+	int ctx;
+	unsigned int num_desc;
+        struct at_dma_prg *prg;
+        unsigned int prg_ind;
+        unsigned int sent_ind;
+	int free_prgs;
+        quadlet_t *branchAddrPtr;
+        struct hpsb_packet *first;
+        struct hpsb_packet *last;
+        spinlock_t lock;
+        struct tq_struct task;
+	int ctrlClear;
+	int ctrlSet;
+	int cmdPtr;
+};
+
 struct ti_ohci {
         int id; /* sequential card number */
 
@@ -54,42 +113,18 @@
         quadlet_t *self_id_buffer; /* dma buffer for self-id packets */
         quadlet_t *csr_config_rom; /* buffer for csr config rom */
 
-        /* asynchronous receive */
-        struct dma_cmd **AR_resp_prg;
-        quadlet_t **AR_resp_buf;
-        unsigned int AR_resp_buf_bh_ind;
-        unsigned int AR_resp_buf_bh_offset;
-        unsigned int AR_resp_buf_th_ind;
-        unsigned int AR_resp_buf_th_offset;
-	int AR_resp_bytes_left;
-        quadlet_t *AR_resp_spb;
-        spinlock_t AR_resp_lock;
-
-        /* async receive task */
-        struct tq_struct AR_resp_pdl_task;
-
-        /* asynchronous transmit */
-        struct dma_cmd *AT_req_prg;
-
-        /* isochronous receive */
-        struct dma_cmd **IR_recv_prg;
-        quadlet_t **IR_recv_buf;
-        unsigned int IR_buf_used;
-        unsigned int IR_buf_last_ind;
-        unsigned int IR_buf_next_ind;
-        spinlock_t IR_recv_lock;
-
-        /* iso recv split packet handling */
-        quadlet_t *IR_spb;
-        unsigned int IR_sp_bytes_left;
-        unsigned int IR_spb_bytes_used;
+        /* async receive */
+	struct dma_rcv_ctx *ar_resp_context;
+	struct dma_rcv_ctx *ar_req_context;
+
+	/* async transmit */
+	struct dma_trm_ctx *at_resp_context;
+	struct dma_trm_ctx *at_req_context;
 
-        /* iso receive channel usage */
-        spinlock_t IR_channel_lock;
+        /* iso receive */
+	struct dma_rcv_ctx *ir_context;
         u64 IR_channel_usage;
-
-        /* iso receive task */
-        struct tq_struct IR_pdl_task;
+        spinlock_t IR_channel_lock;
 
         /* IEEE-1394 part follows */
         struct hpsb_host *host;
@@ -98,16 +133,9 @@
 
         spinlock_t phy_reg_lock;
 
-        struct hpsb_packet *async_queue;
-        spinlock_t async_queue_lock;
-
-        int AR_resp_active;
         int NumBusResets;
-        int TxRdy;
-        int NumInterrupts;
 };
 
-
 /*
  * Register read and write helper functions.
  */
@@ -129,9 +157,9 @@
         /* bus info block */
         0x04040000, /* info/CRC length, CRC */
         0x31333934, /* 1394 magic number */
-        0xf064a000, /* misc. settings - FIXME */
-        0x08002856, /* vendor ID, chip ID high */
-        0x0000083E, /* chip ID low */
+        0xf07da002, /* cyc_clk_acc = 125us, max_rec = 1024 */
+        0x00000000, /* vendor ID, chip ID high (written from card info) */
+        0x00000000, /* chip ID low (written from card info) */
         /* root directory - FIXME */
         0x00090000, /* CRC length, CRC */
         0x03080028, /* vendor ID (Texas Instr.) */
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/pcilynx.h linux/drivers/ieee1394/pcilynx.h
--- v2.3.46/linux/drivers/ieee1394/pcilynx.h	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/pcilynx.h	Sun Feb 20 20:32:50 2000
@@ -348,8 +348,8 @@
         struct {
                 u32 control;
                 u32 pointer;
-        } buffer[13];
-};
+        } buffer[13] __attribute__ ((packed));
+} __attribute__ ((packed));
 
 #include <linux/stddef.h>
 #define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
@@ -383,7 +383,11 @@
 
 inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
+        return lynx->dev->base_address[1] + pclid * sizeof(struct ti_pcl);
+#else
         return lynx->dev->resource[1].start + pclid * sizeof(struct ti_pcl);
+#endif
 }
 
 #else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c
--- v2.3.46/linux/drivers/ieee1394/raw1394.c	Tue Feb  1 01:35:43 2000
+++ linux/drivers/ieee1394/raw1394.c	Sun Feb 20 20:32:50 2000
@@ -3,7 +3,7 @@
  *
  * Raw interface to the bus
  *
- * Copyright (C) 1999 Andreas E. Bombe
+ * Copyright (C) 1999, 2000 Andreas E. Bombe
  */
 
 #include <linux/kernel.h>
@@ -30,6 +30,9 @@
 
 static struct hpsb_highlevel *hl_handle = NULL;
 
+static atomic_t iso_buffer_size;
+static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
+
 static void queue_complete_cb(struct pending_request *req);
 
 static struct pending_request *__alloc_pending_request(int flags)
@@ -56,6 +59,7 @@
 {
         if (req->ibs) {
                 if (atomic_dec_and_test(&req->ibs->refcount)) {
+                        atomic_sub((req->data[0] >> 16) + 4, &iso_buffer_size);
                         kfree(req->ibs);
                 }
         } else if (req->free_data) {
@@ -210,6 +214,10 @@
         struct iso_block_store *ibs = NULL;
         LIST_HEAD(reqs);
 
+        if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+                return;
+        }
+
         spin_lock_irqsave(&host_info_lock, flags);
         hi = find_host_info(host);
 
@@ -227,6 +235,7 @@
                                               + length, SLAB_ATOMIC);
                                 if (!ibs) break;
 
+                                atomic_add(length, &iso_buffer_size);
                                 atomic_set(&ibs->refcount, 0);
                                 memcpy(ibs->data, data, length);
                         }
diff -u --recursive --new-file v2.3.46/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.3.46/linux/drivers/isdn/isdn_net.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/isdn_net.c	Thu Feb 17 09:18:47 2000
@@ -483,7 +483,7 @@
  * Instead I chose to add isdn_net_started() which gives the state of the 
  * master in case of slaves.
  * I'm still not sure if this is how it's supposed to be done this way
- * because it uses test_bit(LINK_STATE_START, &dev->state) which might be 
+ * because it uses netif_running(dev) which might be 
  * considered private to the network layer. However, it works for now.
  * Alternative: set a flag in _open() and clear it in _close() 
  *
@@ -506,7 +506,7 @@
 		dev = lp->master;
 	else
 		dev = &n->dev;
-	return test_bit(LINK_STATE_START, &dev->state);
+	return netif_running(dev);
 }
 
 /*
diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.3.46/linux/drivers/net/3c505.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/3c505.c	Thu Feb 17 09:18:47 2000
@@ -361,7 +361,8 @@
 static inline void prime_rx(struct net_device *dev)
 {
 	elp_device *adapter = dev->priv;
-	while (adapter->rx_active < ELP_RX_PCBS && test_bit(LINK_STATE_START, &dev->state)) {
+	while (adapter->rx_active < ELP_RX_PCBS &&
+	       netif_running(dev->state)) {
 		if (!start_receive(dev, &adapter->itx_pcb))
 			break;
 	}
@@ -722,7 +723,7 @@
 				case 0xff:
 				case CMD_RECEIVE_PACKET_COMPLETE:
 					/* if the device isn't open, don't pass packets up the stack */
-					if (test_bit(LINK_STATE_START, &dev->state) == 0)
+					if (!netif_running(dev))
 						break;
 					len = adapter->irx_pcb.data.rcv_resp.pkt_len;
 					dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
@@ -806,7 +807,7 @@
 				case CMD_TRANSMIT_PACKET_COMPLETE:
 					if (elp_debug >= 3)
 						printk("%s: interrupt - packet sent\n", dev->name);
-					if (test_bit(LINK_STATE_START, &dev->state) == 0)
+					if (!netif_running(dev))
 						break;
 					switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
 					case 0xffff:
@@ -1121,7 +1122,7 @@
 
 	/* If the device is closed, just return the latest stats we have,
 	   - we cannot ask from the adapter without interrupts */
-	if (!test_bit(LINK_STATE_START, &dev->state))
+	if (!netif_running(dev))
 		return &adapter->stats;
 
 	/* send a get statistics command to the board */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.3.46/linux/drivers/net/3c507.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/3c507.c	Thu Feb 17 09:18:47 2000
@@ -576,8 +576,7 @@
 	/* Acknowledge the interrupt sources. */
 	ack_cmd = status & 0xf000;
 
-	if ((status & 0x0700) != 0x0200 &&
-	    (test_bit(LINK_STATE_START, &dev->state))) {
+	if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
 		if (net_debug)
 			printk("%s: Command unit stopped, status %04x, restarting.\n",
 				   dev->name, status);
@@ -587,9 +586,7 @@
 		ack_cmd |= CUC_RESUME;
 	}
 
-	if ((status & 0x0070) != 0x0040  &&
-	    (test_bit(LINK_STATE_START, &dev->state)))
-	{
+	if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
 		static void init_rx_bufs(struct net_device *);
 		/* The Rx unit is not ready, it must be hung.  Restart the receiver by
 		   initializing the rx buffers, and issuing an Rx start command. */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.3.46/linux/drivers/net/3c515.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/3c515.c	Thu Feb 17 09:18:47 2000
@@ -1081,8 +1081,7 @@
 		   other interrupt problems. */
 		if (donedidthis++ > 100) {
 			printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
-				dev->name, status,
-				test_bit(LINK_STATE_START, &dev->state));
+				   dev->name, status, netif_running(dev));
 			free_irq(dev->irq, dev);
 		}
 	}
@@ -1426,7 +1425,7 @@
 	    (struct corkscrew_private *) dev->priv;
 	unsigned long flags;
 
-	if (test_bit(LINK_STATE_START, &dev->state)) {
+	if (netif_running(dev)) {
 		save_flags(flags);
 		cli();
 		update_stats(dev->base_addr, dev);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.3.46/linux/drivers/net/3c523.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/3c523.c	Thu Feb 17 09:18:47 2000
@@ -869,7 +869,7 @@
 	if (dev == NULL) {
 		printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2));
 		return;
-	} else if (!test_bit(LINK_STATE_START, &dev->state)) {
+	} else if (!netif_running(dev)) {
 		/* The 3c523 has this habit of generating interrupts during the
 		   reset.  I'm not sure if the ni52 has this same problem, but it's
 		   really annoying if we haven't finished initializing it.  I was
@@ -902,7 +902,7 @@
 #ifndef NO_NOPCOMMANDS
 		if (stat & STAT_CNA) {
 			/* CU went 'not ready' */
-			if (test_bit(LINK_STATE_START, &dev->state)) {
+			if (netif_running(dev->state)) {
 				printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status);
 			}
 		}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.3.46/linux/drivers/net/3c59x.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/3c59x.c	Fri Feb 18 15:07:20 2000
@@ -1085,7 +1085,7 @@
 				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 = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ));
+			vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
 		}
 		/* Wrap the ring. */
 		vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
@@ -1407,7 +1407,7 @@
 	if (vp->bus_master) {
 		/* Set the bus-master controller to transfer the packet. */
 		int len = (skb->len + 3) & ~3;
-		outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len), ioaddr + Wn7_MasterAddr);
+		outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr);
 		outw(len, ioaddr + Wn7_MasterLen);
 		vp->tx_skb = skb;
 		outw(StartDMADown, ioaddr + EL3_CMD);
@@ -1479,7 +1479,7 @@
 		}
 		vp->tx_skbuff[entry] = skb;
 		vp->tx_ring[entry].next = 0;
-		vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len));
+		vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
 		vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
 		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
 
@@ -1559,7 +1559,7 @@
 				if (vp->tx_skbuff[entry]) {
 					struct sk_buff *skb = vp->tx_skbuff[entry];
 					
-					pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len);
+					pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
 					dev_kfree_skb_irq(vp->tx_skbuff[entry]);
 					vp->tx_skbuff[entry] = 0;
 				}
@@ -1576,7 +1576,7 @@
 		if (status & DMADone) {
 			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
 				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3);
+				pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE);
 				dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
 				if (inw(ioaddr + TxFree) > 1536) {
 					netif_wake_queue(dev);
@@ -1657,13 +1657,13 @@
 				if (vp->bus_master &&
 					! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) {
 					dma_addr_t dma = pci_map_single(vp->pdev, skb_put(skb, pkt_len),
-									   pkt_len);
+									   pkt_len, PCI_DMA_FROMDEVICE);
 					outl(dma, ioaddr + Wn7_MasterAddr);
 					outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
 					outw(StartDMAUp, ioaddr + EL3_CMD);
 					while (inw(ioaddr + Wn7_MasterStatus) & 0x8000)
 						;
-					pci_unmap_single(vp->pdev, dma, pkt_len);
+					pci_unmap_single(vp->pdev, dma, pkt_len, PCI_DMA_FROMDEVICE);
 				} else {
 					insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
 						 (pkt_len + 3) >> 2);
@@ -1737,7 +1737,7 @@
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ);
+				pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				memcpy(skb_put(skb, pkt_len),
 					   vp->rx_skbuff[entry]->tail,
@@ -1748,7 +1748,7 @@
 				skb = vp->rx_skbuff[entry];
 				vp->rx_skbuff[entry] = NULL;
 				skb_put(skb, pkt_len);
-				pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ);
+				pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				rx_nocopy++;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
@@ -1777,7 +1777,7 @@
 				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[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ));
+			vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
 			vp->rx_skbuff[entry] = skb;
 		}
 		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
@@ -1825,7 +1825,7 @@
 		outl(0, ioaddr + UpListPtr);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			if (vp->rx_skbuff[i]) {
-				pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ);
+				pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				DEV_FREE_SKB(vp->rx_skbuff[i]);
 				vp->rx_skbuff[i] = 0;
 			}
@@ -1836,7 +1836,7 @@
 			if (vp->tx_skbuff[i]) {
 				struct sk_buff *skb = vp->tx_skbuff[i];
 
-				pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len);
+				pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
 				DEV_FREE_SKB(skb);
 				vp->tx_skbuff[i] = 0;
 			}
@@ -1852,7 +1852,7 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
 
-	if (test_bit(LINK_STATE_START, &dev->state)) {
+	if (netif_running(dev)) {
 		save_flags(flags);
 		cli();
 		update_stats(dev->base_addr, dev);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.3.46/linux/drivers/net/8139too.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/8139too.c	Sun Feb 20 09:06:14 2000
@@ -87,7 +87,7 @@
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.2"
+#define RTL8139_VERSION "0.9.3"
 #define RTL8139_MODULE_NAME "8139too"
 #define RTL8139_DRIVER_NAME   RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX RTL8139_MODULE_NAME ": "
@@ -154,7 +154,7 @@
 	HAS_LNK_CHNG = 0x040000,
 };
 
-#define RTL_IO_SIZE 256
+#define RTL_IO_SIZE 0x80
 
 #define RTL8139_CAPS  HAS_CHIP_XCVR|HAS_LNK_CHNG
 
@@ -163,8 +163,6 @@
 	RTL8139_CB,
 	SMC1211TX,
 	/*MPX5030,*/
-	SIS900,
-	SIS7016,
 	DELTA8139,
 	ADDTRON8139,
 } chip_t;
@@ -178,8 +176,6 @@
 	{ RTL8139_CB, "RealTek RTL8139B PCI/CardBus"},
 	{ SMC1211TX, "SMC1211TX EZCard 10/100 (RealTek RTL8139)"},
 /*	{ MPX5030, "Accton MPX5030 (RealTek RTL8139)"},*/
-	{ SIS900, "SiS 900 (RealTek RTL8139) Fast Ethernet"},
-	{ SIS7016, "SiS 7016 (RealTek RTL8139) Fast Ethernet"},
 	{ DELTA8139, "Delta Electronics 8139 10/100BaseTX"},
 	{ ADDTRON8139, "Addtron Technolgy 8139 10/100BaseTX"},
 	{0,},
@@ -191,8 +187,6 @@
 	{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB },
 	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
 /*	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
-	{0x1039, 0x0900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS900 },
-	{0x1039, 0x7016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS7016 },
 	{0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
 	{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
 	{0,},
@@ -1202,7 +1196,7 @@
 			tp->stats.tx_dropped++;
 		}
 		if (rp->mapping != 0) {
-			pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len);
+			pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);
 			rp->mapping = 0;
 		}
 	}
@@ -1258,7 +1252,7 @@
 		RTL_W32 (TxAddr0 + entry * 4, tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
 	} else {
 		tp->tx_info[entry].mapping =
-			pci_map_single(tp->pci_dev, skb->data, skb->len);
+			pci_map_single(tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
 
 		assert (tp->tx_info[entry].mapping > 0);
 		RTL_W32 (TxAddr0 + entry * 4, tp->tx_info[entry].mapping);
@@ -1334,7 +1328,8 @@
 		if (tp->tx_info[entry].mapping != 0) {
 			pci_unmap_single (tp->pci_dev,
 					  tp->tx_info[entry].mapping,
-					  tp->tx_info[entry].skb->len);
+					  tp->tx_info[entry].skb->len,
+					  PCI_DMA_TODEVICE);
 			tp->tx_info[entry].mapping = 0;
 		}
 		/* Free the original skb. */
@@ -1675,7 +1670,7 @@
 
 		if (skb) {
 			if (mapping)
-				pci_unmap_single (tp->pci_dev, mapping, skb->len);
+				pci_unmap_single (tp->pci_dev, mapping, skb->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb (skb);
 		}
 		tp->tx_info[i].skb = NULL;
@@ -1738,7 +1733,7 @@
 
 	assert (tp != NULL);
 
-	if (test_bit(LINK_STATE_START, &dev->state)) {
+	if (netif_running(dev)) {
 		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 		RTL_W32 (RxMissed, 0);
 	}
@@ -1865,6 +1860,8 @@
 		printk (KERN_INFO RTL8139_DRIVER_NAME
 			" loaded (%d device%s registered)\n",
 			rc, rc > 1 ? "s" : "");
+	} else {
+		pci_unregister_driver (&rtl8139_pci_driver);
 	}
 
 	DPRINTK ("EXIT\n");
diff -u --recursive --new-file v2.3.46/linux/drivers/net/82596.c linux/drivers/net/82596.c
--- v2.3.46/linux/drivers/net/82596.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/82596.c	Thu Feb 17 09:18:47 2000
@@ -1251,7 +1251,7 @@
 		}
 
 		if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) &&
-		    (test_bit(LINK_STATE_START, &dev->state)))
+		    netif_running(dev))
 			ack_cmd |= CUC_START;
 		lp->scb.cmd = WSWAPcmd(lp->cmd_head);
 	}
@@ -1260,7 +1260,7 @@
 			printk("%s: i596 interrupt received a frame.\n", dev->name);
 		/* Only RX_START if stopped - RGH 07-07-96 */
 		if (status & 0x1000) {
-			if (test_bit(LINK_STATE_START, &dev->state))
+			if (netif_running(dev))
 				ack_cmd |= RX_START;
 			if (i596_debug > 1)
 				printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.3.46/linux/drivers/net/8390.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/8390.c	Thu Feb 17 09:18:47 2000
@@ -167,7 +167,6 @@
 	NS8390_init(dev, 1);
 	/* Set the flag before we drop the lock, That way the IRQ arrives
 	   after its set and we get no silly warnings */
-	clear_bit(LINK_STATE_RXSEM, &dev->state);
 	netif_start_queue(dev);
       	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	ei_local->irqlock = 0;
@@ -203,8 +202,8 @@
 	 *  board has died and kick it.
 	 */
  
-	if (test_bit(LINK_STATE_XOFF, &dev->state)) 
-	{	/* Do timeouts, just like the 8003 driver. */
+	if (netif_queue_stopped(dev)) {
+		/* Do timeouts, just like the 8003 driver. */
 		int txsr;
 		int isr;
 		int tickssofar = jiffies - dev->trans_start;
@@ -224,8 +223,7 @@
 
 		ei_local->stat.tx_errors++;
 		isr = inb(e8390_base+EN0_ISR);
-		if (!test_bit(LINK_STATE_START, &dev->state))
-		{
+		if (!netif_running(dev)) {
 			spin_unlock_irqrestore(&ei_local->page_lock, flags);
 			printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name);
 			return 1;
@@ -430,8 +428,6 @@
 		return;
 	}
     
-	set_bit(LINK_STATE_RXSEM, &dev->state);
-    
 	/* Change to page 0 and read the intr status reg. */
 	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
 	if (ei_debug > 3)
@@ -442,8 +438,7 @@
 	while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
 		   && ++nr_serviced < MAX_SERVICE) 
 	{
-		if (!test_bit(LINK_STATE_START, &dev->state))
-		{
+		if (!netif_running(dev)) {
 			printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
 			interrupts = 0;
 			break;
@@ -491,7 +486,6 @@
 			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
 		}
 	}
-	clear_bit(LINK_STATE_RXSEM, &dev->state);
 	spin_unlock(&ei_local->page_lock);
 	return;
 }
@@ -837,7 +831,7 @@
 	unsigned long flags;
     
 	/* If the card is stopped, just return the present stats. */
-	if (!test_bit(LINK_STATE_START, &dev->state))
+	if (!netif_running(dev))
 		return &ei_local->stat;
 
 	spin_lock_irqsave(&ei_local->page_lock,flags);
@@ -933,7 +927,7 @@
 	 * Ultra32 EISA) appears to have this bug fixed.
 	 */
 	 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
 	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
 	for(i = 0; i < 8; i++) 
diff -u --recursive --new-file v2.3.46/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.46/linux/drivers/net/Config.in	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/Config.in	Sun Feb 20 20:14:55 2000
@@ -136,8 +136,11 @@
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
          tristate '    DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
       fi
-      tristate '    EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
+      tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+         if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then
+	    bool '      Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM
+	 fi
 	 tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
 	 tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
       fi
@@ -189,6 +192,7 @@
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
    bool '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+   tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --recursive --new-file v2.3.46/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.46/linux/drivers/net/Makefile	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/Makefile	Sun Feb 20 20:14:55 2000
@@ -17,7 +17,8 @@
 SUB_DIRS     := 
 MOD_SUB_DIRS :=
 MOD_IN_SUB_DIRS :=
-ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin arcnet
+ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \
+		arcnet skfp
 
 O_TARGET := net.o
 MOD_LIST_NAME := NET_MODULES
@@ -119,7 +120,7 @@
 obj-$(CONFIG_VORTEX) += 3c59x.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
 obj-$(CONFIG_PCNET32) += pcnet32.o
-obj-$(CONFIG_EEXPRESS_PRO100) += eepro100.o
+obj-$(CONFIG_EEPRO100) += eepro100.o
 obj-$(CONFIG_TLAN) += tlan.o
 obj-$(CONFIG_TULIP) += tulip.o
 obj-$(CONFIG_EPIC100) += epic100.o
@@ -134,6 +135,15 @@
 else
   ifeq ($(CONFIG_SK98LIN),m)
   MOD_IN_SUB_DIRS += sk98lin
+  endif
+endif
+
+ifeq ($(CONFIG_SKFP),y)
+  SUB_DIRS += skfp
+  obj-y += skfp/skfp.o
+else
+  ifeq ($(CONFIG_SKFP),m)
+    MOD_IN_SUB_DIRS += skfp
   endif
 endif
 
diff -u --recursive --new-file v2.3.46/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.46/linux/drivers/net/Space.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/Space.c	Fri Feb 18 14:55:53 2000
@@ -120,6 +120,7 @@
 /* FDDI adapters */
 extern int dfx_probe(struct net_device *dev);
 extern int apfddi_init(struct net_device *dev);
+extern int skfp_probe(struct net_device *dev);
 
 /* Fibre Channel adapters */
 extern int iph5526_probe(struct net_device *dev);
@@ -469,6 +470,9 @@
 #endif
 #ifdef CONFIG_APFDDI
 	&& apfddi_init(dev)
+#endif
+#ifdef CONFIG_SKFP
+	&& skfp_probe(dev)
 #endif
 	&& 1 ) {
 	    return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v2.3.46/linux/drivers/net/a2065.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/a2065.c	Thu Feb 17 09:18:47 2000
@@ -467,8 +467,7 @@
 		ll->rdp = LE_C0_STRT;
 	}
 
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
-	    TX_BUFFS_AVAIL > 0)
+	if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL > 0)
 		netif_wake_queue(dev);
 
 	ll->rap = LE_CSR0;
@@ -687,7 +686,7 @@
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_regs *ll = lp->ll;
 
-	if (!test_bit(LINK_STATE_START, &dev->state))
+	if (!netif_running(dev))
 		return;
 
 	if (lp->tx_old != lp->tx_new) {
diff -u --recursive --new-file v2.3.46/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.3.46/linux/drivers/net/acenic.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/acenic.c	Fri Feb 18 15:07:20 2000
@@ -27,6 +27,8 @@
  *                with 'testing the tx_ret_csm and setting tx_full'
  *   David S. Miller <davem@redhat.com>: conversion to new PCI dma mapping
  *                                       infrastructure and Sparc support
+ *   Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the
+ *                              driver under Linux/Sparc64
  */
 
 #include <linux/config.h>
@@ -59,6 +61,7 @@
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
+
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
 #define ACE_IS_TIGON_I(ap)	0
 #else
@@ -118,8 +121,8 @@
 	return virt_ptr;
 }
 #define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
-#define pci_map_single(cookie, address, size)		virt_to_bus(address)
-#define pci_unmap_single(cookie, address, size)
+#define pci_map_single(cookie, address, size, dir)		virt_to_bus(address)
+#define pci_unmap_single(cookie, address, size, dir)
 #endif
 
 #if (LINUX_VERSION_CODE < 0x02032b)
@@ -144,8 +147,8 @@
 #else
 #define NET_BH			0
 #define ace_mark_net_bh(foo)	{do{} while(0);}
-#define ace_if_busy(dev)	test_bit(LINK_STATE_XOFF, &dev->state)
-#define ace_if_running(dev)	test_bit(LINK_STATE_START, &dev->state)
+#define ace_if_busy(dev)	netif_queue_stopped(dev)
+#define ace_if_running(dev)	netif_running(dev)
 #define ace_if_down(dev)	{do{} while(0);}
 #endif
 
@@ -334,10 +337,14 @@
 #define ACE_JUMBO_BUFSIZE	(ACE_JUMBO_MTU + ETH_HLEN + 2+4+16)
 
 #define DEF_TX_RATIO		24
-#define DEF_TX_COAL		1000
+/*
+ * There seems to be a magic difference in the effect between 995 and 996
+ * but little difference between 900 and 995 ... no idea why.
+ */
+#define DEF_TX_COAL		996
 #define DEF_TX_MAX_DESC		40
 #define DEF_RX_COAL		1000
-#define DEF_RX_MAX_DESC		20
+#define DEF_RX_MAX_DESC		25
 #define TX_COAL_INTS_ONLY	0	/* seems not worth it */
 #define DEF_TRACE		0
 #define DEF_STAT		2 * TICKS_PER_SEC
@@ -352,7 +359,7 @@
 static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static const char __initdata *version = 
-  "acenic.c: v0.39 02/11/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
+  "acenic.c: v0.41 02/16/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev = NULL;
@@ -421,7 +428,6 @@
 		ap->pdev = pdev;
 
 		dev->irq = pdev->irq;
-
 		dev->open = &ace_open;
 		dev->hard_start_xmit = &ace_start_xmit;
 		dev->stop = &ace_close;
@@ -523,8 +529,12 @@
 			break;
 		}
 		ap->name [sizeof (ap->name) - 1] = '\0';
-		printk("Gigabit Ethernet at 0x%08lx, irq %i\n",
-		       dev->base_addr, dev->irq);
+		printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
+#ifdef __sparc__
+		printk("irq %s\n", __irq_itoa(dev->irq));
+#else
+		printk("irq %i\n", dev->irq);
+#endif
 
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
 		if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
@@ -598,7 +608,7 @@
 		/*
 		 * This clears any pending interrupts
 		 */
-		writel(0, &regs->Mb0Lo);
+		writel(1, &regs->Mb0Lo);
 
 		/*
 		 * Make sure no other CPUs are processing interrupts
@@ -622,7 +632,8 @@
 				ap->rx_std_ring[i].size = 0;
 				ap->skb->rx_std_skbuff[i].skb = NULL;
 				pci_unmap_single(ap->pdev, mapping,
-						 ACE_STD_BUFSIZE - (2 + 16));
+						 ACE_STD_BUFSIZE - (2 + 16),
+						 PCI_DMA_FROMDEVICE);
 				dev_kfree_skb(skb);
 			}
 		}
@@ -637,7 +648,8 @@
 					ap->rx_mini_ring[i].size = 0;
 					ap->skb->rx_mini_skbuff[i].skb = NULL;
 					pci_unmap_single(ap->pdev, mapping,
-							 ACE_MINI_BUFSIZE - (2 + 16));
+							 ACE_MINI_BUFSIZE - (2 + 16),
+							 PCI_DMA_FROMDEVICE);
 					dev_kfree_skb(skb);
 				}
 			}
@@ -652,7 +664,8 @@
 				ap->rx_jumbo_ring[i].size = 0;
 				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
 				pci_unmap_single(ap->pdev, mapping,
-						 ACE_JUMBO_BUFSIZE - (2 + 16));
+						 ACE_JUMBO_BUFSIZE - (2 + 16),
+						 PCI_DMA_FROMDEVICE);
 				dev_kfree_skb(skb);
 			}
 		}
@@ -668,8 +681,8 @@
 			kfree(ap->skb);
 		if (root_dev->irq)
 			free_irq(root_dev->irq, root_dev);
-		iounmap(regs);
 		unregister_netdev(root_dev);
+		iounmap(regs);
 		kfree(root_dev);
 
 		root_dev = next;
@@ -677,20 +690,6 @@
 }
 
 
-#if (LINUX_VERSION_CODE < 0x02032b)
-int init_module(void)
-{
-	return ace_module_init();
-}
-
-
-void cleanup_module(void)
-{
-	ace_module_cleanup();
-}
-#endif
-#endif
-
 int __init ace_module_init(void)
 {
 	int cards;
@@ -706,7 +705,22 @@
 }
 
 
-#if (LINUX_VERSION_CODE >= 0x02032b)
+#if (LINUX_VERSION_CODE < 0x02032a)
+int init_module(void)
+{
+	return ace_module_init();
+}
+
+
+void cleanup_module(void)
+{
+	ace_module_cleanup();
+}
+#endif
+#endif
+
+
+#if (LINUX_VERSION_CODE >= 0x02032a)
 module_init(ace_module_init);
 module_exit(ace_module_cleanup);
 #endif
@@ -726,6 +740,7 @@
 		pci_free_consistent(ap->pdev, size,
 				    ap->rx_std_ring,
 				    ap->rx_ring_base_dma);
+		ap->rx_std_ring = NULL;
 		ap->rx_jumbo_ring = NULL;
 		ap->rx_mini_ring = NULL;
 		ap->rx_return_ring = NULL;
@@ -759,7 +774,7 @@
 {
 	struct ace_private *ap = dev->priv;
 	int size;
- 
+
 	size = (sizeof(struct rx_desc) *
 		(RX_STD_RING_ENTRIES +
 		 RX_JUMBO_RING_ENTRIES +
@@ -843,7 +858,7 @@
 	 * address the `Firmware not running' problem subsequent
 	 * to any crashes involving the NIC
 	 */
-	writel(HW_RESET, &regs->HostCtrl);
+	writel(HW_RESET | (HW_RESET << 24), &regs->HostCtrl);
 	wmb();
 
 	/*
@@ -854,7 +869,7 @@
 	 * This will most likely need BYTE_SWAP once we switch
 	 * to using __raw_writel()
 	 */
-	writel(((WORD_SWAP | CLR_INT) |
+	writel((WORD_SWAP | CLR_INT |
 		((WORD_SWAP | CLR_INT) << 24)),
 	       &regs->HostCtrl);
 #else
@@ -888,7 +903,7 @@
 		writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
 		/*
 		 * The SRAM bank size does _not_ indicate the amount
-		 * of memory on the card, it controls the bank size!
+		 * of memory on the card, it controls the _bank_ size!
 		 * Ie. a 1MB AceNIC will have two banks of 512KB.
 		 */
 		writel(SRAM_BANK_512K, &regs->LocalCtrl);
@@ -909,13 +924,14 @@
 	 * value a second time works as well. This is what caused the
 	 * `Firmware not running' problem on the Tigon II.
 	 */
-#ifdef __LITTLE_ENDIAN
-	writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL |
-	       ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
+#ifdef __BIG_ENDIAN
+	writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL | ACE_BYTE_SWAP_BD |
+	       ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
 #else
-	writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL | ACE_BYTE_SWAP |
-	       ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
+	writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL |
+	       ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
 #endif
+	mb();
 
 	mac1 = 0;
 	for(i = 0; i < 4; i++) {
@@ -1007,6 +1023,21 @@
 			}
 		}
 	}
+#ifdef __sparc__
+	/* On this platform, we know what the best dma settings
+	 * are.  We use 64-byte maximum bursts, because if we
+	 * burst larger than the cache line size (or even cross
+	 * a 64byte boundry in a single burst) the UltraSparc
+	 * PCI controller will disconnect at 64-byte multiples.
+	 *
+	 * Read-multiple will be properly enabled above, and when
+	 * set will give the PCI controller proper hints about
+	 * prefetching.
+	 */
+	tmp = (tmp & ~(0xfc));
+	tmp |= DMA_READ_MAX_64;
+	tmp |= DMA_WRITE_MAX_64;
+#endif
 	writel(tmp, &regs->PciState);
 
 	/*
@@ -1301,8 +1332,10 @@
 	 */
 	myjif = jiffies + 3 * HZ;
 	while (time_before(jiffies, myjif) && !ap->fw_running);
+
 	if (!ap->fw_running) {
 		printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name);
+
 		ace_dump_trace(ap);
 		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
 
@@ -1344,6 +1377,8 @@
 	}
 	return 0;
  init_error:
+	iounmap(ap->regs);
+	unregister_netdev(dev);
 	if (ap->skb) {
 		kfree(ap->skb);
 		ap->skb = NULL;
@@ -1460,7 +1495,8 @@
 		 */
 		skb_reserve(skb, 2 + 16);
 		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_STD_BUFSIZE - (2 + 16));
+					 ACE_STD_BUFSIZE - (2 + 16),
+					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_std_skbuff[idx].skb = skb;
 		ap->skb->rx_std_skbuff[idx].mapping = mapping;
 
@@ -1521,7 +1557,8 @@
 		 */
 		skb_reserve(skb, 2 + 16);
 		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_MINI_BUFSIZE - (2 + 16));
+					 ACE_MINI_BUFSIZE - (2 + 16),
+					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_mini_skbuff[idx].skb = skb;
 		ap->skb->rx_mini_skbuff[idx].mapping = mapping;
 
@@ -1579,7 +1616,8 @@
 		 */
 		skb_reserve(skb, 2 + 16);
 		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_JUMBO_BUFSIZE - (2 + 16));
+					 ACE_JUMBO_BUFSIZE - (2 + 16),
+					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
 		ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
 
@@ -1634,6 +1672,7 @@
 			printk(KERN_INFO "%s: Firmware up and running\n",
 			       dev->name);
 			ap->fw_running = 1;
+			wmb();
 			break;
 		case E_STATS_UPDATED:
 			break;
@@ -1756,8 +1795,7 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
-		pci_unmap_single(ap->pdev, rip->mapping, mapsize);
-		rxdesc->size = 0;
+		pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE);
 		skb_put(skb, retdesc->size);
 #if 0
 		/* unncessary */
@@ -1864,7 +1902,7 @@
 
 			ap->stats.tx_packets++;
 			ap->stats.tx_bytes += skb->len;
-			pci_unmap_single(ap->pdev, mapping, skb->len);
+			pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb_irq(skb);
 
 			ap->skb->tx_skbuff[idx].skb = NULL;
@@ -2105,7 +2143,7 @@
 			writel(0, &ap->tx_ring[i].addr.addrhi);
 			writel(0, &ap->tx_ring[i].addr.addrlo);
 			writel(0, &ap->tx_ring[i].flagsize);
-			pci_unmap_single(ap->pdev, mapping, skb->len);
+			pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
 			ap->skb->tx_skbuff[i].skb = NULL;
 		}
@@ -2155,7 +2193,7 @@
 
 	ap->skb->tx_skbuff[idx].skb = skb;
 	ap->skb->tx_skbuff[idx].mapping =
-		pci_map_single(ap->pdev, skb->data, skb->len);
+		pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
 	addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping;
 #if (BITS_PER_LONG == 64)
 	writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.3.46/linux/drivers/net/acenic.h	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/acenic.h	Thu Feb 17 09:18:47 2000
@@ -245,10 +245,10 @@
  * Mode status
  */
 
-#define ACE_BYTE_SWAP_DATA	0x10
+#define ACE_BYTE_SWAP_BD	0x02
+#define ACE_WORD_SWAP_BD	0x04		/* not actually used */
 #define ACE_WARN		0x08
-#define ACE_WORD_SWAP		0x04
-#define ACE_BYTE_SWAP		0x02
+#define ACE_BYTE_SWAP_DMA	0x10
 #define ACE_NO_JUMBO_FRAG	0x200
 #define ACE_FATAL		0x40000000
 
@@ -298,7 +298,7 @@
 #define EVT_RING_SIZE	(EVT_RING_ENTRIES * sizeof(struct event))
 
 struct event {
-#ifdef __LITTLE_ENDIAN
+#ifdef __LITTLE_ENDIAN_BITFIELD
 	u32	idx:12;
 	u32	code:12;
 	u32	evt:8;
@@ -344,7 +344,7 @@
 #define CMD_RING_ENTRIES	64
 
 struct cmd {
-#ifdef __LITTLE_ENDIAN
+#ifdef __LITTLE_ENDIAN_BITFIELD
 	u32	idx:12;
 	u32	code:12;
 	u32	evt:8;
@@ -594,7 +594,8 @@
 {
 	struct ace_skb		*skb;
 	struct ace_regs		*regs;		/* register base */
-	int			version, fw_running, fw_up, link;
+	volatile int		fw_running;
+	int			version, fw_up, link;
 	int			promisc, mcast_all;
 	/*
 	 * The send ring is located in the shared memory window
@@ -648,17 +649,19 @@
 
 static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
 {
+	unsigned long baddr = (unsigned long) addr;
 #if (BITS_PER_LONG == 64)
-	aa->addrlo = addr & 0xffffffff;
-	aa->addrhi = addr >> 32;
+	aa->addrlo = baddr & 0xffffffff;
+	aa->addrhi = baddr >> 32;
 #else
-    /* Don't bother setting zero every time */
-	aa->addrlo = addr;
+	/* Don't bother setting zero every time */
+	aa->addrlo = baddr;
 #endif
 	mb();
 }
 
 
+#if 0
 static inline void *get_aceaddr(aceaddr *aa)
 {
 	unsigned long addr;
@@ -668,21 +671,9 @@
 #else
 	addr = aa->addrlo;
 #endif
-	return bus_to_virt(addr);
-}
-
-
-static inline void *get_aceaddr_bus(aceaddr *aa)
-{
-	unsigned long addr;
-	mb();
-#if (BITS_PER_LONG == 64)
-	addr = (u64)aa->addrhi << 32 | aa->addrlo;
-#else
-	addr = aa->addrlo;
-#endif
 	return (void *)addr;
 }
+#endif
 
 
 static inline void ace_set_txprd(struct ace_regs *regs,
diff -u --recursive --new-file v2.3.46/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c
--- v2.3.46/linux/drivers/net/arcnet/arcnet.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/arcnet/arcnet.c	Thu Feb 17 09:18:47 2000
@@ -723,7 +723,7 @@
 	 * RESET flag was enabled - if device is not running, we must clear it right
 	 * away (but nothing else).
 	 */
-	if (!test_bit(LINK_STATE_START, &dev->state)) {
+	if (!netif_running(dev)) {
 		if (ASTATUS() & RESETflag)
 			ACOMMAND(CFLAGScmd | RESETclear);
 		AINTMASK(0);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.3.46/linux/drivers/net/cs89x0.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/cs89x0.c	Thu Feb 17 09:18:47 2000
@@ -941,7 +941,7 @@
 static int set_mac_address(struct net_device *dev, void *addr)
 {
 	int i;
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		return -EBUSY;
 	printk("%s: Setting MAC address to ", dev->name);
 	for (i = 0; i < 6; i++)
diff -u --recursive --new-file v2.3.46/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.3.46/linux/drivers/net/de4x5.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/de4x5.c	Fri Feb 18 15:07:20 2000
@@ -1561,15 +1561,14 @@
 	return -1;
 
     /* Transmit descriptor ring full or stale skb */
-    if (test_bit(LINK_STATE_XOFF, &dev->state) ||
-	(u_long) lp->tx_skb[lp->tx_new] > 1) {
+    if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) {
 	if (lp->interrupt) {
 	    de4x5_putb_cache(dev, skb);          /* Requeue the buffer */
 	} else {
 	    de4x5_put_cache(dev, skb);
 	}
 	if (de4x5_debug & DEBUG_TX) {
-	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), test_bit(LINK_STATE_XOFF, &dev->state), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO");
+	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), netif_queue_stopped(dev), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO");
 	}
     } else if (skb->len > 0) {
 	/* If we already have stuff queued locally, use that first */
@@ -1578,7 +1577,8 @@
 	    skb = de4x5_get_cache(dev);
 	}
 
-	while (skb && !test_bit(LINK_STATE_XOFF, &dev->state) && (u_long) lp->tx_skb[lp->tx_new] <= 1) {
+	while (skb && !netif_queue_stopped(dev) &&
+	       (u_long) lp->tx_skb[lp->tx_new] <= 1) {
 	    spin_lock_irqsave(&lp->lock, flags);
 	    netif_stop_queue(dev);
 	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
@@ -1666,7 +1666,7 @@
 
     /* Load the TX ring with any locally stored packets */
     if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
-	while (lp->cache.skb && !test_bit(LINK_STATE_XOFF, &dev->state) && lp->tx_enable) {
+	while (lp->cache.skb && !netif_queue_stopped(dev) && lp->tx_enable) {
 	    de4x5_queue_pkt(de4x5_get_cache(dev), dev);
 	}
 	lp->cache.lock = 0;
@@ -1759,7 +1759,8 @@
 de4x5_free_tx_buff(struct de4x5_private *lp, int entry)
 {
     pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf),
-		     le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1);
+		     le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1,
+		     PCI_DMA_TODEVICE);
     if ((u_long) lp->tx_skb[entry] > 1)
 	dev_kfree_skb_irq(lp->tx_skb[entry]);
     lp->tx_skb[entry] = NULL;
@@ -1810,7 +1811,7 @@
     }
 
     /* Any resources available? */
-    if (TX_BUFFS_AVAIL && test_bit(LINK_STATE_XOFF, &dev->state)) {
+    if (TX_BUFFS_AVAIL && netif_queue_stopped(dev)) {
 	if (lp->interrupt)
 	    netif_wake_queue(dev);
 	else
@@ -1980,7 +1981,7 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1);
-    dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1);
+    dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1, PCI_DMA_TODEVICE);
 
     lp->tx_ring[lp->tx_new].buf = cpu_to_le32(buf_dma);
     lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
@@ -5606,18 +5607,19 @@
     case DE4X5_SET_HWADDR:           /* Set the hardware address */
 	if (!capable(CAP_NET_ADMIN)) return -EPERM;
 	if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT;
+	if (netif_queue_stopped(dev))
+		return -EBUSY;
+	netif_stop_queue(dev);
 	for (i=0; i<ETH_ALEN; i++) {
 	    dev->dev_addr[i] = tmp.addr[i];
 	}
 	build_setup_frame(dev, PHYS_ADDR_ONLY);
 	/* Set up the descriptor and give ownership to the card */
-	while (test_and_set_bit(LINK_STATE_XOFF, &dev->state) != 0)
-	    barrier();
 	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 		                                       SETUP_FRAME_LEN, (struct sk_buff *)1);
 	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
-	netif_start_queue(dev);                      /* Unlock the TX ring */
+	netif_wake_queue(dev);                      /* Unlock the TX ring */
 	break;
 
     case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
@@ -5769,7 +5771,7 @@
 	}
 	
 	tmp.addr[j++] = lp->txRingSize;
-	tmp.addr[j++] = test_bit(LINK_STATE_XOFF, &dev->state);
+	tmp.addr[j++] = netif_queue_stopped(dev);
 	
 	ioc->len = j;
 	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.3.46/linux/drivers/net/de600.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/de600.c	Thu Feb 17 09:18:47 2000
@@ -368,7 +368,7 @@
 	de600_put_command(0);
 	select_prn();
 
-	if (test_bit(LINK_STATE_START, &dev->state)) { /* perhaps not needed? */
+	if (netif_running(dev)) { /* perhaps not needed? */
 		free_irq(DE600_IRQ, dev);
 		MOD_DEC_USE_COUNT;
 	}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.3.46/linux/drivers/net/depca.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/depca.c	Thu Feb 17 09:18:47 2000
@@ -905,7 +905,8 @@
 	if (csr0 & TINT)	/* Tx interrupt (packet sent) */
 		depca_tx (dev);
 
-	if ((TX_BUFFS_AVAIL >= 0) && (test_bit (LINK_STATE_XOFF, &dev->flags))) {	/* any resources available? */
+	/* Any resources available? */
+	if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
 		netif_wake_queue (dev);
 
 		/* Unmask the DEPCA board interrupts and turn off the LED */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.3.46/linux/drivers/net/eepro.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/eepro.c	Thu Feb 17 09:18:47 2000
@@ -1409,7 +1409,7 @@
 		lp->tx_last = last;
 		lp->tx_end = end;
 
-		if (test_bit(LINK_STATE_XOFF, &dev->flags))
+		if (netif_queue_stopped(dev))
 			netif_wake_queue(dev);
 		
 		/* Enable RX and TX interrupts */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.46/linux/drivers/net/eepro100.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/eepro100.c	Sun Feb 20 20:14:55 2000
@@ -188,10 +188,8 @@
 
 /* 'options' is used to pass a transceiver override or full-duplex flag
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-#if MODULE_SETUP_FIXED
 static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-#endif
 static int debug = -1;			/* The debug level */
 
 /* A few values that may be tweaked. */
@@ -214,7 +212,8 @@
 #error You must compile this driver with "-O".
 #endif
 
-#include <linux/version.h>
+
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -237,12 +236,8 @@
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
 MODULE_PARM(debug, "i");
-
-#if MODULE_OPTIONS_FIXED
 MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-#endif
-
 MODULE_PARM(congenb, "i");
 MODULE_PARM(txfifo, "i");
 MODULE_PARM(rxfifo, "i");
@@ -257,6 +252,21 @@
 
 #define RUN_AT(x) (jiffies + (x))
 
+/* ACPI power states don't universally work (yet) */
+#ifndef CONFIG_EEPRO100_PM
+#undef pci_set_power_state
+#define pci_set_power_state null_set_power_state
+static inline int null_set_power_state(struct pci_dev *dev, int state)
+{
+	return 0;
+}
+#endif /* CONFIG_EEPRO100_PM */
+
+
+/* compile-time switch to en/disable slow PIO */
+#undef USE_IO
+
+
 int speedo_debug = 1;
 
 
@@ -522,6 +532,7 @@
 	u16 eeprom[0x100];
 	int acpi_idle_state = 0, pm, irq;
 	unsigned long ioaddr;
+	static int card_idx = -1;
 
 	static int did_version = 0;			/* Already printed version info. */
 
@@ -531,6 +542,8 @@
 	ioaddr = pci_resource_start (pdev, 1);
 #endif
 	irq = pdev->irq;
+
+	card_idx++;
 	
 	if (!request_region (pci_resource_start (pdev, 1),
 			     pci_resource_len (pdev, 1),
@@ -578,10 +591,8 @@
 
 	if (dev->mem_start > 0)
 		option = dev->mem_start;
-#if MODULE_SETUP_FIXED
 	else if (card_idx >= 0  &&  options[card_idx] >= 0)
 		option = options[card_idx];
-#endif
 	else
 		option = 0;
 
@@ -735,12 +746,10 @@
 	
 	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 
-#if MODULE_SETUP_FIXED
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
 			sp->full_duplex = full_duplex[card_idx];
 	}
-#endif
 
 	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
@@ -773,8 +782,8 @@
 err_out_iounmap:
 #ifndef USE_IO
 	iounmap ((void *)ioaddr);
-#endif
 err_out_free_mmio_region:
+#endif
 	release_mem_region (pci_resource_start (pdev, 0),
 			    pci_resource_len (pdev, 0));
 err_out_free_pio_region:
@@ -903,7 +912,6 @@
 	/* Fire up the hardware. */
 	speedo_resume(dev);
 
-	clear_bit(LINK_STATE_RXSEM, &dev->state);
 	netif_start_queue(dev);
 
 	/* Setup the chip and configure the multicast list. */
@@ -1093,7 +1101,7 @@
 		rxf = (struct RxFD *)skb->tail;
 		sp->rx_ringp[i] = rxf;
 		sp->rx_ring_dma[i] =
-			pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD));
+			pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 		skb_reserve(skb, sizeof(struct RxFD));
 		if (last_rxf)
 			last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]);
@@ -1194,7 +1202,7 @@
 		sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
 		sp->tx_ring[entry].tx_buf_addr0 =
 			cpu_to_le32(pci_map_single(sp->pdev, skb->data,
-						   skb->len));
+						   skb->len, PCI_DMA_TODEVICE));
 		sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
 		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
 		   than half full.  Argument against: we should be receiving packets
@@ -1289,19 +1297,18 @@
 				/* Free the original skb. */
 				if (sp->tx_skbuff[entry]) {
 					sp->stats.tx_packets++;	/* Count only user packets. */
-#if LINUX_VERSION_CODE > 0x20127
 					sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
-#endif
 					pci_unmap_single(sp->pdev,
 							 le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
-							 sp->tx_skbuff[entry]->len);
+							 sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
 					dev_kfree_skb_irq(sp->tx_skbuff[entry]);
 					sp->tx_skbuff[entry] = 0;
 				} else if ((status & 0x70000) == CmdNOp) {
 					if (sp->mc_setup_busy)
 						pci_unmap_single(sp->pdev,
 								 sp->mc_setup_dma,
-								 sp->mc_setup_frm_len);
+								 sp->mc_setup_frm_len,
+								 PCI_DMA_TODEVICE);
 					sp->mc_setup_busy = 0;
 				}
 				dirty_tx++;
@@ -1386,7 +1393,7 @@
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
-						    PKT_BUF_SZ + sizeof(struct RxFD));
+						    PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 #if 1 || USE_IP_CSUM
 				/* Packet is in one chunk -- we can copy + cksum. */
 				eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
@@ -1408,14 +1415,12 @@
 				temp = skb_put(skb, pkt_len);
 				sp->rx_ringp[entry] = NULL;
 				pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
-						 PKT_BUF_SZ + sizeof(struct RxFD));
+						 PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			sp->stats.rx_packets++;
-#if LINUX_VERSION_CODE > 0x20127
 			sp->stats.rx_bytes += pkt_len;
-#endif
 		}
 		entry = (++sp->cur_rx) % RX_RING_SIZE;
 	}
@@ -1436,7 +1441,7 @@
 			rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
 			sp->rx_ring_dma[entry] =
 				pci_map_single(sp->pdev, rxf, PKT_BUF_SZ
-					       + sizeof(struct RxFD));
+					       + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 			skb->dev = dev;
 			skb_reserve(skb, sizeof(struct RxFD));
 			rxf->rx_buf_addr = 0xffffffff;
@@ -1485,10 +1490,7 @@
 		if (skb) {
 			pci_unmap_single(sp->pdev,
 					 sp->rx_ring_dma[i],
-					 PKT_BUF_SZ + sizeof(struct RxFD));
-#if LINUX_VERSION_CODE < 0x20100
-			skb->free = 1;
-#endif
+					 PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(skb);
 		}
 	}
@@ -1501,7 +1503,7 @@
 		if (skb) {
 			pci_unmap_single(sp->pdev,
 							 le32_to_cpu(sp->tx_ring[i].tx_buf_addr0),
-							 skb->len);
+							 skb->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
 		}
 	}
@@ -1554,7 +1556,7 @@
 		sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats->rx_overrun_errs);
 		sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs);
 		sp->lstats->done_marker = 0x0000;
-		if (test_bit(LINK_STATE_START, &dev->state)) {
+		if (netif_running(dev)) {
 			wait_for_cmd_done(ioaddr + SCBCmd);
 			outw(CUDumpStats, ioaddr + SCBCmd);
 		}
@@ -1746,7 +1748,7 @@
 		/* Change the command to a NoOp, pointing to the CmdMulti command. */
 		sp->tx_skbuff[entry] = 0;
 		sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
-		sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len);
+		sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len, PCI_DMA_TODEVICE);
 		sp->tx_ring[entry].link = cpu_to_le32(sp->mc_setup_dma);
 
 		/* Set the link in the setup frame. */
@@ -1773,7 +1775,7 @@
 	struct net_device *dev = pdev->driver_data;
 	long ioaddr = dev->base_addr;
 
-	netif_stop_queue (dev);
+	netif_device_detach(dev);
 	outl(PortPartialReset, ioaddr + SCBPort);
 	
 	/* XXX call pci_set_power_state ()? */
@@ -1785,6 +1787,7 @@
 	struct net_device *dev = pdev->driver_data;
 	struct speedo_private *np = (struct speedo_private *)dev->priv;
 
+	netif_device_attach(dev);
 	speedo_resume(dev);
 	np->rx_mode = -1;
 	np->flow_ctrl = np->partner = 0;
@@ -1810,6 +1813,10 @@
 
 	pci_set_power_state (pdev, sp->acpi_pwr);
 
+	pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+				  + sizeof(struct speedo_stats),
+			    sp->tx_ring, sp->tx_ring_dma);
+
 	kfree (dev);
 }
 
@@ -1846,6 +1853,7 @@
 	cards_found = pci_register_driver (&eepro100_driver);
 	if (cards_found <= 0) {
 		printk(KERN_INFO PFX "No cards found, driver not installed.\n");
+		pci_unregister_driver (&eepro100_driver);
 		return -ENODEV;
 	}
 
diff -u --recursive --new-file v2.3.46/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.3.46/linux/drivers/net/eexpress.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/eexpress.c	Thu Feb 17 09:18:47 2000
@@ -543,7 +543,7 @@
 				else
 				{
 					unsigned short txstatus = eexp_hw_lasttxstat(dev);
-					if (test_bit(LINK_STATE_XOFF, &dev->state) && !txstatus)
+					if (netif_queue_stopped(dev) && !txstatus)
 					{
 						printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
 						       dev->name,status,txstatus);
@@ -1204,7 +1204,7 @@
 	unsigned short tx_block = lp->tx_reap;
 	unsigned short status;
 
-	if (!test_bit(LINK_STATE_XOFF, &dev->state) && lp->tx_head==lp->tx_reap)
+	if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
 		return 0x0000;
 
 	do
diff -u --recursive --new-file v2.3.46/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.3.46/linux/drivers/net/epic100.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/epic100.c	Sun Feb 20 09:06:14 2000
@@ -775,7 +775,7 @@
 #endif
 
 			if (ep->tx_full &&
-			    test_bit(LINK_STATE_XOFF, &dev->flags) &&
+			    netif_queue_stopped(dev) &&
 			    dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) {
 				/* The ring is no longer full, clear tbusy. */
 				ep->tx_full = 0;
@@ -970,7 +970,7 @@
 	struct epic_private *ep = (struct epic_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (test_bit(LINK_STATE_START, &dev->state)) {
+	if (netif_running(dev)) {
 		/* Update the error counts. */
 		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
 		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
@@ -1058,12 +1058,12 @@
 		data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		if (! test_bit(LINK_STATE_START, &dev->state)) {
+		if (! netif_running(dev)) {
 			outl(0x0200, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 		}
 		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-		if (! test_bit(LINK_STATE_START, &dev->state)) {
+		if (! netif_running(dev)) {
 #ifdef notdef
 			outl(0x0008, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
@@ -1073,12 +1073,12 @@
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		if (!suser())
 			return -EPERM;
-		if (! test_bit(LINK_STATE_START, &dev->state)) {
+		if (! netif_running(dev)) {
 			outl(0x0200, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 		}
 		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-		if (! test_bit(LINK_STATE_START, &dev->state)) {
+		if (! netif_running(dev)) {
 #ifdef notdef
 			outl(0x0008, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
@@ -1285,6 +1285,7 @@
 	if (pci_register_driver (&epic100_driver) > 0)
 		return 0;
 	
+	pci_unregister_driver (&epic100_driver);
 	return -ENODEV;
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c
--- v2.3.46/linux/drivers/net/hamradio/6pack.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/hamradio/6pack.c	Thu Feb 17 09:18:47 2000
@@ -283,7 +283,8 @@
 	struct sixpack *sp = (struct sixpack *) tty->disc_data;
 
 	/* First make sure we're connected. */
-	if (!sp || sp->magic != SIXPACK_MAGIC || !test_bit(LINK_STATE_START, &sp->dev->state)) {
+	if (!sp || sp->magic != SIXPACK_MAGIC ||
+	    !netif_running(sp->dev)) {
 		return;
 	}
 
@@ -477,7 +478,8 @@
 
 	struct sixpack *sp = (struct sixpack *) tty->disc_data;
 
-	if (!sp || sp->magic != SIXPACK_MAGIC || !test_bit(LINK_STATE_START, &sp->dev->state) || !count)
+	if (!sp || sp->magic != SIXPACK_MAGIC ||
+	    !netif_running(sp->dev) || !count)
 		return;
 
 	save_flags(flags);
@@ -750,7 +752,7 @@
 				 * VSV = if dev->start==0, then device
 				 * unregistered while close proc.
 				 */ 
-				if (test_bit(LINK_STATE_START, &sixpack_ctrls[i]->dev.state))
+				if (netif_running(sixpack_ctrls[i]->dev))
 					unregister_netdev(&(sixpack_ctrls[i]->dev));
 
 				kfree(sixpack_ctrls[i]);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c
--- v2.3.46/linux/drivers/net/hamradio/baycom_epp.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/hamradio/baycom_epp.c	Thu Feb 17 09:18:47 2000
@@ -1275,7 +1275,7 @@
 		break;
 
 	case HDLCDRVCTL_SETMODEMPAR:
-		if ((!suser()) || test_bit(LINK_STATE_START, &dev->state))
+		if ((!suser()) || netif_running(dev))
 			return -EACCES;
 		dev->base_addr = hi.data.mp.iobase;
 		dev->irq = /*hi.data.mp.irq*/0;
@@ -1314,7 +1314,7 @@
 		break;
 
 	case HDLCDRVCTL_SETMODE:
-		if (!suser() || test_bit(LINK_STATE_START, &dev->state))
+		if (!suser() || netif_running(dev))
 			return -EACCES;
 		hi.data.modename[sizeof(hi.data.modename)-1] = '\0';
 		return baycom_setmode(bc, hi.data.modename);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c
--- v2.3.46/linux/drivers/net/hamradio/baycom_par.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/hamradio/baycom_par.c	Thu Feb 17 09:18:47 2000
@@ -445,7 +445,7 @@
 		return 0;
 
 	case HDLCDRVCTL_SETMODE:
-		if (test_bit(LINK_STATE_START, &dev->state) || !suser())
+		if (netif_running(dev) || !suser())
 			return -EACCES;
 		hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
 		return baycom_setmode(bc, hi->data.modename);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c
--- v2.3.46/linux/drivers/net/hamradio/baycom_ser_fdx.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/hamradio/baycom_ser_fdx.c	Thu Feb 17 09:18:47 2000
@@ -555,7 +555,7 @@
 		return 0;
 
 	case HDLCDRVCTL_SETMODE:
-		if (test_bit(LINK_STATE_START, &dev->state) || !suser())
+		if (netif_running(dev) || !suser())
 			return -EACCES;
 		hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
 		return baycom_setmode(bc, hi->data.modename);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c
--- v2.3.46/linux/drivers/net/hamradio/baycom_ser_hdx.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/hamradio/baycom_ser_hdx.c	Thu Feb 17 09:18:47 2000
@@ -598,7 +598,7 @@
 		return 0;
 
 	case HDLCDRVCTL_SETMODE:
-		if (test_bit(LINK_STATE_START, &dev->state) || !suser())
+		if (netif_running(dev) || !suser())
 			return -EACCES;
 		hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
 		return baycom_setmode(bc, hi->data.modename);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- v2.3.46/linux/drivers/net/hamradio/bpqether.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/hamradio/bpqether.c	Thu Feb 17 09:18:47 2000
@@ -222,7 +222,7 @@
 
 	dev = bpq_get_ax25_dev(dev);
 
-	if (dev == NULL || !test_bit(LINK_STATE_START, &dev->state)) {
+	if (dev == NULL || !netif_running(dev)) {
 		kfree_skb(skb);
 		return 0;
 	}
@@ -275,8 +275,7 @@
 	 * Just to be *really* sure not to send anything if the interface
 	 * is down, the ethernet device may have gone.
 	 */
-	if (!test_bit(LINK_STATE_START, &dev->state))
-	{
+	if (!netif_running(dev)) {
 		bpq_check_devices(dev);
 		kfree_skb(skb);
 		return -ENODEV;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.3.46/linux/drivers/net/hamradio/dmascc.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/hamradio/dmascc.c	Thu Feb 17 09:18:47 2000
@@ -784,7 +784,7 @@
   case SIOCSSCCPARAM:
     if (!capable(CAP_NET_ADMIN)) 
     	return -EPERM;
-    if (test_bit(LINK_STATE_START, &dev->state)) 
+    if (netif_running(dev))
     	return -EAGAIN;
     if(copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param)))
     	return -EFAULT;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c
--- v2.3.46/linux/drivers/net/hamradio/hdlcdrv.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/hamradio/hdlcdrv.c	Thu Feb 17 09:18:47 2000
@@ -656,7 +656,7 @@
 		break;
 
 	case HDLCDRVCTL_SETMODEMPAR:
-		if ((!suser()) || test_bit(LINK_STATE_START, &dev->state))
+		if ((!suser()) || netif_running(dev))
 			return -EACCES;
 		dev->base_addr = bi.data.mp.iobase;
 		dev->irq = bi.data.mp.irq;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c
--- v2.3.46/linux/drivers/net/hamradio/soundmodem/sm.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/hamradio/soundmodem/sm.c	Thu Feb 17 09:18:47 2000
@@ -509,7 +509,7 @@
 		return 0;
 
 	case HDLCDRVCTL_SETMODE:
-		if (test_bit(LINK_STATE_START, &dev->state) || !suser())
+		if (netif_running(dev) || !suser())
 			return -EACCES;
 		hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
 		return sethw(dev, sm, hi->data.modename);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c
--- v2.3.46/linux/drivers/net/hamradio/yam.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/hamradio/yam.c	Thu Feb 17 09:18:47 2000
@@ -649,7 +649,7 @@
 
 	for (i = 0; i < NR_PORTS; i++) {
 		struct net_device *dev = &yam_ports[i].dev;
-		if (test_bit(LINK_STATE_START, &dev->state))
+		if (netif_running(dev))
 			yam_arbitrate(dev);
 	}
 	yam_timer.expires = jiffies + HZ / 100;
@@ -748,7 +748,7 @@
 		yp = &yam_ports[i];
 		dev = &yp->dev;
 
-		if (!test_bit(LINK_STATE_START, &dev->state))
+		if (!netif_running(dev))
 			continue;
 
 		while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
@@ -794,7 +794,7 @@
 		if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0)
 			continue;
 		len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name);
-		len += sprintf(buffer + len, "  Up       %d\n", test_bit(LINK_STATE_START, &yam_ports[i].dev.state));
+		len += sprintf(buffer + len, "  Up       %d\n", netif_running(&yam_ports[i].dev));
 		len += sprintf(buffer + len, "  Speed    %u\n", yam_ports[i].bitrate);
 		len += sprintf(buffer + len, "  IoBase   0x%x\n", yam_ports[i].iobase);
 		len += sprintf(buffer + len, "  BaudRate %u\n", yam_ports[i].baudrate);
@@ -974,7 +974,7 @@
 		return -EINVAL;			/* unused */
 
 	case SIOCYAMSMCS:
-		if (test_bit(LINK_STATE_START, &dev->state))
+		if (netif_running(dev))
 			return -EINVAL;		/* Cannot change this parameter when up */
 		ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC);
 		ym->bitrate = 9600;
@@ -990,13 +990,13 @@
 		if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
 			 return -EFAULT;
 
-		if ((yi.cfg.mask & YAM_IOBASE) && test_bit(LINK_STATE_START, &dev->state))
+		if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev))
 			return -EINVAL;		/* Cannot change this parameter when up */
-		if ((yi.cfg.mask & YAM_IRQ) && test_bit(LINK_STATE_START, &dev->state))
+		if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev))
 			return -EINVAL;		/* Cannot change this parameter when up */
-		if ((yi.cfg.mask & YAM_BITRATE) && test_bit(LINK_STATE_START, &dev->state))
+		if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev))
 			return -EINVAL;		/* Cannot change this parameter when up */
-		if ((yi.cfg.mask & YAM_BAUDRATE) && test_bit(LINK_STATE_START, &dev->state))
+		if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev))
 			return -EINVAL;		/* Cannot change this parameter when up */
 
 		if (yi.cfg.mask & YAM_IOBASE) {
@@ -1210,7 +1210,7 @@
 		struct net_device *dev = &yam_ports[i].dev;
 		if (!dev->priv)
 			continue;
-		if (test_bit(LINK_STATE_START, &dev->state))
+		if (netif_running(dev))
 			yam_close(dev);
 		unregister_netdev(dev);
 	}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.3.46/linux/drivers/net/lance.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/lance.c	Thu Feb 17 09:18:47 2000
@@ -1043,7 +1043,7 @@
 #endif
 
 			if (lp->tx_full &&
-			    (test_bit(LINK_STATE_XOFF, &dev->flags)) &&
+			    (netif_queue_stopped(dev)) &&
 			    dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
 				/* The ring is no longer full, clear tbusy. */
 				lp->tx_full = 0;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.3.46/linux/drivers/net/myri_sbus.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/myri_sbus.c	Fri Feb 18 15:07:20 2000
@@ -256,7 +256,7 @@
 			u32 dma_addr;
 
 			dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
-			sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE);
+			sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
 			dev_kfree_skb(mp->rx_skbs[i]);
 			mp->rx_skbs[i] = NULL;
 		}
@@ -272,7 +272,7 @@
 			u32 dma_addr;
 
 			dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
-			sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3);
+			sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);
 			dev_kfree_skb(mp->tx_skbs[i]);
 			mp->tx_skbs[i] = NULL;
 		}
@@ -301,7 +301,7 @@
 		skb->dev = dev;
 		skb_put(skb, RX_ALLOC_SIZE);
 
-		dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE);
+		dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
 		sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr);
 		sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len);
 		sbus_writel(i, &rxd[i].ctx);
@@ -363,7 +363,7 @@
 
 		DTX(("SKB[%d] ", entry));
 		dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);
-		sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len);
+		sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
 		dev_kfree_skb(skb);
 		mp->tx_skbs[entry] = NULL;
 		mp->enet_stats.tx_packets++;
@@ -444,7 +444,7 @@
 		DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
 		sbus_dma_sync_single(mp->myri_sdev,
 				     sbus_readl(&rxd->myri_scatters[0].addr),
-				     RX_ALLOC_SIZE);
+				     RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
 		if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
 			DRX(("ERROR["));
 			mp->enet_stats.rx_errors++;
@@ -481,13 +481,15 @@
 			}
 			sbus_unmap_single(mp->myri_sdev,
 					  sbus_readl(&rxd->myri_scatters[0].addr),
-					  RX_ALLOC_SIZE);
+					  RX_ALLOC_SIZE,
+					  SBUS_DMA_FROMDEVICE);
 			mp->rx_skbs[index] = new_skb;
 			new_skb->dev = dev;
 			skb_put(new_skb, RX_ALLOC_SIZE);
 			dma_addr = sbus_map_single(mp->myri_sdev,
 						   new_skb->data,
-						   RX_ALLOC_SIZE);
+						   RX_ALLOC_SIZE,
+						   SBUS_DMA_FROMDEVICE);
 			sbus_writel(dma_addr, &rxd->myri_scatters[0].addr);
 			sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
 			sbus_writel(index, &rxd->ctx);
@@ -650,7 +652,7 @@
 		sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]);
 	}
 
-	dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len);
+	dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE);
 	sbus_writel(dma_addr, &txd->myri_gathers[0].addr);
 	sbus_writel(len, &txd->myri_gathers[0].len);
 	sbus_writel(1, &txd->num_sg);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.3.46/linux/drivers/net/net_init.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/net_init.c	Thu Feb 17 09:18:47 2000
@@ -153,7 +153,7 @@
 static int eth_mac_addr(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr=p;
-	if(test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		return -EBUSY;
 	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
 	return 0;
@@ -200,7 +200,7 @@
 static int hippi_mac_addr(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr = p;
-	if(test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		return -EBUSY;
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 	return 0;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.3.46/linux/drivers/net/ni52.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/ni52.c	Thu Feb 17 09:18:47 2000
@@ -858,7 +858,7 @@
 #ifndef NO_NOPCOMMANDS
 		if(stat & STAT_CNA)	/* CU went 'not ready' */
 		{
-			if(test_bit(LINK_STATE_START, &dev->state))
+			if(netif_running(dev))
 				printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
 		}
 #endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/3c574_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/3c574_cs.c	Thu Feb 17 09:18:47 2000
@@ -627,8 +627,7 @@
 	case CS_EVENT_CARD_REMOVAL:
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
-			netif_stop_queue (dev);
-			clear_bit(LINK_STATE_START, &dev->state);
+			netif_device_detach(dev);
 			link->release.expires = jiffies + HZ/20;
 			add_timer(&link->release);
 		}
@@ -642,10 +641,9 @@
 		/* Fall through... */
 	case CS_EVENT_RESET_PHYSICAL:
 		if (link->state & DEV_CONFIG) {
-			if (link->open) {
-				netif_stop_queue (dev);
-				clear_bit(LINK_STATE_START, &dev->state);
-			}
+			if (link->open)
+				netif_device_detach(dev);
+
 			CardServices(ReleaseConfiguration, link->handle);
 		}
 		break;
@@ -657,8 +655,7 @@
 			CardServices(RequestConfiguration, link->handle, &link->conf);
 			if (link->open) {
 				tc574_reset(dev);
-				set_bit(LINK_STATE_START, &dev->state);
-				netif_start_queue (dev);
+				netif_device_attach(dev);
 			}
 		}
 		break;
@@ -953,7 +950,7 @@
 	ioaddr_t ioaddr, status;
 	int work_budget = max_interrupt_work;
 
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_device_present(dev))
 		return;
 
 	spin_lock (&lp->lock);
@@ -966,8 +963,7 @@
 	while ((status = inw(ioaddr + EL3_STATUS)) &
 		   (IntLatch | RxComplete | RxEarly | StatsFull)) {
 
-		if (!test_bit(LINK_STATE_START, &dev->state) ||
-			((status & 0xe000) != 0x2000)) {
+		if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) {
 			DEBUG(1, "%s: Interrupt from dead card\n", dev->name);
 			break;
 		}
@@ -1047,7 +1043,7 @@
     u_long flags;
 	u_short /* cable, */ media, partner;
 	
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_device_present(dev))
 		goto reschedule;
 	
     /* Check for pending interrupt with expired latency timer: with
@@ -1118,7 +1114,7 @@
 {
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_device_present(dev))
 		update_stats(dev);
 	return &lp->stats;
 }
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/3c575_cb.c linux/drivers/net/pcmcia/3c575_cb.c
--- v2.3.46/linux/drivers/net/pcmcia/3c575_cb.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/pcmcia/3c575_cb.c	Thu Feb 17 09:18:47 2000
@@ -1845,7 +1845,7 @@
 	long ioaddr = dev->base_addr;
 	int i;
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_device_present(dev))
 		vortex_down(dev);
 
 	if (vortex_debug > 1) {
@@ -1883,7 +1883,7 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
 
-	if (test_bit(LINK_STATE_START, &dev->state)) {
+	if (netif_device_present(dev)) {
 		spin_lock_irqsave (&vp->lock, flags);
 		update_stats(dev->base_addr, dev);
 		spin_unlock_irqrestore (&vp->lock, flags);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/3c589_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/3c589_cs.c	Thu Feb 17 09:18:47 2000
@@ -512,8 +512,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    netif_stop_queue (dev);
-	    clear_bit(LINK_STATE_START, &dev->state);
+	    netif_device_detach(dev);
 	    link->release.expires = jiffies + HZ/20;
 	    add_timer(&link->release);
 	}
@@ -527,10 +526,9 @@
 	/* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
-	    if (link->open) {
-		netif_stop_queue (dev);
-		clear_bit(LINK_STATE_START, &dev->state);
-	    }
+	    if (link->open)
+		netif_device_detach(dev);
+
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -542,8 +540,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		tc589_reset(dev);
-		set_bit(LINK_STATE_START, &dev->state);
-		netif_start_queue (dev);
+		netif_device_attach(dev);
 	    }
 	}
 	break;
@@ -782,7 +779,7 @@
     ioaddr_t ioaddr, status;
     int i = 0;
     
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_device_present(dev))
 	return;
     ioaddr = dev->base_addr;
 
@@ -791,7 +788,7 @@
     
     while ((status = inw(ioaddr + EL3_STATUS)) &
 	(IntLatch | RxComplete | StatsFull)) {
-	if (!test_bit(LINK_STATE_START, &dev->state) ||
+	if (!netif_device_present(dev)) ||
 	    ((status & 0xe000) != 0x2000)) {
 	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);
 	    break;
@@ -865,7 +862,7 @@
     u_short media, errs;
     u_long flags;
 
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_device_present(dev))
 	goto reschedule;
 
     EL3WINDOW(1);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/aironet4500_cs.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/pcmcia/aironet4500_cs.c	Thu Feb 17 09:18:47 2000
@@ -566,7 +566,7 @@
 	case CS_EVENT_CARD_REMOVAL:
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
-			netif_stop_queue (dev);
+			netif_device_detach(dev);
 			link->release.expires = RUN_AT( HZ/20 );
 			add_timer(&link->release);
 		}
@@ -580,9 +580,9 @@
 		/* Fall through... */
 	case CS_EVENT_RESET_PHYSICAL:
 		if (link->state & DEV_CONFIG) {
-			if (link->open) {
-				netif_stop_queue (dev);
-			}
+			if (link->open)
+				netif_device_detach(dev);
+
 			CardServices(ReleaseConfiguration, link->handle);
 		}
 		break;
@@ -594,7 +594,7 @@
 			CardServices(RequestConfiguration, link->handle, &link->conf);
 			if (link->open) {
 				// awc_reset(dev);
-				netif_start_queue (dev);
+				netif_device_attach(dev);
 			}
 		}
 		break;
@@ -636,4 +636,4 @@
 //		awc_detach(dev_list);
 }
 
-        
\ No newline at end of file
+        
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/fmvj18x_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Thu Feb 17 09:18:47 2000
@@ -593,8 +593,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    netif_stop_queue (dev);
-	    clear_bit(LINK_STATE_START, &dev->state);
+	    netif_device_detach(dev);
 	    link->release.expires = jiffies + HZ/20;
 	    add_timer(&link->release);
 	}
@@ -608,10 +607,9 @@
 	/* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
-	    if (link->open) {
-	    	netif_stop_queue (dev);
-		clear_bit(LINK_STATE_START, &dev->state);
-	    }
+	    if (link->open)
+	    	netif_device_detach(dev);
+
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -623,8 +621,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		fjn_reset(dev);
-		set_bit(LINK_STATE_START, &dev->state);
-		netif_start_queue (dev);
+		netif_device_attach(dev);
 	    }
 	}
 	break;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/netwave_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/netwave_cs.c	Thu Feb 17 09:18:47 2000
@@ -1019,8 +1019,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    netif_stop_queue (dev);
-	    clear_bit(LINK_STATE_START, &dev->state);
+	    netif_device_detach(dev);
 	    link->release.expires = jiffies + 5;
 	    add_timer(&link->release);
 	}
@@ -1034,10 +1033,9 @@
 	/* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
-	    if (link->open) {
-		netif_stop_queue (dev);
-		clear_bit(LINK_STATE_START, &dev->state);
-	    }
+	    if (link->open)
+		netif_device_detach(dev);
+
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -1049,8 +1047,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		netwave_reset(dev);
-		set_bit(LINK_STATE_START, &dev->state);
-		netif_start_queue (dev);
+		netif_device_attach(dev);
 	    }
 	}
 	break;
@@ -1299,7 +1296,7 @@
     dev_link_t *link = &priv->link;
     int i;
     
-    if ((dev == NULL) || !test_bit(LINK_STATE_START, &dev->state))
+    if ((dev == NULL) || !netif_device_present(dev))
 	return;
     
     spin_lock (&priv->lock);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/nmclan_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/nmclan_cs.c	Thu Feb 17 09:18:47 2000
@@ -870,7 +870,7 @@
     case CS_EVENT_CARD_REMOVAL:
       link->state &= ~DEV_PRESENT;
       if (link->state & DEV_CONFIG) {
-	netif_stop_queue (dev);
+	netif_device_detach(dev);
 	link->release.expires = jiffies + HZ/20;
 	add_timer(&link->release);
       }
@@ -884,9 +884,9 @@
       /* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
       if (link->state & DEV_CONFIG) {
-	if (link->open) {
-	  netif_stop_queue (dev);
-	}
+	if (link->open)
+	  netif_device_detach(dev);
+
 	CardServices(ReleaseConfiguration, link->handle);
       }
       break;
@@ -898,7 +898,7 @@
 	CardServices(RequestConfiguration, link->handle, &link->conf);
 	if (link->open) {
 	  nmclan_reset(dev);
-	  netif_start_queue (dev);
+	  netif_device_attach(dev);
 	}
       }
       break;
@@ -1153,7 +1153,7 @@
     return;
   }
 
-  if (!test_bit(LINK_STATE_START, &dev->state)) {
+  if (!netif_device_present(dev)) {
     DEBUG(2, "%s: interrupt from dead card\n", dev->name);
     goto exception;
   }
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/pcnet_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/pcnet_cs.c	Thu Feb 17 09:18:47 2000
@@ -812,8 +812,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    netif_stop_queue(&info->dev);
-	    clear_bit(LINK_STATE_START, &info->dev.state);
+	    netif_device_detach(&info->dev);
 	    link->release.expires = jiffies + HZ/20;
 	    link->state |= DEV_RELEASE_PENDING;
 	    add_timer(&link->release);
@@ -828,10 +827,9 @@
 	/* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
-	    if (link->open) {
-		netif_stop_queue(&info->dev);
-		clear_bit(LINK_STATE_START, &info->dev.state);
-	    }
+	    if (link->open)
+		netif_device_detach(&info->dev);
+
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -844,8 +842,7 @@
 	    if (link->open) {
 		pcnet_reset_8390(&info->dev);
 		NS8390_init(&info->dev, 1);
-		netif_start_queue(&info->dev);
-		set_bit(LINK_STATE_START, &info->dev.state);
+		netif_device_attach(&info->dev);
 	    }
 	}
 	break;
@@ -988,7 +985,7 @@
     struct net_device *dev = &info->dev;
     ioaddr_t nic_base = dev->base_addr;
 
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_device_present(dev))
 	    goto reschedule;
 
     /* Check for pending interrupt with expired latency timer: with
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/ray_cs.c	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/pcmcia/ray_cs.c	Thu Feb 17 09:18:47 2000
@@ -926,8 +926,7 @@
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
         link->state &= ~DEV_PRESENT;
-        netif_stop_queue(dev);
-        clear_bit(LINK_STATE_START, &dev->state);
+        netif_device_detach(dev);
         if (link->state & DEV_CONFIG) {
             link->release.expires = jiffies + HZ/20;
             add_timer(&link->release);
@@ -943,10 +942,9 @@
         /* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
         if (link->state & DEV_CONFIG) {
-            if (link->open) {
-            	netif_stop_queue(dev);
-            	clear_bit(LINK_STATE_START, &dev->state);
-            }
+            if (link->open)
+            	netif_device_detach(dev);
+
             pcmcia_release_configuration(link->handle);
         }
         break;
@@ -958,8 +956,7 @@
             pcmcia_request_configuration(link->handle, &link->conf);
             if (link->open) {
                 ray_reset(dev);
-		netif_start_queue(dev);
-		set_bit(LINK_STATE_START, &dev->state);
+		netif_device_attach(dev);
             }
         }
         break;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/smc91c92_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	Thu Feb 17 09:18:47 2000
@@ -1112,8 +1112,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    netif_stop_queue (dev);
-	    clear_bit(LINK_STATE_START, &dev->state);
+	    netif_device_detach(dev);
 	    link->release.expires = jiffies + HZ/20;
 	    link->state |= DEV_RELEASE_PENDING;
 	    add_timer(&link->release);
@@ -1128,10 +1127,9 @@
 	/* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
-	    if (link->open) {
-		netif_stop_queue (dev);
-		clear_bit(LINK_STATE_START, &dev->state);
-	    }
+	    if (link->open)
+		netif_device_detach(dev);
+
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -1154,8 +1152,7 @@
 	    }
 	    if (link->open) {
 		smc_reset(dev);
-		set_bit(LINK_STATE_START, &dev->state);
-		netif_start_queue (dev);
+		netif_device_attach(dev);
 	    }
 	}
 	break;
@@ -1506,7 +1503,7 @@
     u_short saved_bank, saved_pointer, mask, status;
     char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */
 
-    if ((smc == NULL) || !test_bit(LINK_STATE_START, &dev->state))
+    if ((smc == NULL) || !netif_device_present(dev))
 	return;
     ioaddr = dev->base_addr;
     
@@ -1910,7 +1907,7 @@
     ioaddr_t ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
 
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_device_present(dev))
 	goto reschedule;
 
     saved_bank = inw(ioaddr + BANK_SELECT);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c
--- v2.3.46/linux/drivers/net/pcmcia/tulip_cb.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/pcmcia/tulip_cb.c	Fri Feb 18 11:50:34 2000
@@ -2713,8 +2713,6 @@
 	long ioaddr = dev->base_addr;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 
-	netif_stop_queue (dev);
-
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0x00000000, ioaddr + CSR7);
 	/* Stop the chip's Tx and Rx processes. */
@@ -2726,8 +2724,6 @@
 	if (inl(ioaddr + CSR6) != 0xffffffff)
 		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 
-	del_timer(&tp->timer);
-
 	dev->if_port = tp->saved_if_port;
 }
 
@@ -2742,9 +2738,13 @@
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
 			   dev->name, inl(ioaddr + CSR5));
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	netif_stop_queue(dev);
+
+	if (netif_device_present(dev))
 		tulip_down(dev);
 
+	del_timer(&tp->timer);
+
 	free_irq(dev->irq, dev);
 
 	/* Free all the skbuffs in the Rx queue. */
@@ -2774,7 +2774,7 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_device_present(dev))
 		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 
 	return &tp->stats;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/wavelan_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Thu Feb 17 09:18:47 2000
@@ -1001,7 +1001,7 @@
 
 		lp->reconfig_82593 = FALSE;
 		wv_82593_config (dev);
-		netif_start_queue (dev);
+		netif_wake_queue (dev);
 	}
 }
 
@@ -4360,7 +4360,7 @@
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if (test_bit(LINK_STATE_START, &dev->state))
+  if (netif_device_present(dev))
     {
       netif_stop_queue (dev);
 
@@ -4662,8 +4662,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
 	    /* Accept no more transmissions */
-      	    netif_stop_queue (dev);
-	    clear_bit(LINK_STATE_START, &dev->state);
+      	    netif_device_detach(dev);
 
 	    /* Release the card */
 	    wv_pcmcia_release((u_long) link);
@@ -4700,10 +4699,8 @@
     	if(link->state & DEV_CONFIG)
 	  {
       	    if(link->open)
-	      {
-	      	netif_stop_queue (dev);
-		clear_bit(LINK_STATE_START, &dev->state);
-	      }
+	      	netif_device_detach(dev);
+
       	    CardServices(ReleaseConfiguration, link->handle);
 	  }
 	break;
@@ -4718,8 +4715,7 @@
       	    if(link->open)	/* If RESET -> True, If RESUME -> False ??? */
 	      {
 		wv_hw_reset(dev);
-		set_bit(LINK_STATE_START, &dev->state);
-		netif_start_queue (dev);
+		netif_device_attach(dev);
 	      }
 	  }
 	break;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- v2.3.46/linux/drivers/net/pcmcia/xirc2ps_cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	Thu Feb 17 09:18:47 2000
@@ -1340,8 +1340,7 @@
       case CS_EVENT_CARD_REMOVAL:
 	  link->state &= ~DEV_PRESENT;
 	  if (link->state & DEV_CONFIG) {
-	      netif_stop_queue(dev);
-	      clear_bit(LINK_STATE_START, &dev->state);
+	      netif_device_detach(dev);
 	      link->release.expires = jiffies + HZ / 20;
 	      add_timer(&link->release);
 	  }
@@ -1356,8 +1355,7 @@
       case CS_EVENT_RESET_PHYSICAL:
 	  if (link->state & DEV_CONFIG) {
 	      if (link->open) {
-		  netif_stop_queue(dev);
-		  clear_bit(LINK_STATE_START, &dev->state);
+		  netif_device_detach(dev);
 		  lp->suspended=1;
 		  do_powerdown(dev);
 	      }
@@ -1373,8 +1371,7 @@
 	     if (link->open) {
 		 do_reset(dev,1);
 		 lp->suspended=0;
-		 set_bit(LINK_STATE_START, &dev->state);
-		 netif_start_queue(dev);
+		 netif_device_attach(dev);
 	     }
 	  }
 	  break;
@@ -1403,7 +1400,7 @@
 				  */
 
     spin_lock (&lp->lock);
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_device_present(dev))
 	return;
 
     ioaddr = dev->base_addr;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.3.46/linux/drivers/net/pcnet32.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/pcnet32.c	Thu Feb 17 09:18:47 2000
@@ -1153,8 +1153,8 @@
 	    }
 #endif
 	    if (lp->tx_full &&
-	        test_bit(LINK_STATE_XOFF, &dev->flags) &&
-		dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+	        netif_queue_stopped(dev) &&
+			dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
 		/* The ring is no longer full, clear tbusy. */
 		lp->tx_full = 0;
 		netif_wake_queue (dev);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.3.46/linux/drivers/net/plip.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/plip.c	Thu Feb 17 09:18:47 2000
@@ -965,7 +965,7 @@
 	struct net_local *nl = (struct net_local *)dev->priv;
 	struct plip_local *snd = &nl->snd_data;
 
-	if (test_bit(LINK_STATE_XOFF, &dev->flags))
+	if (netif_queue_stopped(dev))
 		return 1;
 
 	/* We may need to grab the bus */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c
--- v2.3.46/linux/drivers/net/rtl8129.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/rtl8129.c	Fri Feb 18 15:07:20 2000
@@ -787,7 +787,7 @@
 			rtl8129_interrupt(dev->irq, dev, 0);
 		}
 	}
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+	if (netif_queue_stopped(dev) &&
 		(jiffies - dev->trans_start) >= 2*TX_TIMEOUT)
 		rtl8129_tx_timeout(dev);
 
@@ -908,7 +908,7 @@
 
 			saved_skb[j] = rp->skb;
 			if (rp->mapping != 0) {
-				pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len);
+				pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);
 				rp->mapping = 0;
 			}
 		}
@@ -922,7 +922,7 @@
 					 ioaddr + TxAddr0 + i*4);
 			} else {
 				tp->tx_info[i].mapping =
-					pci_map_single(tp->pdev, skb->data, skb->len);
+					pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
 				outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4);
 			}
 			/* Note: the chip doesn't have auto-pad! */
@@ -991,7 +991,7 @@
 			 ioaddr + TxAddr0 + entry*4);
 	} else {
 		tp->tx_info[entry].mapping =
-			pci_map_single(tp->pdev, skb->data, skb->len);
+			pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
 		outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4);
 	}
 	/* Note: the chip doesn't have auto-pad! */
@@ -1085,7 +1085,8 @@
 				if (tp->tx_info[entry].mapping != 0) {
 					pci_unmap_single(tp->pdev,
 									 tp->tx_info[entry].mapping,
-									 tp->tx_info[entry].skb->len);
+									 tp->tx_info[entry].skb->len,
+									 PCI_DMA_TODEVICE);
 					tp->tx_info[entry].mapping = 0;
 				}
 
@@ -1315,7 +1316,7 @@
 
 		if (skb) {
 			if (mapping)
-				pci_unmap_single(tp->pdev, mapping, skb->len);
+				pci_unmap_single(tp->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
 		}
 		tp->tx_info[i].skb = NULL;
@@ -1366,7 +1367,7 @@
 	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (test_bit(LINK_STATE_START, &dev->state)) {
+	if (netif_running(dev)) {
 		tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
 		outl(0, ioaddr + RxMissed);
 	}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
--- v2.3.46/linux/drivers/net/sis900.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/sis900.c	Thu Feb 17 09:18:47 2000
@@ -1066,7 +1066,7 @@
 		sis_priv->tx_ring[entry].cmdsts = 0;
 	}
 	
-	if (sis_priv->tx_full && test_bit(LINK_STATE_XOFF, &net_dev->flags) && 
+	if (sis_priv->tx_full && netif_queue_stopped(net_dev) && 
 	    sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
 		/* The ring is no longer full, clear tx_full and schedule more transmission
 		   by netif_wake_queue(net_dev) */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.3.46/linux/drivers/net/sk98lin/skge.c	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/sk98lin/skge.c	Fri Feb 18 15:07:20 2000
@@ -276,7 +276,9 @@
 // #define RLMT_MODE	{"CheckLink", }
 
 
-#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb)
+#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb)
 
 /* function prototypes ******************************************************/
 static void	FreeResources(struct net_device *dev);
@@ -410,6 +412,21 @@
 
 		pci_set_master(pdev);
 
+#ifdef __sparc__
+		/* Set the proper cache line size value, plus enable
+		 * write-invalidate and fast back-to-back on Sparc.
+		 */
+		{
+			SK_U16 pci_command;
+
+			SkPciWriteCfgByte(pAC, PCI_CACHE_LINE_SIZE, 0x10);
+
+			SkPciReadCfgWord(pAC, PCI_COMMAND, &pci_command);
+			pci_command |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK);
+			SkPciWriteCfgWord(pAC, PCI_COMMAND, pci_command);
+		}
+#endif
+
 		base_address = pdev->resource[0].start;
 
 #ifdef SK_BIG_ENDIAN
@@ -1507,13 +1524,16 @@
 
 	Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb);
 
-	if (Rc == 0) {
-		/* transmitter out of resources */
+	/* Transmitter out of resources? */
+	if (Rc <= 0)
 		netif_stop_queue(dev);
 
-		/* give buffer ownership back to the queueing layer */
+	/* If not taken, give buffer ownership back to the
+	 * queueing layer.
+	 */
+	if (Rc < 0)
 		return (1);
-	} 
+
 	dev->trans_start = jiffies;
 	return (0);
 } /* SkGeXmit */
@@ -1539,7 +1559,7 @@
  *	> 0 - on succes: the number of bytes in the message
  *	= 0 - on resource shortage: this frame sent or dropped, now
  *        the ring is full ( -> set tbusy)
- *	< 0 - on failure: other problems (not used)
+ *	< 0 - on failure: other problems ( -> return failure to upper layers)
  */
 static int XmitFrame(
 SK_AC 		*pAC,		/* pointer to adapter context */
@@ -1566,7 +1586,7 @@
 				SK_DBGCAT_DRV_TX_PROGRESS,
 				("XmitFrame failed\n"));
 			/* this message can not be sent now */
-			return (0);
+			return (-1);
 		}
 	}
 	/* advance head counter behind descriptor needed for this frame */
@@ -1586,7 +1606,8 @@
 	/* set up descriptor and CONTROL dword */
 	PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev,
 					   pMessage->data,
-					   pMessage->len);
+					   pMessage->len,
+					   PCI_DMA_TODEVICE);
 	pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
 	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
 	pTxd->pMBuf = pMessage;
@@ -1679,9 +1700,11 @@
 		PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
 		PhysAddr |= (SK_U64) pTxd->VDataLow;
 		pci_unmap_single(&pAC->PciDev, PhysAddr,
-				 pTxd->pMBuf->len);
+				 pTxd->pMBuf->len,
+				 PCI_DMA_TODEVICE);
 
-		DEV_KFREE_SKB(pTxd->pMBuf); /* free message */
+		/* free message */
+		DEV_KFREE_SKB_ANY(pTxd->pMBuf);
 		pTxPort->TxdRingFree++;
 		pTxd->TBControl &= ~TX_CTRL_SOFTWARE;
 		pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
@@ -1759,7 +1782,8 @@
 	Length = pAC->RxBufSize;
 	PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev,
 					   pMsgBlock->data,
-					   pAC->RxBufSize - 2);
+					   pAC->RxBufSize - 2,
+					   PCI_DMA_FROMDEVICE);
 	pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
 	pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
 	pRxd->pMBuf = pMsgBlock;
@@ -1882,7 +1906,8 @@
 				skb_put(pNewMsg, FrameLength);
 				pci_dma_sync_single(&pAC->PciDev,
 						    (dma_addr_t) PhysAddr,
-						    FrameLength);
+						    FrameLength,
+						    PCI_DMA_FROMDEVICE);
 				eth_copy_and_sum(pNewMsg, pMsg->data,
 					FrameLength, 0);
 				ReQueueRxBuffer(pAC, pRxPort, pMsg,
@@ -1902,15 +1927,16 @@
 			/* release the DMA mapping */
 			pci_unmap_single(&pAC->PciDev,
 					 PhysAddr,
-					 pAC->RxBufSize - 2);
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
 
 			/* set length in message */
 			skb_put(pMsg, FrameLength);
 			/* hardware checksum */
 			Type = ntohs(*((short*)&pMsg->data[12]));
 			if (Type == 0x800) {
-				Csum1= pRxd->TcpSums & 0xffff;
-				Csum2=(pRxd->TcpSums >> 16) & 0xffff;
+				Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff);
+				Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff);
 				if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) {
 					Result = SkCsGetReceiveInfo(pAC,
 						&pMsg->data[14], 
@@ -1980,7 +2006,7 @@
 					SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
 						SK_DBGCAT_DRV_RX_PROGRESS,
 						("D"));
-					DEV_KFREE_SKB(pMsg);
+					DEV_KFREE_SKB_IRQ(pMsg);
 				}
 			} /* if not for rlmt */
 			else {
@@ -2016,7 +2042,7 @@
 					pAC->dev->last_rx = jiffies;
 				}
 				else {
-					DEV_KFREE_SKB(pMsg);
+					DEV_KFREE_SKB_IRQ(pMsg);
 				}
 
 			} /* if packet for rlmt */
@@ -2040,7 +2066,7 @@
 				("skge: Error in received frame, dropped!\n"
 				"Control: %x\nRxStat: %x\n",
 				Control, FrameStat));
-			DEV_KFREE_SKB(pMsg);
+			DEV_KFREE_SKB_IRQ(pMsg);
 		}
 	} /* while */
 	FillRxRing(pAC, pRxPort);
@@ -2060,8 +2086,9 @@
 	PhysAddr |= (SK_U64) pRxd->VDataLow;
 	pci_unmap_single(&pAC->PciDev,
 			 PhysAddr,
-			 pAC->RxBufSize - 2);
-	DEV_KFREE_SKB(pRxd->pMBuf);
+			 pAC->RxBufSize - 2,
+			 PCI_DMA_FROMDEVICE);
+	DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
 	pRxd->pMBuf = NULL;
 	pRxPort->RxdRingFree++;
 	pRxPort->pRxdRingHead = pRxd->pNextRxd;
@@ -2139,7 +2166,8 @@
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
 			pci_unmap_single(&pAC->PciDev,
 					 PhysAddr,
-					 pAC->RxBufSize - 2);
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
 			DEV_KFREE_SKB(pRxd->pMBuf);
 			pRxd->pMBuf = NULL;
 		}
@@ -2276,7 +2304,7 @@
 	
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeSetMacAddr starts now...\n"));
-	if(test_bit(LINK_STATE_START, &dev->state)) {
+	if(netif_running(dev)) {
 		return -EBUSY;
 	}
 	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
@@ -3120,7 +3148,7 @@
 	pFreeMbuf = pMbuf;
 	do {
 		pNextMbuf = pFreeMbuf->pNext;
-		DEV_KFREE_SKB(pFreeMbuf->pOs);
+		DEV_KFREE_SKB_ANY(pFreeMbuf->pOs);
 		pFreeMbuf = pNextMbuf;
 	} while ( pFreeMbuf != NULL );
 } /* SkDrvFreeRlmtMbuf */
@@ -3489,8 +3517,9 @@
 		pRlmtMbuf = (SK_MBUF*) Param.pParaPtr;
 		pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
 		skb_put(pMsg, pRlmtMbuf->Length);
-		XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
-			pMsg);
+		if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
+			      pMsg) < 0)
+			DEV_KFREE_SKB_ANY(pMsg);
 		break;
 	default:
 		break;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v2.3.46/linux/drivers/net/skeleton.c	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/skeleton.c	Thu Feb 17 09:18:47 2000
@@ -416,7 +416,7 @@
 	spin_lock_irq(&np->lock);
 
 	add_to_tx_ring(np, skb, length);
-	dev->trans_start = jiffied;
+	dev->trans_start = jiffies;
 
 	/* If we just used up the very last entry in the
 	 * TX ring on this device, tell the queueing
@@ -482,8 +482,7 @@
 	 * condition, and space has now been made available,
 	 * wake up the queue.
 	 */
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
-	    ! tx_full(dev))
+	if (netif_queue_stopped(dev) && ! tx_full(dev))
 		netif_wake_queue(dev);
 
 	spin_unlock(&np->lock);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/Makefile linux/drivers/net/skfp/Makefile
--- v2.3.46/linux/drivers/net/skfp/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/Makefile	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,39 @@
+#
+# Makefile for the SysKonnect FDDI PCI adapter driver
+#
+
+ifeq ($(CONFIG_SKFP),y)
+    O_TARGET := skfp.o
+    O_OBJS =  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
+              ecm.o       pcmplc.o   pmf.o      queue.o    rmt.o     \
+	      smtdef.o    smtinit.o  smttimer.o srf.o      lnkstat.o \
+              smtparse.o  hwt.o      drvfbi.o   ess.o
+else
+  ifeq ($(CONFIG_SKFP),m)
+    MOD_LIST_NAME := SKFP_MODULES
+    M_OBJS := skfp.o
+    O_TARGET := skfp.o
+    O_OBJS =  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
+              ecm.o       pcmplc.o   pmf.o      queue.o    rmt.o     \
+	      smtdef.o    smtinit.o  smttimer.o srf.o      lnkstat.o \
+              smtparse.o  hwt.o      drvfbi.o   ess.o
+  endif
+endif
+
+# NOTE:
+#   Compiling this driver produces some warnings (and some more are 
+#   switched off below), but I did not fix this, because the Hardware
+#   Module source (see skfddi.c for details) is used for different
+#   drivers, and fixing it for Linux might bring problems on other
+#   projects. To keep the source common for all those drivers (and
+#   thus simplify fixes to it), please do not clean it up!
+ 
+EXTRA_CFLAGS += -I. -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes 
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
+
+
+
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/can.c linux/drivers/net/skfp/can.c
--- v2.3.46/linux/drivers/net/skfp/can.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/can.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static const char xID_sccs[] = "@(#)can.c	1.5 97/04/07 (C) SK " ;
+#endif
+
+/*
+ * canonical bit order
+ */
+const u_char canonical[256] = {
+	0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
+	0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
+	0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
+	0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
+	0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
+	0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
+	0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
+	0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
+	0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
+	0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
+	0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
+	0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
+	0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
+	0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
+	0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
+	0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
+	0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
+	0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
+	0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
+	0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
+	0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
+	0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
+	0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
+	0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
+	0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
+	0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
+	0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
+	0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
+	0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
+	0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
+	0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
+	0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
+} ;
+
+#ifdef	MAKE_TABLE
+int byte_reverse(x)
+int x ;
+{
+	int     y = 0 ;
+
+	if (x & 0x01)
+		y |= 0x80 ;
+	if (x & 0x02)
+		y |= 0x40 ;
+	if (x & 0x04)
+		y |= 0x20 ;
+	if (x & 0x08)
+		y |= 0x10 ;
+	if (x & 0x10)
+		y |= 0x08 ;
+	if (x & 0x20)
+		y |= 0x04 ;
+	if (x & 0x40)
+		y |= 0x02 ;
+	if (x & 0x80)
+		y |= 0x01 ;
+	return(y) ;
+}
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/cfm.c linux/drivers/net/skfp/cfm.c
--- v2.3.46/linux/drivers/net/skfp/cfm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/cfm.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,642 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT CFM
+	Configuration Management
+	DAS with single MAC
+*/
+
+/*
+ *	Hardware independant state machine implemantation
+ *	The following external SMT functions are referenced :
+ *
+ *		queue_event()
+ *
+ *	The following external HW dependant functions are referenced :
+ *		config_mux()
+ *
+ *	The following HW dependant events are required :
+ *		NONE 
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)cfm.c	2.18 98/10/06 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG	0x10
+#define GO_STATE(x)	(smc->mib.fddiSMTCF_State = (x)|AFLAG)
+#define ACTIONS_DONE()	(smc->mib.fddiSMTCF_State &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const cfm_states[] = {
+	"SC0_ISOLATED","CF1","CF2","CF3","CF4",
+	"SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
+	"SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const cfm_events[] = {
+	"NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
+} ;
+#endif
+
+/*
+ * map from state to downstream port type
+ */
+static const u_char cf_to_ptype[] = {
+	TNONE,TNONE,TNONE,TNONE,TNONE,
+	TNONE,TB,TB,TS,
+	TA,TB,TS,TB
+} ;
+
+/*
+ * CEM port states
+ */
+#define	CEM_PST_DOWN	0
+#define	CEM_PST_UP	1
+#define	CEM_PST_HOLD	2
+/* define portstate array only for A and B port */
+/* Do this within the smc structure (use in multiple cards) */
+
+/*
+ * all Globals  are defined in smc.h
+ * struct s_cfm
+ */
+
+/*
+ * function declarations
+ */
+static void cfm_fsm() ;
+
+/*
+	init CFM state machine
+	clear all CFM vars and flags
+*/
+void cfm_init(smc)
+struct s_smc *smc ;
+{
+	smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
+	smc->r.rm_join = 0 ;
+	smc->r.rm_loop = 0 ;
+	smc->y[PA].scrub = 0 ;
+	smc->y[PB].scrub = 0 ;
+	smc->y[PA].cem_pst = CEM_PST_DOWN ;
+	smc->y[PB].cem_pst = CEM_PST_DOWN ;
+}
+
+/* Some terms conditions used by the selection criteria */
+#define THRU_ENABLED(smc)	(smc->y[PA].pc_mode != PM_TREE && \
+				 smc->y[PB].pc_mode != PM_TREE)
+/* Selection criteria for the ports */
+static void	selection_criteria (smc,phy)
+struct s_smc	*smc ;
+struct s_phy	*phy ;
+{
+
+	switch (phy->mib->fddiPORTMy_Type) {
+	case TA:
+		if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
+			phy->wc_flag = TRUE ;
+		} else {
+			phy->wc_flag = FALSE ;
+		}
+
+		break;
+	case TB:
+		/* take precedence over PA */
+		phy->wc_flag = FALSE ;
+		break;
+	case TS:
+		phy->wc_flag = FALSE ;
+		break;
+	case TM:
+		phy->wc_flag = FALSE ;
+		break;
+	}
+
+}
+
+void	all_selection_criteria (smc)
+struct s_smc *smc ;
+{
+	struct s_phy	*phy ;
+	int		p ;
+
+	for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
+		/* Do the selection criteria */
+		selection_criteria (smc,phy);
+	}
+}
+
+static void	cem_priv_state (smc, event)
+struct s_smc *smc ;
+int event ;
+/* State machine for private PORT states: used to optimize dual homing */
+{
+	int	np;	/* Number of the port */
+	int	i;
+
+	/* Do this only in a DAS */
+	if (smc->s.sas != SMT_DAS )
+		return ;
+
+	np = event - CF_JOIN;
+
+	if (np != PA && np != PB) {
+		return ;
+	}
+	/* Change the port state according to the event (portnumber) */
+	if (smc->y[np].cf_join) {
+		smc->y[np].cem_pst = CEM_PST_UP ;
+	} else if (!smc->y[np].wc_flag) {
+		/* set the port to done only if it is not withheld */
+		smc->y[np].cem_pst = CEM_PST_DOWN ;
+	}
+
+	/* Don't set an hold port to down */
+
+	/* Check all ports of restart conditions */
+	for (i = 0 ; i < 2 ; i ++ ) {
+		/* Check all port for PORT is on hold and no withhold is done */
+		if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
+			smc->y[i].cem_pst = CEM_PST_DOWN;
+			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
+		}
+		if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
+			smc->y[i].cem_pst = CEM_PST_HOLD;
+			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
+		}
+		if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
+			/*
+			 * The port must be restarted when the wc_flag
+			 * will be reset. So set the port on hold.
+			 */
+			smc->y[i].cem_pst = CEM_PST_HOLD;
+		}
+	}
+	return ;
+}
+
+/*
+	CFM state machine
+	called by dispatcher
+
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void cfm(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	int	state ;		/* remember last state */
+	int	cond ;
+	int	oldstate ;
+
+	/* We will do the following: */
+	/*  - compute the variable WC_Flag for every port (This is where */
+	/*    we can extend the requested path checking !!) */
+	/*  - do the old (SMT 6.2 like) state machine */
+	/*  - do the resulting station states */
+
+	all_selection_criteria (smc);
+
+	/* We will check now whether a state transition is allowed or not */
+	/*  - change the portstates */
+	cem_priv_state (smc, event);
+
+	oldstate = smc->mib.fddiSMTCF_State ;
+	do {
+		DB_CFM("CFM : state %s%s",
+			(smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "",
+			cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ;
+		DB_CFM(" event %s\n",cfm_events[event],0) ;
+		state = smc->mib.fddiSMTCF_State ;
+		cfm_fsm(smc,event) ;
+		event = 0 ;
+	} while (state != smc->mib.fddiSMTCF_State) ;
+
+#ifndef	SLIM_SMT
+	/*
+	 * check peer wrap condition
+	 */
+	cond = FALSE ;
+	if (	(smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
+		smc->y[PA].pc_mode == PM_PEER) 	||
+		(smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
+		smc->y[PB].pc_mode == PM_PEER) 	||
+		(smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
+		smc->y[PS].pc_mode == PM_PEER &&
+		smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
+			cond = TRUE ;
+	}
+	if (cond != smc->mib.fddiSMTPeerWrapFlag)
+		smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
+
+#if	0
+	/*
+	 * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired
+	 * to the primary path.
+	 */
+	/*
+	 * path change
+	 */
+	if (smc->mib.fddiSMTCF_State != oldstate) {
+		smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ;
+	}
+#endif
+#endif	/* no SLIM_SMT */
+
+	/*
+	 * set MAC port type
+	 */
+	smc->mib.m[MAC0].fddiMACDownstreamPORTType =
+		cf_to_ptype[smc->mib.fddiSMTCF_State] ;
+	cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
+}
+
+/*
+	process CFM event
+*/
+/*ARGSUSED1*/
+static void cfm_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+	switch(smc->mib.fddiSMTCF_State) {
+	case ACTIONS(SC0_ISOLATED) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
+		config_mux(smc,MUX_ISOLATE) ;	/* configure PHY Mux */
+		smc->r.rm_loop = FALSE ;
+		smc->r.rm_join = FALSE ;
+		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		/* Don't do the WC-Flag changing here */
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break;
+	case SC0_ISOLATED :
+		/*SC07*/
+		/*SAS port can be PA or PB ! */
+		if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
+				smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
+			GO_STATE(SC11_C_WRAP_S) ;
+			break ;
+		}
+		/*SC01*/
+		if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
+		     !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC02*/
+		if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
+		     !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC9_C_WRAP_A) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+		config_mux(smc,MUX_WRAPA) ;		/* configure PHY mux */
+		if (smc->y[PA].cf_loop) {
+			smc->r.rm_join = FALSE ;
+			smc->r.rm_loop = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+		}
+		if (smc->y[PA].cf_join) {
+			smc->r.rm_loop = FALSE ;
+			smc->r.rm_join = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		}
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC9_C_WRAP_A :
+		/*SC10*/
+		if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
+		      !smc->y[PA].cf_loop ) {
+			GO_STATE(SC0_ISOLATED) ;
+			break ;
+		}
+		/*SC12*/
+		else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
+			   smc->y[PA].cem_pst == CEM_PST_UP) ||
+			  ((smc->y[PB].cf_loop ||
+			   (smc->y[PB].cf_join &&
+			    smc->y[PB].cem_pst == CEM_PST_UP)) &&
+			    (smc->y[PA].pc_mode == PM_TREE ||
+			     smc->y[PB].pc_mode == PM_TREE))) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		/*SC14*/
+		else if (!smc->s.attach_s &&
+			  smc->y[PA].cf_join &&
+			  smc->y[PA].cem_pst == CEM_PST_UP &&
+			  smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
+			  smc->y[PB].cem_pst == CEM_PST_UP &&
+			  smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC4_THRU_A) ;
+			break ;
+		}
+		/*SC15*/
+		else if ( smc->s.attach_s &&
+			  smc->y[PA].cf_join &&
+			  smc->y[PA].cem_pst == CEM_PST_UP &&
+			  smc->y[PA].pc_mode == PM_PEER &&
+			  smc->y[PB].cf_join &&
+			  smc->y[PB].cem_pst == CEM_PST_UP &&
+			  smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC5_THRU_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC10_C_WRAP_B) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+		config_mux(smc,MUX_WRAPB) ;		/* configure PHY mux */
+		if (smc->y[PB].cf_loop) {
+			smc->r.rm_join = FALSE ;
+			smc->r.rm_loop = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+		}
+		if (smc->y[PB].cf_join) {
+			smc->r.rm_loop = FALSE ;
+			smc->r.rm_join = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		}
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC10_C_WRAP_B :
+		/*SC20*/
+		if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
+			GO_STATE(SC0_ISOLATED) ;
+			break ;
+		}
+		/*SC21*/
+		else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
+			  smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC24*/
+		else if (!smc->s.attach_s &&
+			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
+			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC4_THRU_A) ;
+			break ;
+		}
+		/*SC25*/
+		else if ( smc->s.attach_s &&
+			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
+			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC5_THRU_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC4_THRU_A) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
+		config_mux(smc,MUX_THRUA) ;		/* configure PHY mux */
+		smc->r.rm_loop = FALSE ;
+		smc->r.rm_join = TRUE ;
+		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC4_THRU_A :
+		/*SC41*/
+		if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC42*/
+		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		/*SC45*/
+		else if (smc->s.attach_s) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC5_THRU_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC5_THRU_B) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
+		config_mux(smc,MUX_THRUB) ;		/* configure PHY mux */
+		smc->r.rm_loop = FALSE ;
+		smc->r.rm_join = TRUE ;
+		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC5_THRU_B :
+		/*SC51*/
+		if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC52*/
+		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		/*SC54*/
+		else if (!smc->s.attach_s) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC4_THRU_A) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC11_C_WRAP_S) :
+		smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+		smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+		config_mux(smc,MUX_WRAPS) ;		/* configure PHY mux */
+		if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
+			smc->r.rm_join = FALSE ;
+			smc->r.rm_loop = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+		}
+		if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
+			smc->r.rm_loop = FALSE ;
+			smc->r.rm_join = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		}
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC11_C_WRAP_S :
+		/*SC70*/
+		if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
+		     !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
+			GO_STATE(SC0_ISOLATED) ;
+			break ;
+		}
+		break ;
+	default:
+		SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
+		break;
+	}
+}
+
+/*
+ * get MAC's input Port
+ *	return :
+ *		PA or PB
+ */
+int cfm_get_mac_input(smc)
+struct s_smc *smc ;
+{
+	return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+		smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA) ;
+}
+
+/*
+ * get MAC's output Port
+ *	return :
+ *		PA or PB
+ */
+int cfm_get_mac_output(smc)
+struct s_smc *smc ;
+{
+	return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+		smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA) ;
+}
+
+static char path_iso[] = {
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
+} ;
+
+static char path_wrap_a[] = {
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
+} ;
+
+static char path_wrap_b[] = {
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO
+} ;
+
+static char path_thru[] = {
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM
+} ;
+
+static char path_wrap_s[] = {
+	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+} ;
+
+static char path_iso_s[] = {
+	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_ISO,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
+} ;
+
+int cem_build_path(smc,to,path_index)
+struct s_smc *smc ;
+char *to ;
+int path_index ;
+{
+	char	*path ;
+	int	len ;
+
+	switch (smc->mib.fddiSMTCF_State) {
+	default :
+	case SC0_ISOLATED :
+		path = smc->s.sas ? path_iso_s : path_iso ;
+		len = smc->s.sas ? sizeof(path_iso_s) :  sizeof(path_iso) ;
+		break ;
+	case SC9_C_WRAP_A :
+		path = path_wrap_a ;
+		len = sizeof(path_wrap_a) ;
+		break ;
+	case SC10_C_WRAP_B :
+		path = path_wrap_b ;
+		len = sizeof(path_wrap_b) ;
+		break ;
+	case SC4_THRU_A :
+		path = path_thru ;
+		len = sizeof(path_thru) ;
+		break ;
+	case SC11_C_WRAP_S :
+		path = path_wrap_s ;
+		len = sizeof(path_wrap_s) ;
+		break ;
+	}
+	memcpy(to,path,len) ;
+
+	LINT_USE(path_index);
+
+	return(len) ;
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/drvfbi.c linux/drivers/net/skfp/drvfbi.c
--- v2.3.46/linux/drivers/net/skfp/drvfbi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/drvfbi.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,1612 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FBI board dependent Driver for SMT and LLC
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "h/skfbiinc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)drvfbi.c	1.63 99/02/11 (C) SK " ;
+#endif
+
+/*
+ * PCM active state
+ */
+#define PC8_ACTIVE	8
+
+#define	LED_Y_ON	0x11	/* Used for ring up/down indication */
+#define	LED_Y_OFF	0x10
+
+
+#define MS2BCLK(x)	((x)*12500L)
+
+/*
+ * valid configuration values are:
+ */
+#ifdef	ISA
+const int opt_ints[] = {8,	3, 4, 5, 9, 10, 11, 12, 15} ;
+const int opt_iops[] = {8,
+	0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340};
+const int opt_dmas[] = {4,	3, 5, 6, 7} ;
+const int opt_eproms[] = {15,	0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
+			0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
+#endif
+#ifdef	EISA
+const int opt_ints[] = {5, 9, 10, 11} ;
+const int opt_dmas[] = {0, 5, 6, 7} ;
+const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
+				0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
+#endif
+
+#ifdef	MCA
+int	opt_ints[] = {3, 11, 10, 9} ;			/* FM1 */
+int	opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
+#endif	/* MCA */
+
+/*
+ *	xPOS_ID:xxxx
+ *	|	\  /
+ *	|	 \/
+ *	|	  --------------------- the patched POS_ID of the Adapter
+ *	|				xxxx = (Vendor ID low byte,
+ *	|					Vendor ID high byte,
+ *	|					Device ID low byte,
+ *	|					Device ID high byte)
+ *	+------------------------------ the patched oem_id must be
+ *					'S' for SK or 'I' for IBM
+ *					this is a short id for the driver.
+ */
+#ifndef MULT_OEM
+#ifndef	OEM_CONCEPT
+#ifndef MCA
+const u_char oem_id[] = "xPOS_ID:xxxx" ;
+#else
+const u_char oem_id[] = "xPOSID1:xxxx" ;	/* FM1 card id. */
+#endif
+#else	/* OEM_CONCEPT */
+#ifndef MCA
+const u_char oem_id[] = OEM_ID ;
+#else
+const u_char oem_id[] = OEM_ID1 ;	/* FM1 card id. */
+#endif	/* MCA */
+#endif	/* OEM_CONCEPT */
+#define	ID_BYTE0	8
+#define	OEMID(smc,i)	oem_id[ID_BYTE0 + i]
+#else	/* MULT_OEM */
+const struct s_oem_ids oem_ids[] = {
+#include "oemids.h"
+{0}
+};
+#define	OEMID(smc,i)	smc->hw.oem_id->oi_id[i]
+#endif	/* MULT_OEM */
+
+/* Prototypes of external functions */
+extern void hwt_restart() ;
+#ifdef AIX
+extern int AIX_vpdReadByte() ;
+#endif
+
+
+/* Prototypes of local functions. */
+void smt_stop_watchdog() ;
+
+#ifdef MCA
+static int read_card_id() ;
+static void DisableSlotAccess() ;
+static void EnableSlotAccess() ;
+#ifdef AIX
+extern int attach_POS_addr() ;
+extern int detach_POS_addr() ;
+extern u_char read_POS() ;
+extern void write_POS() ;
+extern int AIX_vpdReadByte() ;
+#else
+#define	read_POS(smc,a1,a2)	((u_char) inp(a1))
+#define	write_POS(smc,a1,a2,a3)	outp((a1),(a3))
+#endif
+#endif	/* MCA */
+
+
+/*
+ * FDDI card reset
+ */
+void card_start(smc)
+struct s_smc *smc ;
+{
+	int i ;
+#ifdef	PCI
+	u_char	rev_id ;
+	u_short word;
+#endif
+
+	smt_stop_watchdog(smc) ;
+
+#ifdef	ISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+	for (i = 10 ; i ; i--)			/* delay for PLC's */
+		(void)inpw(ISR_A) ;
+	OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ;
+					/* counter 2, mode 2 */
+	OUT_82c54_TIMER(2,97) ;		/* LSB */
+	OUT_82c54_TIMER(2,0) ;		/* MSB ( 15.6 us ) */
+	outpw(CSR_A,CS_CRESET) ;
+#endif
+#ifdef	EISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+	for (i = 10 ; i ; i--)			/* delay for PLC's */
+		(void)inpw(ISR_A) ;
+	outpw(CSR_A,CS_CRESET) ;
+	smc->hw.led = (2<<6) ;
+	outpw(CSR_A,CS_CRESET | smc->hw.led) ;
+#endif
+#ifdef	MCA
+	outp(ADDR(CARD_DIS),0) ;		/* reset for all chips */
+	for (i = 10 ; i ; i--)			/* delay for PLC's */
+		(void)inpw(ISR_A) ;
+	outp(ADDR(CARD_EN),0) ;
+	/* first I/O after reset must not be a access to FORMAC or PLC */
+
+	/*
+	 * bus timeout (MCA)
+	 */
+	OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ;
+					/* counter 2, mode 3 */
+	OUT_82c54_TIMER(2,(2*24)) ;	/* 3.9 us * 2 square wave */
+	OUT_82c54_TIMER(2,0) ;		/* MSB */
+
+	/* POS 102 indicated an activ Check Line or Buss Error monitoring */
+	if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) {
+		outp(ADDR(IRQ_CHCK_EN),0) ;
+	}
+
+	if (!((i = inpw(CSR_A)) & CS_SAS)) {
+		if (!(i & CS_BYSTAT)) {
+			outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
+		}
+	}
+	outpw(LEDR_A,LED_1) ;	/* yellow */
+#endif	/* MCA */
+#ifdef	PCI
+	/*
+	 * make sure no transfer activity is pending
+	 */
+	outpw(FM_A(FM_MDREG1),FM_MINIT) ;
+	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
+	/*
+	 * now reset everything
+	 */
+	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */
+	i = (int) inp(ADDR(B0_CTRL)) ;		/* do dummy read */
+	SK_UNUSED(i) ;				/* Make LINT happy. */
+	outp(ADDR(B0_CTRL), CTRL_RST_CLR) ;
+
+	/*
+	 * Reset all bits in the PCI STATUS register
+	 */
+	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ;	/* enable for writes */
+	word = inpw(PCI_C(PCI_STATUS)) ;
+	outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ;
+	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ;	/* disable writes */
+
+	/*
+	 * Release the reset of all the State machines
+	 * Release Master_Reset
+	 * Release HPI_SM_Reset
+	 */
+	outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ;
+
+	/*
+	 * determine the adapter type
+	 * Note: Do it here, because some drivers may call card_start() once
+	 *	 at very first before any other initialization functions is
+	 *	 executed.
+	 */
+	rev_id = inp(PCI_C(PCI_REV_ID)) ;
+	if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) {
+		smc->hw.hw_is_64bit = TRUE ;
+	} else {
+		smc->hw.hw_is_64bit = FALSE ;
+	}
+
+	/*
+	 * Watermark initialization
+	 */
+	if (!smc->hw.hw_is_64bit) {
+		outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
+		outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
+		outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
+	}
+
+	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* clear the reset chips */
+	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */
+
+	/* init the timer value for the watch dog 2,5 minutes */
+	outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ;
+
+	/* initialize the ISR mask */
+	smc->hw.is_imask = ISR_MASK ;
+	smc->hw.hw_state = STOPPED ;
+#endif
+	GET_PAGE(0) ;		/* necessary for BOOT */
+}
+
+void card_stop(smc)
+struct s_smc *smc ;
+{
+	smt_stop_watchdog(smc) ;
+	smc->hw.mac_ring_is_up = 0 ;		/* ring down */
+#ifdef	ISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+#endif
+#ifdef	EISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+#endif
+#ifdef	MCA
+	outp(ADDR(CARD_DIS),0) ;		/* reset for all chips */
+#endif
+#ifdef	PCI
+	/*
+	 * make sure no transfer activity is pending
+	 */
+	outpw(FM_A(FM_MDREG1),FM_MINIT) ;
+	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
+	/*
+	 * now reset everything
+	 */
+	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */
+	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* reset for all chips */
+	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */
+	smc->hw.hw_state = STOPPED ;
+#endif
+}
+/*--------------------------- ISR handling ----------------------------------*/
+
+#ifndef PCI
+void mac1_irq(smc,stu, stl)
+struct s_smc *smc ;
+u_short stu;
+u_short stl;
+{
+	int	restart_tx = 0 ;
+again:
+#ifndef ISA
+/*
+ * FORMAC+ bug modified the queue pointer if many read/write accesses happens!?
+ */
+	if (stl & (FM_SPCEPDS  |	/* parit/coding err. syn.q.*/
+		   FM_SPCEPDA0 |	/* parit/coding err. a.q.0 */
+		   FM_SPCEPDA1 |	/* parit/coding err. a.q.1 */
+		   FM_SPCEPDA2)) {	/* parit/coding err. a.q.2 */
+		SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ;
+	}
+	if (stl & (FM_STBURS  |	/* tx buffer underrun syn.q.*/
+		   FM_STBURA0 |	/* tx buffer underrun a.q.0 */
+		   FM_STBURA1 |	/* tx buffer underrun a.q.1 */
+		   FM_STBURA2)) {	/* tx buffer underrun a.q.2 */
+		SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
+	}
+#endif
+	if ( (stu & (FM_SXMTABT |		/* transmit abort */
+#ifdef	SYNC
+		     FM_STXABRS |	/* syn. tx abort */
+#endif	/* SYNC */
+		     FM_STXABRA0)) ||	/* asyn. tx abort */
+	     (stl & (FM_SQLCKS |		/* lock for syn. q. */
+		     FM_SQLCKA0)) ) {	/* lock for asyn. q. */
+		formac_tx_restart(smc) ;		/* init tx */
+		restart_tx = 1 ;
+		stu = inpw(FM_A(FM_ST1U)) ;
+		stl = inpw(FM_A(FM_ST1L)) ;
+		stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
+		if (stu || stl)
+			goto again ;
+	}
+
+#ifndef	SYNC
+	if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */
+		   FM_STEFRMA0)) { /* end of frame asyn tx */
+		/* free tx_queue */
+		smc->hw.n_a_send = 0 ;
+		if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) {
+			start_next_send(smc);
+		}
+		restart_tx = 1 ;
+	}
+#else	/* SYNC */
+	if (stu & (FM_STEFRMA0 |	/* end of asyn tx */
+		    FM_STEFRMS)) {	/* end of sync tx */
+		restart_tx = 1 ;
+	}
+#endif	/* SYNC */
+	if (restart_tx)
+		llc_restart_tx(smc) ;
+}
+#else	/* PCI */
+
+void mac1_irq(smc,stu, stl)
+struct s_smc *smc ;
+u_short stu;
+u_short stl;
+{
+	int	restart_tx = 0 ;
+again:
+
+	/*
+	 * parity error: note encoding error is not possible in tag mode
+	 */
+	if (stl & (FM_SPCEPDS  |	/* parity err. syn.q.*/
+		   FM_SPCEPDA0 |	/* parity err. a.q.0 */
+		   FM_SPCEPDA1)) {	/* parity err. a.q.1 */
+		SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ;
+	}
+	/*
+	 * buffer underrun: can only occur if a tx threshold is specified
+	 */
+	if (stl & (FM_STBURS  |		/* tx buffer underrun syn.q.*/
+		   FM_STBURA0 |		/* tx buffer underrun a.q.0 */
+		   FM_STBURA1)) {	/* tx buffer underrun a.q.2 */
+		SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
+	}
+
+	if ( (stu & (FM_SXMTABT |		/* transmit abort */
+		     FM_STXABRS |		/* syn. tx abort */
+		     FM_STXABRA0)) ||		/* asyn. tx abort */
+	     (stl & (FM_SQLCKS |		/* lock for syn. q. */
+		     FM_SQLCKA0)) ) {		/* lock for asyn. q. */
+		formac_tx_restart(smc) ;	/* init tx */
+		restart_tx = 1 ;
+		stu = inpw(FM_A(FM_ST1U)) ;
+		stl = inpw(FM_A(FM_ST1L)) ;
+		stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
+		if (stu || stl)
+			goto again ;
+	}
+
+	if (stu & (FM_STEFRMA0 |	/* end of asyn tx */
+		    FM_STEFRMS)) {	/* end of sync tx */
+		restart_tx = 1 ;
+	}
+
+	if (restart_tx)
+		llc_restart_tx(smc) ;
+}
+#endif	/* PCI */
+/*
+ * interrupt source= plc1
+ * this function is called in nwfbisr.asm
+ */
+void plc1_irq(smc)
+struct s_smc *smc ;
+{
+	u_short	st = inpw(PLC(PB,PL_INTR_EVENT)) ;
+
+#if	(defined(ISA) || defined(EISA))
+	/* reset PLC Int. bits */
+	outpw(PLC1_I,inpw(PLC1_I)) ;
+#endif
+	plc_irq(smc,PB,st) ;
+}
+
+/*
+ * interrupt source= plc2
+ * this function is called in nwfbisr.asm
+ */
+void plc2_irq(smc)
+struct s_smc *smc ;
+{
+	u_short	st = inpw(PLC(PA,PL_INTR_EVENT)) ;
+
+#if	(defined(ISA) || defined(EISA))
+	/* reset PLC Int. bits */
+	outpw(PLC2_I,inpw(PLC2_I)) ;
+#endif
+	plc_irq(smc,PA,st) ;
+}
+
+
+/*
+ * interrupt source= timer
+ */
+void timer_irq(smc)
+struct s_smc *smc ;
+{
+	hwt_restart(smc);
+	smc->hw.t_stop = smc->hw.t_start;
+	smt_timer_done(smc) ;
+}
+
+/*
+ * return S-port (PA or PB)
+ */
+int pcm_get_s_port(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;
+	return(PS) ;
+}
+
+/*
+ * Station Label = "FDDI-XYZ" where
+ *
+ *	X = connector type
+ *	Y = PMD type
+ *	Z = port type
+ */
+#define STATION_LABEL_CONNECTOR_OFFSET	5
+#define STATION_LABEL_PMD_OFFSET	6
+#define STATION_LABEL_PORT_OFFSET	7
+
+void read_address(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;
+{
+	char ConnectorType ;
+	char PmdType ;
+	int	i ;
+
+	extern const u_char canonical[256] ;
+
+#if	(defined(ISA) || defined(MCA))
+	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+	}
+	for (i = 4; i < 6; i++) {
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+	}
+#endif
+#ifdef	EISA
+	/*
+	 * Note: We get trouble on an Alpha machine if we make a inpw()
+	 * instead of inp()
+	 */
+	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[inp(PR_A(i+SA_MAC))] ;
+	}
+	for (i = 4; i < 6; i++) {
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+	}
+#endif
+#ifdef	PCI
+	for (i = 0; i < 6; i++) {	/* read mac address from board */
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[inp(ADDR(B2_MAC_0+i))] ;
+	}
+#endif
+#ifndef	PCI
+	ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ;
+	PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ;
+#else
+	ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
+	PmdType = inp(ADDR(B2_PMD_TYP)) ;
+#endif
+
+	smc->y[PA].pmd_type[PMD_SK_CONN] =
+	smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
+	smc->y[PA].pmd_type[PMD_SK_PMD ] =
+	smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ;
+
+	if (mac_addr) {
+		for (i = 0; i < 6 ;i++) {
+			smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
+			smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+		}
+		return ;
+	}
+	smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ;
+
+	for (i = 0; i < 6 ;i++) {
+		smc->hw.fddi_canon_addr.a[i] =
+			canonical[smc->hw.fddi_phys_addr.a[i]] ;
+	}
+}
+
+/*
+ * FDDI card soft reset
+ */
+void init_board(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;
+{
+	card_start(smc) ;
+	read_address(smc,mac_addr) ;
+
+#ifndef	PCI
+	if (inpw(CSR_A) & CS_SAS)
+#else
+	if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
+#endif
+		smc->s.sas = SMT_SAS ;	/* Single att. station */
+	else
+		smc->s.sas = SMT_DAS ;	/* Dual att. station */
+
+#ifndef	PCI
+	if (inpw(CSR_A) & CS_BYSTAT)
+#else
+	if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
+#endif
+		smc->mib.fddiSMTBypassPresent = 0 ;
+		/* without opt. bypass */
+	else
+		smc->mib.fddiSMTBypassPresent = 1 ;
+		/* with opt. bypass */
+}
+
+/*
+ * insert or deinsert optical bypass (called by ECM)
+ */
+void sm_pm_bypass_req(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+#if	(defined(ISA) || defined(EISA))
+	int csra_v ;
+#endif
+
+	DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
+					"BP_INSERT" : "BP_DEINSERT",0) ;
+
+	if (smc->s.sas != SMT_DAS)
+		return ;
+
+#if	(defined(ISA) || defined(EISA))
+
+	csra_v = inpw(CSR_A) & ~CS_BYPASS ;
+#ifdef	EISA
+	csra_v |= smc->hw.led ;
+#endif
+
+	switch(mode) {
+	case BP_INSERT :
+		outpw(CSR_A,csra_v | CS_BYPASS) ;
+		break ;
+	case BP_DEINSERT :
+		outpw(CSR_A,csra_v) ;
+		break ;
+	}
+#endif	/* ISA / EISA */
+#ifdef	MCA
+	switch(mode) {
+	case BP_INSERT :
+		outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
+		break ;
+	case BP_DEINSERT :
+		outp(ADDR(BYPASS(STAT_BYP)),0) ;	/* bypass station */
+		break ;
+	}
+#endif
+#ifdef	PCI
+	switch(mode) {
+	case BP_INSERT :
+		outp(ADDR(B0_DAS),DAS_BYP_INS) ;	/* insert station */
+		break ;
+	case BP_DEINSERT :
+		outp(ADDR(B0_DAS),DAS_BYP_RMV) ;	/* bypass station */
+		break ;
+	}
+#endif
+}
+
+/*
+ * check if bypass connected
+ */
+int sm_pm_bypass_present(smc)
+struct s_smc *smc ;
+{
+#ifndef	PCI
+	return(	(inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ;
+#else
+	return(	(inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
+#endif
+}
+
+void plc_clear_irq(smc,p)
+struct s_smc *smc ;
+int p ;
+{
+	SK_UNUSED(p) ;
+
+#if	(defined(ISA) || defined(EISA))
+	switch (p) {
+	case PA :
+		/* reset PLC Int. bits */
+		outpw(PLC2_I,inpw(PLC2_I)) ;
+		break ;
+	case PB :
+		/* reset PLC Int. bits */
+		outpw(PLC1_I,inpw(PLC1_I)) ;
+		break ;
+	}
+#else
+	SK_UNUSED(smc) ;
+#endif
+}
+
+
+/*
+ * led_indication called by rmt_indication() and
+ * pcm_state_change()
+ *
+ * Input:
+ *	smc:	SMT context
+ *	led_event:
+ *	0	Only switch green LEDs according to their respective PCM state
+ *	LED_Y_OFF	just switch yellow LED off
+ *	LED_Y_ON	just switch yello LED on
+ */
+void led_indication(smc,led_event)
+struct s_smc	*smc ;
+int		led_event;
+{
+	/* use smc->hw.mac_ring_is_up == TRUE 
+	 * as indication for Ring Operational
+	 */
+	u_short			led_state ;
+	struct s_phy		*phy ;
+	struct fddi_mib_p	*mib_a ;
+	struct fddi_mib_p	*mib_b ;
+
+	phy = &smc->y[PA] ;
+	mib_a = phy->mib ;
+	phy = &smc->y[PB] ;
+	mib_b = phy->mib ;
+
+#ifdef	EISA
+	/* Ring up = yellow led OFF*/
+	if (led_event == LED_Y_ON) {
+		smc->hw.led |= CS_LED_1 ;
+	}
+	else if (led_event == LED_Y_OFF) {
+		smc->hw.led &= ~CS_LED_1 ;
+	}
+	else {
+		/* Link at Port A or B = green led ON */
+		if (mib_a->fddiPORTPCMState == PC8_ACTIVE ||
+		    mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+			smc->hw.led |= CS_LED_0 ;
+		}
+		else {
+			smc->hw.led &= ~CS_LED_0 ;
+		}
+	}
+#endif
+#ifdef	MCA
+	led_state = inpw(LEDR_A) ;
+	
+	/* Ring up = yellow led OFF*/
+	if (led_event == LED_Y_ON) {
+		led_state |= LED_1 ;
+	}
+	else if (led_event == LED_Y_OFF) {
+		led_state &= ~LED_1 ;
+	}
+	else {
+                led_state &= ~(LED_2|LED_0) ;
+
+		/* Link at Port A = green led A ON */
+		if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {	
+			led_state |= LED_2 ;
+		}
+		
+		/* Link at Port B/S = green led B ON */
+		if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+			led_state |= LED_0 ;
+		}
+	}
+
+        outpw(LEDR_A, led_state) ;
+#endif	/* MCA */
+#ifdef	PCI
+        led_state = 0 ;
+	
+	/* Ring up = yellow led OFF*/
+	if (led_event == LED_Y_ON) {
+		led_state |= LED_MY_ON ;
+	}
+	else if (led_event == LED_Y_OFF) {
+		led_state |= LED_MY_OFF ;
+	}
+	else {	/* PCM state changed */
+		/* Link at Port A/S = green led A ON */
+		if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {	
+			led_state |= LED_GA_ON ;
+		}
+		else {
+			led_state |= LED_GA_OFF ;
+		}
+		
+		/* Link at Port B = green led B ON */
+		if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+			led_state |= LED_GB_ON ;
+		}
+		else {
+			led_state |= LED_GB_OFF ;
+		}
+	}
+
+        outp(ADDR(B0_LED), led_state) ;
+#endif	/* PCI */
+
+}
+
+
+void pcm_state_change(smc,plc,p_state)
+struct s_smc *smc;
+int plc;
+int p_state;
+{
+	/*
+	 * the current implementation of pcm_state_change() in the driver
+	 * parts must be renamed to drv_pcm_state_change() which will be called
+	 * now after led_indication.
+	 */
+	DRV_PCM_STATE_CHANGE(smc,plc,p_state) ;
+	
+	led_indication(smc,0) ;
+}
+
+
+void rmt_indication(smc,i)
+struct s_smc *smc ;
+int i;
+{
+	/* Call a driver special function if defined */
+	DRV_RMT_INDICATION(smc,i) ;
+
+        led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ;
+}
+
+
+/*
+ * llc_recover_tx called by init_tx (fplus.c)
+ */
+void llc_recover_tx(smc)
+struct s_smc *smc ;
+{
+#ifdef	LOAD_GEN
+	extern	int load_gen_flag ;
+
+	load_gen_flag = 0 ;
+#endif
+#ifndef	SYNC
+	smc->hw.n_a_send= 0 ;
+#else
+	SK_UNUSED(smc) ;
+#endif
+}
+
+/*--------------------------- DMA init ----------------------------*/
+#ifdef	ISA
+
+/*
+ * init DMA
+ */
+void init_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * set cascade mode,
+	 * clear mask bit (enable DMA cannal)
+	 */
+	if (dma > 3) {
+		outp(0xd6,(dma & 0x03) | 0xc0) ;
+		outp(0xd4, dma & 0x03) ;
+	}
+	else {
+		outp(0x0b,(dma & 0x03) | 0xc0) ;
+		outp(0x0a,dma & 0x03) ;
+	}
+}
+
+/*
+ * disable DMA
+ */
+void dis_dma(smc,dma)
+struct s_smc *smc ;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * set mask bit (disable DMA cannal)
+	 */
+	if (dma > 3) {
+		outp(0xd4,(dma & 0x03) | 0x04) ;
+	}
+	else {
+		outp(0x0a,(dma & 0x03) | 0x04) ;
+	}
+}
+
+#endif	/* ISA */
+
+#ifdef	EISA
+
+/*arrays with io adresses of dma controller length and adress registers*/
+static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
+static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
+static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
+
+void init_dma(smc,dma)
+struct s_smc *smc ;
+int	dma;
+{
+	/*
+	 * extended mode register
+	 * 32 bit IO
+	 * type c
+	 * TC output
+	 * disable stop
+	 */
+
+	/* mode read (write) demand */
+	smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
+	smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
+
+	/* 32 bit IO's, burst DMA mode (type "C") */
+	smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
+
+	outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
+
+	/* disable chaining */
+	outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
+
+	/*load dma controller addresses for fast access during set dma*/
+	smc->hw.dma_base_word_count = cntr[smc->hw.dma];
+	smc->hw.dma_base_address = base[smc->hw.dma];
+	smc->hw.dma_base_address_page = page[smc->hw.dma];
+
+}
+
+void dis_dma(smc,dma)
+struct s_smc *smc ;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+
+	outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
+}
+#endif	/* EISA */
+
+#ifdef	MCA
+void init_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+void dis_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+#endif
+
+#ifdef	PCI
+void init_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+void dis_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+#endif
+
+#ifdef MULT_OEM
+static int is_equal_num(comp1,comp2,num)
+char comp1[] ;
+char comp2[] ;
+int num ;
+{
+	int i ;
+
+	for (i = 0 ; i < num ; i++) {
+		if (comp1[i] != comp2[i])
+			return (0) ;
+	}
+		return (1) ;
+}	/* is_equal_num */
+
+
+/*
+ * set the OEM ID defaults, and test the contents of the OEM data base
+ * The default OEM is the first ACTIVE entry in the OEM data base 
+ *
+ * returns:	0	success
+ *		1	error in data base
+ *		2	data base empty
+ *		3	no active entry	
+ */
+int set_oi_id_def(smc)
+struct s_smc *smc ;
+{
+	int sel_id ;
+	int i ;
+	int act_entries ;
+
+	i = 0 ;
+	sel_id = -1 ;
+	act_entries = FALSE ;
+	smc->hw.oem_id = 0 ;
+	smc->hw.oem_min_status = OI_STAT_ACTIVE ;
+	
+	/* check OEM data base */
+	while (oem_ids[i].oi_status) {
+		switch (oem_ids[i].oi_status) {
+		case OI_STAT_ACTIVE:
+			act_entries = TRUE ;	/* we have active IDs */
+			if (sel_id == -1)
+				sel_id = i ;	/* save the first active ID */
+		case OI_STAT_VALID:
+		case OI_STAT_PRESENT:
+			i++ ;
+			break ;			/* entry ok */
+		default:
+			return (1) ;		/* invalid oi_status */
+		}
+	}
+
+	if (i == 0)
+		return (2) ;
+	if (!act_entries)
+		return (3) ;
+
+	/* ok, we have a valid OEM data base with an active entry */
+	smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[sel_id] ;
+	return (0) ;
+}
+#endif	/* MULT_OEM */
+
+
+#ifdef	MCA
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	exist_board
+ *
+ *	Check if an MCA board is present in the specified slot.
+ *
+ *	int exist_board(
+ *		struct s_smc *smc,
+ *		int slot) ;
+ * In
+ *	smc - A pointer to the SMT Context struct.
+ *
+ *	slot - The number of the slot to inspect.
+ * Out
+ *	0 = No adapter present.
+ *	1 = Found FM1 adapter.
+ *
+ * Pseudo
+ *      Read MCA ID
+ *	for all valid OEM_IDs
+ *		compare with ID read
+ *		if equal, return 1
+ *	return(0
+ *
+ * Note
+ *	The smc pointer must be valid now.
+ *
+ * END_MANUAL_ENTRY()
+ *
+ ************************/
+#define LONG_CARD_ID(lo, hi)	((((hi) & 0xff) << 8) | ((lo) & 0xff))
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+#ifdef MULT_OEM
+	SK_LOC_DECL(u_char,id[2]) ;
+	int idi ;
+#endif	/* MULT_OEM */
+
+	/* No longer valid. */
+	if (smc == NULL)
+		return(0) ;
+
+#ifndef MULT_OEM
+	if (read_card_id(smc, slot)
+		== LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1)))
+		return (1) ;	/* Found FM adapter. */
+
+#else	/* MULT_OEM */
+	idi = read_card_id(smc, slot) ;
+	id[0] = idi & 0xff ;
+	id[1] = idi >> 8 ;
+
+        smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+
+		if (is_equal_num(&id[0],&OEMID(smc,0),2))
+			return (1) ;
+	}
+#endif	/* MULT_OEM */
+	return (0) ;	/* No adapter found. */
+}
+
+/************************
+ *
+ *	read_card_id
+ *
+ *	Read the MCA card id from the specified slot.
+ * In
+ *	smc - A pointer to the SMT Context struct.
+ *	CAVEAT: This pointer may be NULL and *must not* be used within this
+ *	function. It's only purpose is for drivers that need some information
+ *	for the inp() and outp() macros.
+ *
+ *	slot - The number of the slot for which the card id is returned.
+ * Out
+ *	Returns the card id read from the specified slot. If an illegal slot
+ *	number is specified, the function returns zero.
+ *
+ ************************/
+static int read_card_id(smc,slot)
+struct s_smc *smc ;	/* Do not use. */
+int slot ;
+{
+	int card_id ;
+
+	SK_UNUSED(smc) ;	/* Make LINT happy. */
+	if ((slot < 1) || (slot > 15))	/* max 16 slots, 0 = motherboard */
+		return (0) ;	/* Illegal slot number specified. */
+
+	EnableSlotAccess(smc, slot) ;
+
+	card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) |
+				(read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ;
+
+	DisableSlotAccess(smc) ;
+
+	return (card_id) ;
+}
+
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	get_board_para
+ *
+ *	Get adapter configuration information. Fill all board specific
+ *	parameters within the 'smc' structure.
+ *
+ *	int get_board_para(
+ *		struct s_smc *smc,
+ *		int slot) ;
+ * In
+ *	smc - A pointer to the SMT Context struct, to which this function will
+ *	write some adapter configuration data.
+ *
+ *	slot - The number of the slot, in which the adapter is installed.
+ * Out
+ *	0 = No adapter present.
+ *	1 = Ok.
+ *	2 = Adapter present, but card enable bit not set.
+ *
+ * END_MANUAL_ENTRY()
+ *
+ ************************/
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+	int val ;
+	int i ;
+
+	/* Check if adapter present & get type of adapter. */
+	switch (exist_board(smc, slot)) {
+	case 0:	/* Adapter not present. */
+		return (0) ;
+	case 1:	/* FM Rev. 1 */
+		smc->hw.rev = FM1_REV ;
+		smc->hw.VFullRead = 0x0a ;
+		smc->hw.VFullWrite = 0x05 ;
+		smc->hw.DmaWriteExtraBytes = 8 ;	/* 2 extra words. */
+		break ;
+	}
+	smc->hw.slot = slot ;
+
+	EnableSlotAccess(smc, slot) ;
+
+	if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) {
+		DisableSlotAccess(smc) ;
+		return (2) ;	/* Card enable bit not set. */
+	}
+
+	val = read_POS(smc,POS_104, slot - 1) ;	/* I/O, IRQ */
+
+#ifndef MEM_MAPPED_IO	/* is defined by the operating system */
+	i = val & POS_IOSEL ;	/* I/O base addr. (0x0200 .. 0xfe00) */
+	smc->hw.iop = (i + 1) * 0x0400 - 0x200 ;
+#endif
+	i = ((val & POS_IRQSEL) >> 6) & 0x03 ;	/* IRQ <0, 1> */
+	smc->hw.irq = opt_ints[i] ;
+
+	/* FPROM base addr. */
+	i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ;
+	smc->hw.eprom = opt_eproms[i] ;
+
+	DisableSlotAccess(smc) ;
+
+	/* before this, the smc->hw.iop must be set !!! */
+	smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ;
+
+	return (1) ;
+}
+
+/* Enable access to specified MCA slot. */
+static void EnableSlotAccess(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+	SK_UNUSED(slot) ;
+
+#ifndef AIX
+	SK_UNUSED(smc) ;
+
+	/* System mode. */
+	outp(POS_SYS_SETUP, POS_SYSTEM) ;
+
+	/* Select slot. */
+	outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ;
+#else
+	attach_POS_addr (smc) ;
+#endif
+}
+
+/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */
+static void DisableSlotAccess(smc)
+struct s_smc *smc ;
+{
+#ifndef AIX
+	SK_UNUSED(smc) ;
+
+	outp(POS_CHANNEL_POS, 0) ;
+#else
+	detach_POS_addr (smc) ;
+#endif
+}
+#endif	/* MCA */
+
+#ifdef	EISA
+#ifndef	MEM_MAPPED_IO
+#define	SADDR(slot)	(((slot)<<12)&0xf000)
+#else	/* MEM_MAPPED_IO */
+#define	SADDR(slot)	(smc->hw.iop)
+#endif	/* MEM_MAPPED_IO */
+
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	exist_board
+ *
+ *	Check if an EISA board is present in the specified slot.
+ *
+ *	int exist_board(
+ *		struct s_smc *smc,
+ *		int slot) ;
+ * In
+ *	smc - A pointer to the SMT Context struct.
+ *
+ *	slot - The number of the slot to inspect.
+ * Out
+ *	0 = No adapter present.
+ *	1 = Found adapter.
+ *
+ * Pseudo
+ *      Read EISA ID
+ *	for all valid OEM_IDs
+ *		compare with ID read
+ *		if equal, return 1
+ *	return(0
+ *
+ * Note
+ *	The smc pointer must be valid now.
+ *
+ ************************/
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	int i ;
+#ifdef MULT_OEM
+	SK_LOC_DECL(u_char,id[4]) ;
+#endif	/* MULT_OEM */
+
+	/* No longer valid. */
+	if (smc == NULL)
+		return(0);
+
+	SK_UNUSED(slot) ;
+
+#ifndef MULT_OEM
+	for (i = 0 ; i < 4 ; i++) {
+		if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i))
+			return(0) ;
+	}
+	return(1) ;
+#else	/* MULT_OEM */
+	for (i = 0 ; i < 4 ; i++)
+		id[i] = inp(SADDR(slot)+PRA(i)) ;
+
+	smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+
+		if (is_equal_num(&id[0],&OEMID(smc,0),4))
+			return (1) ;
+	}
+	return (0) ;	/* No adapter found. */
+#endif	/* MULT_OEM */
+}
+
+
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	int	i ;
+
+	if (!exist_board(smc,slot))
+		return(0) ;
+
+	smc->hw.slot = slot ;
+#ifndef	MEM_MAPPED_IO		/* if defined by the operating system */
+	smc->hw.iop = SADDR(slot) ;
+#endif
+
+	if (!(inp(C0_A(0))&CFG_CARD_EN)) {
+		return(2) ;			/* CFG_CARD_EN bit not set! */
+	}
+
+	smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ;
+	smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ;
+
+	if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f)
+		smc->hw.eprom = opt_eproms[i] ;
+	else
+		smc->hw.eprom = 0 ;
+
+	smc->hw.DmaWriteExtraBytes = 8 ;
+
+	return(1) ;
+}
+#endif	/* EISA */
+
+#ifdef	ISA
+#ifndef MULT_OEM
+const u_char sklogo[6] = SKLOGO_STR ;
+#define	SIZE_SKLOGO(smc)	sizeof(sklogo)
+#define	SKLOGO(smc,i)		sklogo[i]
+#else	/* MULT_OEM */
+#define	SIZE_SKLOGO(smc)	smc->hw.oem_id->oi_logo_len
+#define	SKLOGO(smc,i)		smc->hw.oem_id->oi_logo[i]
+#endif	/* MULT_OEM */
+
+
+int exist_board(smc,port)
+struct s_smc *smc ;
+HW_PTR	port ;
+{
+	int	i ;
+#ifdef MULT_OEM
+	int	bytes_read ;
+	u_char	board_logo[15] ;
+	SK_LOC_DECL(u_char,id[4]) ;
+#endif	/* MULT_OEM */
+
+	/* No longer valid. */
+	if (smc == NULL)
+		return(0);
+
+	SK_UNUSED(smc) ;
+#ifndef MULT_OEM
+	for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) {
+		if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) {
+			return(0) ;
+		}
+	}
+
+	/* check MAC address (S&K or other) */
+	for (i = 0 ; i < 3 ; i++) {
+		if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i))
+			return(0) ;
+	}
+	return(1) ;
+#else	/* MULT_OEM */
+        smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[0] ;
+	board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ;
+	bytes_read = 1 ;
+
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+
+		/* Test all read bytes with current OEM_entry */
+		/* for (i=0; (i<bytes_read) && (i < SIZE_SKLOGO(smc)); i++) { */
+		for (i = 0; i < bytes_read; i++) {
+			if (board_logo[i] != SKLOGO(smc,i))
+				break ;
+		}
+
+		/* If mismatch, switch to next OEM entry */
+		if ((board_logo[i] != SKLOGO(smc,i)) && (i < bytes_read))
+			continue ;
+
+		--i ;
+		while (bytes_read < SIZE_SKLOGO(smc)) {
+			//   inpw next byte SK_Logo
+			i++ ;
+			board_logo[i] = (u_char)inpw((PRA(SADDRL+i)+port)) ;
+			bytes_read++ ;
+			if (board_logo[i] != SKLOGO(smc,i))
+				break ;
+		}
+
+		for (i = 0 ; i < 3 ; i++)
+			id[i] = (u_char)inpw((PRA(i)+port)) ;
+
+		if ((board_logo[i] == SKLOGO(smc,i))
+			&& (bytes_read == SIZE_SKLOGO(smc))) {
+
+			if (is_equal_num(&id[0],&OEMID(smc,0),3))
+				return(1);
+		}
+	}	/* for */
+	return(0) ;
+#endif	/* MULT_OEM */
+}
+
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(slot) ;
+	return(0) ;	/* for ISA not supported */
+}
+#endif	/* ISA */
+
+#ifdef PCI
+#ifdef USE_BIOS_FUN
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	u_short dev_id ;
+	u_short ven_id ;
+	int found ; 
+	int i ;
+
+	found = FALSE ;		/* make sure we returned with adatper not found*/
+				/* if an empty oemids.h was included */
+
+#ifdef MULT_OEM
+        smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+#endif
+		ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ; 
+		dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ; 
+		for (i = 0; i < slot; i++) {
+			if (pci_find_device(i,&smc->hw.pci_handle,
+				dev_id,ven_id) != 0) {
+
+				found = FALSE ;
+			} else {
+				found = TRUE ;
+			}
+		}
+		if (found) {
+			return(1) ;	/* adapter was found */
+		}
+#ifdef MULT_OEM
+	}
+#endif
+	return(0) ;	/* adapter was not found */
+}
+#endif	/* PCI */
+#endif	/* USE_BIOS_FUNC */
+
+void driver_get_bia(smc, bia_addr)
+struct s_smc *smc ;
+struct fddi_addr *bia_addr ;
+{
+	int i ;
+
+	extern const u_char canonical[256] ;
+
+	for (i = 0 ; i < 6 ; i++) {
+		bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
+	}
+}
+
+void smt_start_watchdog(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;	/* Make LINT happy. */
+
+#ifndef	DEBUG
+
+#ifdef	PCI
+	if (smc->hw.wdog_used) {
+		outpw(ADDR(B2_WDOG_CRTL),TIM_START) ;	/* Start timer. */
+	}
+#endif
+
+#endif	/* DEBUG */
+}
+
+void smt_stop_watchdog(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;	/* Make LINT happy. */
+#ifndef	DEBUG
+
+#ifdef	PCI
+	if (smc->hw.wdog_used) {
+		outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ;	/* Stop timer. */
+	}
+#endif
+
+#endif	/* DEBUG */
+}
+
+#ifdef	PCI
+static char get_rom_byte(smc,addr)
+struct s_smc *smc ;
+u_short	addr ;
+{
+	GET_PAGE(addr) ;
+	return (READ_PROM(ADDR(B2_FDP))) ;
+}
+
+/*
+ * ROM image defines
+ */
+#define	ROM_SIG_1	0
+#define ROM_SIG_2	1
+#define PCI_DATA_1	0x18
+#define PCI_DATA_2	0x19
+
+/*
+ * PCI data structure defines
+ */
+#define	VPD_DATA_1	0x08
+#define	VPD_DATA_2	0x09
+#define IMAGE_LEN_1	0x10
+#define IMAGE_LEN_2	0x11
+#define	CODE_TYPE	0x14
+#define	INDICATOR	0x15
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
+ *	mac_drv_vpd_read(smc,buf,size,image)
+ *
+ * function	DOWNCALL	(FDDIWARE)
+ *		reads the VPD data of the FPROM and writes it into the
+ *		buffer
+ *
+ * para	buf	points to the buffer for the VPD data
+ *	size	size of the VPD data buffer
+ *	image	boot image; code type of the boot image
+ *		image = 0	Intel x86, PC-AT compatible
+ *			1	OPENBOOT standard for PCI
+ *			2-FF	reserved
+ *
+ * returns	len	number of VPD data bytes read form the FPROM
+ *		<0	number of read bytes
+ *		>0	error: data invalid
+ *
+ *	END_MANUAL_ENTRY
+ */
+int mac_drv_vpd_read(smc,buf,size,image)
+struct s_smc *smc ;
+char *buf ;
+int size ;
+char image ;
+{
+	u_short	ibase ;
+	u_short pci_base ;
+	u_short vpd ;
+	int	len ;
+
+	len = 0 ;
+	ibase = 0 ;
+	/*
+	 * as long images defined
+	 */
+	while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
+		(u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
+		/*
+		 * get the pointer to the PCI data structure
+		 */
+		pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
+				(get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
+
+		if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
+			/*
+			 * we have the right image, read the VPD data
+			 */
+			vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
+				(get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
+			if (vpd == ibase) {
+				break ;		/* no VPD data */
+			}
+			for (len = 0; len < size; len++,buf++,vpd++) {
+				*buf = get_rom_byte(smc,vpd) ;
+			}
+			break ;
+		}
+		else {
+			/*
+			 * try the next image
+			 */
+			if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
+				break ;		/* this was the last image */
+			}
+			ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
+				(get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
+		}
+	}
+
+	return(len) ;
+}
+
+void mac_drv_pci_fix(smc,fix_value)
+struct s_smc *smc ;
+u_long fix_value ;
+{
+	smc->hw.pci_fix_value = fix_value ;
+}
+
+void mac_do_pci_fix(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;
+}
+#endif	/* PCI */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/ecm.c linux/drivers/net/skfp/ecm.c
--- v2.3.46/linux/drivers/net/skfp/ecm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/ecm.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,547 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT ECM
+	Entity Coordination Management
+	Hardware independant state machine
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * 		queue_event()
+ * 		smt_timer_start()
+ * 		smt_timer_stop()
+ *
+ * 	The following external HW dependant functions are referenced :
+ * 		sm_pm_bypass_req()
+ * 		sm_pm_ls_latch()
+ * 		sm_pm_get_ls()
+ * 
+ * 	The following HW dependant events are required :
+ *		NONE
+ *
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)ecm.c	2.7 99/08/05 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG	0x10
+#define GO_STATE(x)	(smc->mib.fddiSMTECMState = (x)|AFLAG)
+#define ACTIONS_DONE()	(smc->mib.fddiSMTECMState &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+#define EC0_OUT		0			/* not inserted */
+#define EC1_IN		1			/* inserted */
+#define EC2_TRACE	2			/* tracing */
+#define EC3_LEAVE	3			/* leaving the ring */
+#define EC4_PATH_TEST	4			/* performing path test */
+#define EC5_INSERT	5			/* bypass being turned on */
+#define EC6_CHECK	6			/* checking bypass */
+#define EC7_DEINSERT	7			/* bypass being turnde off */
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const ecm_states[] = {
+	"EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
+	"EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const ecm_events[] = {
+	"NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
+	"EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
+	"EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
+} ;
+#endif
+
+/*
+ * all Globals  are defined in smc.h
+ * struct s_ecm
+ */
+
+/*
+ * function declarations
+ */
+
+static void ecm_fsm() ;
+static void start_ecm_timer() ;
+static void stop_ecm_timer() ;
+static void prop_actions() ;
+
+/*
+	init ECM state machine
+	clear all ECM vars and flags
+*/
+void ecm_init(smc)
+struct s_smc *smc ;
+{
+	smc->e.path_test = PT_PASSED ;
+	smc->e.trace_prop = 0 ;
+	smc->e.sb_flag = 0 ;
+	smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
+	smc->e.ecm_line_state = FALSE ;
+}
+
+/*
+	ECM state machine
+	called by dispatcher
+
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void ecm(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	int	state ;
+
+	do {
+		DB_ECM("ECM : state %s%s",
+			(smc->mib.fddiSMTECMState & AFLAG) ? "ACTIONS " : "",
+			ecm_states[smc->mib.fddiSMTECMState & ~AFLAG]) ;
+		DB_ECM(" event %s\n",ecm_events[event],0) ;
+		state = smc->mib.fddiSMTECMState ;
+		ecm_fsm(smc,event) ;
+		event = 0 ;
+	} while (state != smc->mib.fddiSMTECMState) ;
+	ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
+}
+
+/*
+	process ECM event
+*/
+static void ecm_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+	int ls_a ;			/* current line state PHY A */
+	int ls_b ;			/* current line state PHY B */
+	int	p ;			/* ports */
+
+
+	smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
+	if (cmd == EC_CONNECT)
+		smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
+
+	/* For AIX event notification: */
+	/* Is a disconnect  command remotely issued ? */
+	if (cmd == EC_DISCONNECT &&
+		smc->mib.fddiSMTRemoteDisconnectFlag == TRUE)
+		AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
+			FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
+			smt_get_error_word(smc) );
+
+	/*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
+	if (cmd == EC_CONNECT) {
+		smc->e.DisconnectFlag = FALSE ;
+	}
+	else if (cmd == EC_DISCONNECT) {
+		smc->e.DisconnectFlag = TRUE ;
+	}
+	
+	switch(smc->mib.fddiSMTECMState) {
+	case ACTIONS(EC0_OUT) :
+		/*
+		 * We do not perform a path test
+		 */
+		smc->e.path_test = PT_PASSED ;
+		smc->e.ecm_line_state = FALSE ;
+		stop_ecm_timer(smc) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC0_OUT:
+		/*EC01*/
+		if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
+			&& smc->e.path_test==PT_PASSED) {
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC05*/
+		else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
+			smc->mib.fddiSMTBypassPresent &&
+			(smc->s.sas == SMT_DAS)) {
+			GO_STATE(EC5_INSERT) ;
+			break ;
+		}
+		break;
+	case ACTIONS(EC1_IN) :
+		stop_ecm_timer(smc) ;
+		smc->e.trace_prop = 0 ;
+		sm_ma_control(smc,MA_TREQ) ;
+		for (p = 0 ; p < NUMPHYS ; p++)
+			if (smc->mib.p[p].fddiPORTHardwarePresent)
+				queue_event(smc,EVENT_PCMA+p,PC_START) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC1_IN:
+		/*EC12*/
+		if (cmd == EC_TRACE_PROP) {
+			prop_actions(smc) ;
+			GO_STATE(EC2_TRACE) ;
+			break ;
+		}
+		/*EC13*/
+		else if (cmd == EC_DISCONNECT) {
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		break;
+	case ACTIONS(EC2_TRACE) :
+		start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
+			EC_TIMEOUT_TMAX) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC2_TRACE :
+		/*EC22*/
+		if (cmd == EC_TRACE_PROP) {
+			prop_actions(smc) ;
+			GO_STATE(EC2_TRACE) ;
+			break ;
+		}
+		/*EC23a*/
+		else if (cmd == EC_DISCONNECT) {
+			smc->e.path_test = PT_EXITING ;
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		/*EC23b*/
+		else if (smc->e.path_test == PT_PENDING) {
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		/*EC23c*/
+		else if (cmd == EC_TIMEOUT_TMAX) {
+			/* Trace_Max is expired */
+			/* -> send AIX_EVENT */
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
+				(u_long) FDDI_SMT_ERROR, (u_long)
+				FDDI_TRACE_MAX, smt_get_error_word(smc));
+			smc->e.path_test = PT_PENDING ;
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC3_LEAVE) :
+		start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
+		for (p = 0 ; p < NUMPHYS ; p++)
+			queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC3_LEAVE:
+		/*EC30*/
+		if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
+			(smc->e.path_test != PT_PENDING)) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC34*/
+		else if (cmd == EC_TIMEOUT_TD &&
+			(smc->e.path_test == PT_PENDING)) {
+			GO_STATE(EC4_PATH_TEST) ;
+			break ;
+		}
+		/*EC31*/
+		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC33*/
+		else if (cmd == EC_DISCONNECT &&
+			smc->e.path_test == PT_PENDING) {
+			smc->e.path_test = PT_EXITING ;
+			/*
+			 * stay in state - state will be left via timeout
+			 */
+		}
+		/*EC37*/
+		else if (cmd == EC_TIMEOUT_TD &&
+			smc->mib.fddiSMTBypassPresent &&
+			smc->e.path_test != PT_PENDING) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC4_PATH_TEST) :
+		stop_ecm_timer(smc) ;
+		smc->e.path_test = PT_TESTING ;
+		start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
+		/* now perform path test ... just a simulation */
+		ACTIONS_DONE() ;
+		break ;
+	case EC4_PATH_TEST :
+		/* path test done delay */
+		if (cmd == EC_TEST_DONE)
+			smc->e.path_test = PT_PASSED ;
+
+		if (smc->e.path_test == PT_FAILED)
+			RS_SET(smc,RS_PATHTEST) ;
+
+		/*EC40a*/
+		if (smc->e.path_test == PT_FAILED &&
+			!smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC40b*/
+		else if (cmd == EC_DISCONNECT &&
+			!smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC41*/
+		else if (smc->e.path_test == PT_PASSED) {
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC47a*/
+		else if (smc->e.path_test == PT_FAILED &&
+			smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		/*EC47b*/
+		else if (cmd == EC_DISCONNECT &&
+			smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC5_INSERT) :
+		sm_pm_bypass_req(smc,BP_INSERT);
+		start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC5_INSERT :
+		/*EC56*/
+		if (cmd == EC_TIMEOUT_INMAX) {
+			GO_STATE(EC6_CHECK) ;
+			break ;
+		}
+		/*EC57*/
+		else if (cmd == EC_DISCONNECT) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC6_CHECK) :
+		/*
+		 * in EC6_CHECK, we *POLL* the line state !
+		 * check whether both bypass switches have switched.
+		 */
+		start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
+		smc->e.ecm_line_state = TRUE ;	/* flag to pcm: report Q/HLS */
+		(void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */
+		(void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */
+		ACTIONS_DONE() ;
+		break ;
+	case EC6_CHECK :
+		ls_a = sm_pm_get_ls(smc,PA) ;
+		ls_b = sm_pm_get_ls(smc,PB) ;
+
+		/*EC61*/
+		if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
+		    ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
+			smc->e.sb_flag = FALSE ;
+			smc->e.ecm_line_state = FALSE ;
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC66*/
+		else if (!smc->e.sb_flag &&
+			 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
+			  ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
+			smc->e.sb_flag = TRUE ;
+			DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ;
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
+				smt_get_error_word(smc));
+		}
+		/*EC67*/
+		else if (cmd == EC_DISCONNECT) {
+			smc->e.ecm_line_state = FALSE ;
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		else {
+			/*
+			 * restart poll
+			 */
+			start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
+		}
+		break ;
+	case ACTIONS(EC7_DEINSERT) :
+		sm_pm_bypass_req(smc,BP_DEINSERT);
+		start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC7_DEINSERT:
+		/*EC70*/
+		if (cmd == EC_TIMEOUT_IMAX) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC75*/
+		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
+			GO_STATE(EC5_INSERT) ;
+			break ;
+		}
+		break;
+	default:
+		SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
+		break;
+	}
+}
+
+#ifndef	CONCENTRATOR
+/*
+ * trace propagation actions for SAS & DAS
+ */
+static void prop_actions(smc)
+struct s_smc *smc ;
+{
+	int	port_in ;
+	int	port_out ;
+
+	RS_SET(smc,RS_EVENT) ;
+	switch (smc->s.sas) {
+	case SMT_SAS :
+		port_in = port_out = pcm_get_s_port(smc) ;
+		break ;
+	case SMT_DAS :
+		port_in = cfm_get_mac_input(smc) ;	/* PA or PB */
+		port_out = cfm_get_mac_output(smc) ;	/* PA or PB */
+		break ;
+	case SMT_NAC :
+		SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
+		return ;
+	}
+
+	DB_ECM("ECM : prop_actions - trace_prop %d\n", smc->e.trace_prop,0) ;
+	DB_ECM("ECM : prop_actions - in %d out %d\n", port_in,port_out) ;
+
+	if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
+		/* trace initiatior */
+		DB_ECM("ECM : initiate TRACE on PHY %c\n",'A'+port_in-PA,0) ;
+		queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
+	}
+	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
+		port_out != PA) {
+		/* trace propagate upstream */
+		DB_ECM("ECM : propagate TRACE on PHY B\n",0,0) ;
+		queue_event(smc,EVENT_PCMB,PC_TRACE) ;
+	}
+	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
+		port_out != PB) {
+		/* trace propagate upstream */
+		DB_ECM("ECM : propagate TRACE on PHY A\n",0,0) ;
+		queue_event(smc,EVENT_PCMA,PC_TRACE) ;
+	}
+	else {
+		/* signal trace termination */
+		DB_ECM("ECM : TRACE terminated\n",0,0) ;
+		smc->e.path_test = PT_PENDING ;
+	}
+	smc->e.trace_prop = 0 ;
+}
+#else
+/*
+ * trace propagation actions for Concentrator
+ */
+static void prop_actions(smc)
+struct s_smc *smc ;
+{
+	int	initiator ;
+	int	upstream ;
+	int	p ;
+
+	RS_SET(smc,RS_EVENT) ;
+	while (smc->e.trace_prop) {
+		DB_ECM("ECM : prop_actions - trace_prop %d\n",
+			smc->e.trace_prop,0) ;
+
+		if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
+			initiator = ENTITY_MAC ;
+			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
+			DB_ECM("ECM: MAC initiates trace\n",0,0) ;
+		}
+		else {
+			for (p = NUMPHYS-1 ; p >= 0 ; p--) {
+				if (smc->e.trace_prop &
+					ENTITY_BIT(ENTITY_PHY(p)))
+					break ;
+			}
+			initiator = ENTITY_PHY(p) ;
+			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
+		}
+		upstream = cem_get_upstream(smc,initiator) ;
+
+		if (upstream == ENTITY_MAC) {
+			/* signal trace termination */
+			DB_ECM("ECM : TRACE terminated\n",0,0) ;
+			smc->e.path_test = PT_PENDING ;
+		}
+		else {
+			/* trace propagate upstream */
+			DB_ECM("ECM : propagate TRACE on PHY %d\n",upstream,0) ;
+			queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
+		}
+	}
+}
+#endif
+
+
+/*
+ * SMT timer interface
+ *	start ECM timer
+ */
+static void start_ecm_timer(smc,value,event)
+struct s_smc *smc ;
+u_long value;
+int event ;
+{
+	smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
+}
+
+/*
+ * SMT timer interface
+ *	stop ECM timer
+ */
+static void stop_ecm_timer(smc)
+struct s_smc *smc ;
+{
+	if (smc->e.ecm_timer.tm_active)
+		smt_timer_stop(smc,&smc->e.ecm_timer) ;
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/ess.c linux/drivers/net/skfp/ess.c
--- v2.3.46/linux/drivers/net/skfp/ess.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/ess.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,732 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * *******************************************************************
+ * This SBA code implements the Synchronous Bandwidth Allocation
+ * functions described in the "FDDI Synchronous Forum Implementer's
+ * Agreement" dated December 1th, 1993.
+ * *******************************************************************
+ *
+ *	PURPOSE: The purpose of this function is to control
+ *		 synchronous allocations on a single FDDI segment.
+ *		 Allocations are limited to the primary FDDI ring.
+ *		 The SBM provides recovery mechanisms to recover
+ *		 unused bandwidth also resolves T_Neg and
+ *		 reconfiguration changes. Many of the SBM state
+ *		 machine inputs are sourced by the underlying
+ *		 FDDI sub-system supporting the SBA application.
+ *
+ * *******************************************************************
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+
+#ifndef	SLIM_SMT
+
+#ifdef ESS
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)ess.c	1.10 96/02/23 (C) SK" ;
+#define LINT_USE(x)
+#else
+#define LINT_USE(x)	(x)=(x)
+#endif
+#define MS2BCLK(x)	((x)*12500L)
+
+/*
+	-------------------------------------------------------------
+	LOCAL VARIABLES:
+	-------------------------------------------------------------
+*/
+
+static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F,
+					SMT_P3210, SMT_P0019, SMT_P001A,
+					SMT_P001D, 0 } ;
+
+static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210,
+					SMT_P001A, 0 } ;
+
+static const struct fddi_addr smt_sba_da = {0x80,0x01,0x43,0x00,0x80,0x0C} ;
+static const struct fddi_addr null_addr = {0,0,0,0,0,0} ;
+
+/*
+	-------------------------------------------------------------
+	GLOBAL VARIABLES:
+	-------------------------------------------------------------
+*/
+
+
+/*
+	-------------------------------------------------------------
+	LOCAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+static	void	ess_send_response(),		ess_config_fifo(),
+		ess_send_alc_req(),		ess_send_frame() ;
+
+/*
+	-------------------------------------------------------------
+	EXTERNAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+extern	void	*sm_to_para() ;
+
+extern	void	smt_send_frame(),	smt_free_mbuf(),
+		set_formac_tsync(),	formac_reinit_tx() ;
+
+extern	int	smt_check_para() ;
+
+extern	SMbuf	*smt_get_mbuf(),	*smt_build_frame() ;
+
+extern	u_long	smt_get_tid() ;
+
+/*
+	-------------------------------------------------------------
+	PUBLIC FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+	void	ess_timer_poll(),		ess_para_change() ;
+
+	int	ess_raf_received_pack(),	process_bw_alloc() ;
+
+
+/*
+ * --------------------------------------------------------------------------
+ *	End Station Support	(ESS)
+ * --------------------------------------------------------------------------
+ */
+
+/*
+ * evaluate the RAF frame
+ */
+int ess_raf_received_pack(smc,mb,sm,fs)
+struct s_smc *smc ;
+SMbuf *mb ;
+struct smt_header *sm ;
+int fs ;
+{
+	void			*p ;		/* universal pointer */
+	struct smt_p_0016	*cmd ;		/* para: command for the ESS */
+	SMbuf			*db ;
+	u_long			msg_res_type ;	/* recource type */
+	u_long			payload, overhead ;
+	int			local ;
+	int			i ;
+
+	/*
+	 * Message Processing Code
+	 */
+	 local = ((fs & L_INDICATOR) != 0) ;
+
+	/*
+	 * get the resource type
+	 */
+	if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) {
+		DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ;
+		return(fs) ;
+	}
+	msg_res_type = ((struct smt_p_0015 *)p)->res_type ;
+
+	/*
+	 * get the pointer to the ESS command
+	 */
+	if (!(cmd = (struct smt_p_0016 *) sm_to_para(smc,sm,SMT_P0016))) {
+		/*
+		 * error in frame: para ESS command was not found
+		 */
+		 DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0);
+		 return(fs) ;
+	}
+
+	DB_ESSN(2,"fc %x	ft %x\n",sm->smt_class,sm->smt_type) ;
+	DB_ESSN(2,"ver %x	tran %lx\n",sm->smt_version,sm->smt_tid) ;
+	DB_ESSN(2,"stn_id %s\n",addr_to_string(&sm->smt_source),0) ;
+
+	DB_ESSN(2,"infolen %x	res %x\n",sm->smt_len, msg_res_type) ;
+	DB_ESSN(2,"sbacmd %x\n",cmd->sba_cmd,0) ;
+
+	/*
+	 * evaluate the ESS command
+	 */
+	switch (cmd->sba_cmd) {
+
+	/*
+	 * Process an ESS Allocation Request
+	 */
+	case REQUEST_ALLOCATION :
+		/*
+		 * check for an RAF Request (Allocation Request)
+		 */
+		if (sm->smt_type == SMT_REQUEST) {
+			/*
+			 * process the Allocation request only if the frame is
+			 * local and no static allocation is used
+			 */
+			if (!local || smc->mib.fddiESSPayload)
+				return(fs) ;
+			
+			p = (void *) sm_to_para(smc,sm,SMT_P0019)  ;
+			for (i = 0; i < 5; i++) {
+				if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) {
+					return(fs) ;
+				}
+			}
+
+			/*
+			 * Note: The Application should send a LAN_LOC_FRAME.
+			 *	 The ESS do not send the Frame to the network!
+			 */
+			smc->ess.alloc_trans_id = sm->smt_tid ;
+			DB_ESS("ESS: save Alloc Req Trans ID %lx\n",sm->smt_tid,0);
+			p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+			((struct smt_p_320f *)p)->mib_payload =
+				smc->mib.a[PATH0].fddiPATHSbaPayload ;
+			p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+			((struct smt_p_3210 *)p)->mib_overhead =
+				smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+			sm->smt_dest = smt_sba_da ;
+
+			if (smc->ess.local_sba_active)
+				return(fs | I_INDICATOR) ;
+
+			if (!(db = smt_get_mbuf(smc)))
+				return(fs) ;
+
+			db->sm_len = mb->sm_len ;
+			db->sm_off = mb->sm_off ;
+			memcpy(((char *)(db->sm_data+db->sm_off)),(char *)sm,
+				(int)db->sm_len) ;
+			dump_smt(smc,
+				(struct smt_header *)(db->sm_data+db->sm_off),
+				"RAF") ;
+			smt_send_frame(smc,db,FC_SMT_INFO,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * The RAF frame is an Allocation Response !
+		 * check the parameters
+		 */
+		if (smt_check_para(smc,sm,plist_raf_alc_res)) {
+			DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * VERIFY THE FRAME IS WELL BUILT:
+		 *
+		 *	1. path index = primary ring only
+		 *	2. resource type = sync bw only
+		 *	3. trans action id = alloc_trans_id
+		 *	4. reason code = success
+		 *
+		 * If any are violated, discard the RAF frame
+		 */
+		if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index
+			!= PRIMARY_RING) ||
+			(msg_res_type != SYNC_BW) ||
+		(((struct smt_p_reason *)sm_to_para(smc,sm,SMT_P0012))->rdf_reason
+			!= SMT_RDF_SUCCESS) ||
+			(sm->smt_tid != smc->ess.alloc_trans_id)) {
+
+			DB_ESS("ESS: Allocation Responce not accepted\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * Extract message parameters
+		 */
+		p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+		payload = ((struct smt_p_320f *)p)->mib_payload ;
+		p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+		overhead = ((struct smt_p_3210 *)p)->mib_overhead ;
+
+		DB_ESSN(2,"payload= %lx	overhead= %lx\n",payload,overhead) ;
+
+		/*
+		 * process the bandwidth allocation
+		 */
+		(void)process_bw_alloc(smc,(long)payload,(long)overhead) ;
+
+		return(fs) ;
+		/* end of Process Allocation Request */
+
+	/*
+	 * Process an ESS Change Request
+	 */
+	case CHANGE_ALLOCATION :
+		/*
+		 * except only replies
+		 */
+		if (sm->smt_type != SMT_REQUEST) {
+			DB_ESS("ESS: Do not process Change Responses\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * check the para for the Change Request
+		 */
+		if (smt_check_para(smc,sm,plist_raf_chg_req)) {
+			DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * Verify the path index and resource
+		 * type are correct. If any of
+		 * these are false, don't process this
+		 * change request frame.
+		 */
+		if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index
+			!= PRIMARY_RING) || (msg_res_type != SYNC_BW)) {
+			DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * Extract message queue parameters
+		 */
+		p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+		payload = ((struct smt_p_320f *)p)->mib_payload ;
+		p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+		overhead = ((struct smt_p_3210 *)p)->mib_overhead ;
+
+		DB_ESSN(2,"ESS: Change Request from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		DB_ESSN(2,"payload= %lx	overhead= %lx\n",payload,overhead) ;
+
+		/*
+		 * process the bandwidth allocation
+		 */
+		if(!process_bw_alloc(smc,(long)payload,(long)overhead))
+			return(fs) ;
+
+		/*
+		 * send an RAF Change Reply
+		 */
+		ess_send_response(smc,sm,CHANGE_ALLOCATION) ;
+
+		return(fs) ;
+		/* end of Process Change Request */
+
+	/*
+	 * Process Report Response
+	 */
+	case REPORT_ALLOCATION :
+		/*
+		 * except only requests
+		 */
+		if (sm->smt_type != SMT_REQUEST) {
+			DB_ESS("ESS: Do not process a Report Reply\n",0,0) ;
+			return(fs) ;
+		}
+
+		DB_ESSN(2,"ESS: Report Request from %s\n",
+			addr_to_string(&(sm->smt_source)),0) ;
+
+		/*
+		 * verify that the resource type is sync bw only
+		 */
+		if (msg_res_type != SYNC_BW) {
+			DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * send an RAF Change Reply
+		 */
+		ess_send_response(smc,sm,REPORT_ALLOCATION) ;
+
+		return(fs) ;
+		/* end of Process Report Request */
+
+	default:
+		/*
+		 * error in frame
+		 */
+		DB_ESS("ESS: ignoring RAF with bad sba_cmd\n",0,0) ;
+		break ;
+	}
+
+	return(fs) ;
+}
+
+/*
+ * determines the synchronous bandwidth, set the TSYNC register and the
+ * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
+ */
+int process_bw_alloc(smc,payload,overhead)
+struct s_smc *smc ;
+long payload ;
+long overhead ;
+{
+	/*
+	 * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
+	 * if the payload is greater than zero.
+	 * For the SBAPayload and the SBAOverhead we have the following
+	 * unite quations
+ 	 *		      _		  _
+	 *		     |	     bytes |
+	 *	SBAPayload = | 8000 ------ |
+	 *		     |		s  |
+	 *		      -		  -
+ 	 *		       _       _
+	 *		      |	 bytes	|
+	 *	SBAOverhead = | ------	|
+	 *		      |	 T-NEG	|
+	 *		       -       -
+ 	 *
+	 * T-NEG is discribed by the equation:
+	 *
+	 *		     (-) fddiMACT-NEG
+	 *	T-NEG =	    -------------------
+	 *			12500000 1/s
+	 *
+	 * The number of bytes we are able to send is the payload
+	 * plus the overhead.
+	 *
+	 *			  bytes    T-NEG SBAPayload 8000 bytes/s
+	 * sync_bw =  SBAOverhead ------ + -----------------------------
+	 *	   		  T-NEG		T-NEG
+	 *
+	 *
+	 *	      		     1
+	 * sync_bw =  SBAOverhead + ---- (-)fddiMACT-NEG * SBAPayload
+	 *	       		    1562
+	 *
+	 */
+
+	/*
+	 * set the mib attributes fddiPATHSbaOverhead, fddiPATHSbaPayload
+	 */
+/*	if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) {
+		DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ;
+		return(FALSE) ;
+	}
+	if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) {
+		DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ;
+		return(FALSE) ;
+	} */
+
+	/* premliminary */
+	if (payload > MAX_PAYLOAD || overhead > 5000) {
+		DB_ESS("ESS: payload / overhead not accepted\n",0,0) ;
+		return(FALSE) ;
+	}
+
+	/*
+	 * start the iterative allocation process if the payload or the overhead
+	 * are smaller than the parsed values
+	 */
+	if (smc->mib.fddiESSPayload &&
+		((u_long)payload != smc->mib.fddiESSPayload ||
+		(u_long)overhead != smc->mib.fddiESSOverhead)) {
+		smc->ess.raf_act_timer_poll = TRUE ;
+		smc->ess.timer_count = 0 ;
+	}
+
+	/*
+	 * evulate the Payload
+	 */
+	if (payload) {
+		DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit on\n",0,0) ;
+		smc->ess.sync_bw_available = TRUE ;
+
+		smc->ess.sync_bw = overhead -
+			(long)smc->mib.m[MAC0].fddiMACT_Neg *
+			payload / 1562 ;
+	}
+	else {
+		DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit off\n",0,0) ;
+		smc->ess.sync_bw_available = FALSE ;
+		smc->ess.sync_bw = 0 ;
+		overhead = 0 ;
+	}
+
+	smc->mib.a[PATH0].fddiPATHSbaPayload = payload ;
+	smc->mib.a[PATH0].fddiPATHSbaOverhead = overhead ;
+
+
+	DB_ESSN(2,"tsync = %lx\n",smc->ess.sync_bw,0) ;
+
+	ess_config_fifo(smc) ;
+	set_formac_tsync(smc,smc->ess.sync_bw) ;
+	return(TRUE) ;
+}
+
+static void ess_send_response(smc,sm,sba_cmd)
+struct s_smc *smc ;
+struct smt_header *sm ;
+int sba_cmd ;
+{
+	struct smt_sba_chg	*chg ;
+	SMbuf			*mb ;
+	void			*p ;
+
+	/*
+	 * get and initialize the responce frame
+	 */
+	if (sba_cmd == CHANGE_ALLOCATION) {
+		if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY,
+				sizeof(struct smt_sba_chg))))
+				return ;
+	}
+	else {
+		if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY,
+				sizeof(struct smt_sba_rep_res))))
+				return ;
+	}
+
+	chg = smtod(mb,struct smt_sba_chg *) ;
+	chg->smt.smt_tid = sm->smt_tid ;
+	chg->smt.smt_dest = sm->smt_source ;
+
+	/* set P15 */
+	chg->s_type.para.p_type = SMT_P0015 ;
+	chg->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ;
+	chg->s_type.res_type = SYNC_BW ;
+
+	/* set P16 */
+	chg->cmd.para.p_type = SMT_P0016 ;
+	chg->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ;
+	chg->cmd.sba_cmd = sba_cmd ;
+
+	/* set P320B */
+	chg->path.para.p_type = SMT_P320B ;
+	chg->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ;
+	chg->path.mib_index = SBAPATHINDEX ;
+	chg->path.path_pad = (u_short)NULL ;
+	chg->path.path_index = PRIMARY_RING ;
+
+	/* set P320F */
+	chg->payload.para.p_type = SMT_P320F ;
+	chg->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ;
+	chg->payload.mib_index = SBAPATHINDEX ;
+	chg->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+	/* set P3210 */
+	chg->overhead.para.p_type = SMT_P3210 ;
+	chg->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ;
+	chg->overhead.mib_index = SBAPATHINDEX ;
+	chg->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+	if (sba_cmd == CHANGE_ALLOCATION) {
+		/* set P1A */
+		chg->cat.para.p_type = SMT_P001A ;
+		chg->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ;
+		p = (void *) sm_to_para(smc,sm,SMT_P001A) ;
+		chg->cat.category = ((struct smt_p_001a *)p)->category ;
+	}
+	dump_smt(smc,(struct smt_header *)chg,"RAF") ;
+	ess_send_frame(smc,mb) ;
+}
+
+
+void ess_timer_poll(smc)
+struct s_smc *smc ;
+{
+	if (!smc->ess.raf_act_timer_poll)
+		return ;
+
+	DB_ESSN(2,"ESS: timer_poll\n",0,0) ;
+
+	smc->ess.timer_count++ ;
+	if (smc->ess.timer_count == 10) {
+		smc->ess.timer_count = 0 ;
+		ess_send_alc_req(smc) ;
+	}
+}
+
+static void ess_send_alc_req(smc)
+struct s_smc *smc ;
+{
+	struct smt_sba_alc_req *req ;
+	SMbuf	*mb ;
+
+	/*
+	 * send never allocation request where the requested payload and
+	 * overhead is zero or deallocate bandwidht when no bandwidth is
+	 * parsed
+	 */
+	if (!smc->mib.fddiESSPayload) {
+		smc->mib.fddiESSOverhead = 0 ;
+	}
+	else {
+		if (!smc->mib.fddiESSOverhead)
+			smc->mib.fddiESSOverhead = DEFAULT_OV ;
+	}
+
+	if (smc->mib.fddiESSOverhead ==
+		smc->mib.a[PATH0].fddiPATHSbaOverhead &&
+		smc->mib.fddiESSPayload ==
+		smc->mib.a[PATH0].fddiPATHSbaPayload){
+		smc->ess.raf_act_timer_poll = FALSE ;
+		smc->ess.timer_count = 7 ;	/* next RAF alc req after 3 s */
+		return ;
+	}
+	
+	/*
+	 * get and initialize the responce frame
+	 */
+	if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST,
+			sizeof(struct smt_sba_alc_req))))
+			return ;
+	req = smtod(mb,struct smt_sba_alc_req *) ;
+	req->smt.smt_tid = smc->ess.alloc_trans_id = smt_get_tid(smc) ;
+	req->smt.smt_dest = smt_sba_da ;
+
+	/* set P15 */
+	req->s_type.para.p_type = SMT_P0015 ;
+	req->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ;
+	req->s_type.res_type = SYNC_BW ;
+
+	/* set P16 */
+	req->cmd.para.p_type = SMT_P0016 ;
+	req->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ;
+	req->cmd.sba_cmd = REQUEST_ALLOCATION ;
+
+	/*
+	 * set the parameter type and parameter lenght of all used
+	 * parameters
+	 */
+
+	/* set P320B */
+	req->path.para.p_type = SMT_P320B ;
+	req->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ;
+	req->path.mib_index = SBAPATHINDEX ;
+	req->path.path_pad = (u_short)NULL ;
+	req->path.path_index = PRIMARY_RING ;
+
+	/* set P0017 */
+	req->pl_req.para.p_type = SMT_P0017 ;
+	req->pl_req.para.p_len = sizeof(struct smt_p_0017) - PARA_LEN ;
+	req->pl_req.sba_pl_req = smc->mib.fddiESSPayload -
+		smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+	/* set P0018 */
+	req->ov_req.para.p_type = SMT_P0018 ;
+	req->ov_req.para.p_len = sizeof(struct smt_p_0018) - PARA_LEN ;
+	req->ov_req.sba_ov_req = smc->mib.fddiESSOverhead -
+		smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+	/* set P320F */
+	req->payload.para.p_type = SMT_P320F ;
+	req->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ;
+	req->payload.mib_index = SBAPATHINDEX ;
+	req->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+	/* set P3210 */
+	req->overhead.para.p_type = SMT_P3210 ;
+	req->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ;
+	req->overhead.mib_index = SBAPATHINDEX ;
+	req->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+	/* set P19 */
+	req->a_addr.para.p_type = SMT_P0019 ;
+	req->a_addr.para.p_len = sizeof(struct smt_p_0019) - PARA_LEN ;
+	req->a_addr.sba_pad = (u_short)NULL ;
+	req->a_addr.alloc_addr = null_addr ;
+
+	/* set P1A */
+	req->cat.para.p_type = SMT_P001A ;
+	req->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ;
+	req->cat.category = smc->mib.fddiESSCategory ;
+
+	/* set P1B */
+	req->tneg.para.p_type = SMT_P001B ;
+	req->tneg.para.p_len = sizeof(struct smt_p_001b) - PARA_LEN ;
+	req->tneg.max_t_neg = smc->mib.fddiESSMaxTNeg ;
+
+	/* set P1C */
+	req->segm.para.p_type = SMT_P001C ;
+	req->segm.para.p_len = sizeof(struct smt_p_001c) - PARA_LEN ;
+	req->segm.min_seg_siz = smc->mib.fddiESSMinSegmentSize ;
+
+	dump_smt(smc,(struct smt_header *)req,"RAF") ;
+	ess_send_frame(smc,mb) ;
+}
+
+static void ess_send_frame(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+	/*
+	 * check if the frame must be send to the own ESS
+	 */
+	if (smc->ess.local_sba_active) {
+		/*
+		 * Send the Change Reply to the local SBA
+		 */
+		DB_ESS("ESS:Send to the local SBA\n",0,0) ;
+		if (!smc->ess.sba_reply_pend)
+			smc->ess.sba_reply_pend = mb ;
+		else {
+			DB_ESS("Frame is lost - another frame was pending\n",0,0);
+			smt_free_mbuf(smc,mb) ;
+		}
+	}
+	else {
+		/*
+		 * Send the SBA RAF Change Reply to the network
+		 */
+		DB_ESS("ESS:Send to the network\n",0,0) ;
+		smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
+	}
+}
+
+void ess_para_change(smc)
+struct s_smc *smc ;
+{
+	(void)process_bw_alloc(smc,(long)smc->mib.a[PATH0].fddiPATHSbaPayload,
+		(long)smc->mib.a[PATH0].fddiPATHSbaOverhead) ;
+}
+
+static void ess_config_fifo(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * if nothing to do exit 
+	 */
+	if (smc->mib.a[PATH0].fddiPATHSbaPayload) {
+		if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON &&
+			(smc->hw.fp.fifo.fifo_config_mode&SEND_ASYNC_AS_SYNC) ==
+			smc->mib.fddiESSSynchTxMode) {
+			return ;
+		}
+	}
+	else {
+		if (!(smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON)) {
+			return ;
+		}
+	}
+
+	/*
+	 * split up the FIFO and reinitialize the queues
+	 */
+	formac_reinit_tx(smc) ;
+}
+
+#endif /* ESS */
+
+#endif	/* no SLIM_SMT */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/fplustm.c linux/drivers/net/skfp/fplustm.c
--- v2.3.46/linux/drivers/net/skfp/fplustm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/fplustm.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,1645 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FORMAC+ Driver for tag mode
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "can.c"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)fplustm.c	1.32 99/02/23 (C) SK " ;
+#endif
+
+#ifndef UNUSED
+#ifdef  lint
+#define UNUSED(x)	(x) = (x)
+#else
+#define UNUSED(x)
+#endif
+#endif
+
+#define FM_ADDRX	 (FM_ADDET|FM_EXGPA0|FM_EXGPA1)
+#define MS2BCLK(x)	((x)*12500L)
+#define US2BCLK(x)	((x)*1250L)
+
+/*
+ * prototypes for static function
+ */
+static void build_claim_beacon() ;
+static int init_mac() ;
+static void rtm_init() ;
+static void smt_split_up_fifo() ;
+
+#if (!defined(NO_SMT_PANIC) || defined(DEBUG))
+static	char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n";
+static	char cam_warning [] = "E_SMT_004: CAM still busy\n";
+#endif
+
+#define	DUMMY_READ()	smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP))
+
+#define	CHECK_NPP() {	unsigned k = 10000 ;\
+			while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\
+			if (!k) { \
+				SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \
+			}	\
+		}
+
+#define	CHECK_CAM() {	unsigned k = 10 ;\
+			while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\
+			if (!k) { \
+				SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \
+			}	\
+		}
+
+const struct fddi_addr fddi_broadcast = {0xff,0xff,0xff,0xff,0xff,0xff};
+static const struct fddi_addr null_addr = {0,0,0,0,0,0} ;
+static const struct fddi_addr dbeacon_multi = {0x01,0x80,0xc2,0x00,0x01,0x00};
+
+static const u_short my_said = 0xffff ;	/* short address (n.u.) */
+static const u_short my_sagp = 0xffff ;	/* short group address (n.u.) */
+
+/*
+ * define my address
+ */
+#ifdef	USE_CAN_ADDR
+#define MA	smc->hw.fddi_canon_addr
+#else
+#define MA	smc->hw.fddi_home_addr
+#endif
+
+
+/*
+ * usefull interrupt bits
+ */
+static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ;
+static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0|
+			FM_STBURS | FM_STBURA0 ;
+
+	/* delete FM_SRBFL after tests */
+static int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL |
+			FM_SMYCLM ;
+static int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR |
+			FM_SERRCTR | FM_SLSTCTR |
+			FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ;
+
+static int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ;
+static int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ;
+
+static int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC |
+			FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ;
+
+
+static u_long mac_get_tneg(smc)
+struct s_smc *smc ;
+{
+	u_long	tneg ;
+
+	tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ;
+	return((u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) |
+		0xffe00000L)) ;
+}
+
+void mac_update_counter(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACFrame_Ct =
+		(smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L)
+		+ (u_short) inpw(FM_A(FM_FCNTR)) ;
+	smc->mib.m[MAC0].fddiMACLost_Ct =
+		(smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L)
+		+ (u_short) inpw(FM_A(FM_LCNTR)) ;
+	smc->mib.m[MAC0].fddiMACError_Ct =
+		(smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L)
+		+ (u_short) inpw(FM_A(FM_ECNTR)) ;
+	smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ;
+#ifdef SMT_REAL_TOKEN_CT
+	/*
+	 * If the token counter is emulated it is updated in smt_event.
+	 */
+	TBD
+#else
+	smt_emulate_token_ct( smc, MAC0 );
+#endif
+}
+
+/*
+ * write long value into buffer memory over memory data register (MDR),
+ */
+void	write_mdr(smc,val)
+struct s_smc *smc ;
+u_long val;
+{
+	CHECK_NPP() ;
+	MDRW(val) ;
+}
+
+/*
+ * read long value from buffer memory over memory data register (MDR),
+ */
+u_long read_mdr(smc,addr)
+struct s_smc *smc ;
+unsigned int addr;
+{
+	long p ;
+	CHECK_NPP() ;
+	MARR(addr) ;
+	outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ;
+	CHECK_NPP() ;	/* needed for PCI to prevent from timeing violations */
+/*	p = MDRR() ; */	/* bad read values if the workaround */
+			/* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/
+			/* is used */
+	p = (u_long)inpw(FM_A(FM_MDRU))<<16 ;
+	p += (u_long)inpw(FM_A(FM_MDRL)) ;
+	return(p) ;
+}
+/*
+ * clear buffer memory
+ */
+static void init_ram(smc)
+struct s_smc *smc ;
+{
+	u_short i ;
+
+	smc->hw.fp.fifo.rbc_ram_start = 0 ;
+	smc->hw.fp.fifo.rbc_ram_end =
+		smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ;
+	CHECK_NPP() ;
+	MARW(smc->hw.fp.fifo.rbc_ram_start) ;
+	for (i = smc->hw.fp.fifo.rbc_ram_start;
+		i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++)
+		write_mdr(smc,0L) ;
+	/* Erase the last byte too */
+	write_mdr(smc,0L) ;
+}
+
+/*
+ * set receive FIFO pointer
+ */
+static void set_recvptr(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * initialize the pointer for receive queue 1
+	 */
+	outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ;	/* RPR1 */
+	outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ;	/* SWPR1 */
+	outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ;	/* WPR1 */
+	outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ;	/* EARV1 */
+
+	/*
+	 * initialize the pointer for receive queue 2
+	 */
+	if (smc->hw.fp.fifo.rx2_fifo_size) {
+		outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+		outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+		outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+		outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+	}
+	else {
+		outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+		outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+		outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+		outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+	}
+}
+
+/*
+ * set transmit FIFO pointer
+ */
+static void set_txptr(smc)
+struct s_smc *smc ;
+{
+	outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ;	/* reset transmit queues */
+
+	/*
+	 * initialize the pointer for asynchronous transmit queue
+	 */
+	outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ;	/* RPXA0 */
+	outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ;	/* SWPXA0 */
+	outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ;	/* WPXA0 */
+	outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ;	/* EAA0 */
+
+	/*
+	 * initialize the pointer for synchronous transmit queue
+	 */
+	if (smc->hw.fp.fifo.tx_s_size) {
+		outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ;
+		outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ;
+		outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ;
+		outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ;
+	}
+	else {
+		outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+		outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+		outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+		outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ;
+	}
+}
+
+/*
+ * init memory buffer management registers
+ */
+static void init_rbc(smc)
+struct s_smc *smc ;
+{
+	u_short	rbc_ram_addr ;
+
+	/*
+	 * set unused pointers or permanent pointers
+	 */
+	rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ;
+
+	outpw(FM_A(FM_RPXA1),rbc_ram_addr) ;	/* a1-send pointer */
+	outpw(FM_A(FM_WPXA1),rbc_ram_addr) ;
+	outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ;
+	outpw(FM_A(FM_EAA1),rbc_ram_addr) ;
+
+	set_recvptr(smc) ;
+	set_txptr(smc) ;
+}
+
+/*
+ * init rx pointer
+ */
+static void init_rx(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_rx_queue	*queue ;
+
+	/*
+	 * init all tx data structures for receive queue 1
+	 */
+	smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ;
+	queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ;
+	queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ;
+
+	/*
+	 * init all tx data structures for receive queue 2
+	 */
+	smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ;
+	queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ;
+	queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ;
+}
+
+/*
+ * set the TSYNC register of the FORMAC to regulate synchronous transmission
+ */
+void set_formac_tsync(smc,sync_bw)
+struct s_smc *smc ;
+long sync_bw ;
+{
+	outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ;
+}
+
+/*
+ * init all tx data structures
+ */
+static void init_tx(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_tx_queue	*queue ;
+
+	/*
+	 * init all tx data structures for the synchronous queue
+	 */
+	smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ;
+	queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ;
+	queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ;
+
+#ifdef ESS
+	set_formac_tsync(smc,smc->ess.sync_bw) ;
+#endif
+
+	/*
+	 * init all tx data structures for the asynchronous queue 0
+	 */
+	smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ;
+	queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ;
+	queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ;
+
+
+	llc_recover_tx(smc) ;
+}
+
+static void mac_counter_init(smc)
+struct s_smc *smc ;
+{
+	int i ;
+	u_long *ec ;
+
+	/*
+	 * clear FORMAC+ frame-, lost- and error counter
+	 */
+	outpw(FM_A(FM_FCNTR),0) ;
+	outpw(FM_A(FM_LCNTR),0) ;
+	outpw(FM_A(FM_ECNTR),0) ;
+	/*
+	 * clear internal error counter stucture
+	 */
+	ec = (u_long *)&smc->hw.fp.err_stats ;
+	for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--)
+		*ec++ = 0L ;
+	smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ;
+}
+
+/*
+ * set FORMAC address, and t_request
+ */
+static	void set_formac_addr(smc)
+struct s_smc *smc ;
+{
+	long	t_requ = smc->mib.m[MAC0].fddiMACT_Req ;
+
+	outpw(FM_A(FM_SAID),my_said) ;	/* set short address */
+	outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) +
+					smc->hw.fddi_home_addr.a[5])) ;
+	outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) +
+					smc->hw.fddi_home_addr.a[3])) ;
+	outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) +
+					smc->hw.fddi_home_addr.a[1])) ;
+
+	outpw(FM_A(FM_SAGP),my_sagp) ;	/* set short group address */
+
+	outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) +
+					smc->hw.fp.group_addr.a[5])) ;
+	outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) +
+					smc->hw.fp.group_addr.a[3])) ;
+	outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) +
+					smc->hw.fp.group_addr.a[1])) ;
+
+	/* set r_request regs. (MSW & LSW of TRT ) */
+	outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ;
+	outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ;
+}
+
+void set_long(p,l)
+char *p;
+long l;
+{
+	p[0] = (char)(l >> 24) ;
+	p[1] = (char)(l >> 16) ;
+	p[2] = (char)(l >> 8) ;
+	p[3] = (char)(l >> 0) ;
+}
+
+/*
+ * copy TX descriptor to buffer mem
+ * append FC field and MAC frame
+ * if more bit is set in descr
+ *	append pointer to descriptor (endless loop)
+ * else
+ *	append 'end of chain' pointer
+ */
+static void copy_tx_mac(smc,td,mac,off,len)
+struct s_smc *smc ;
+u_long td;		/* transmit descriptor */
+struct fddi_mac *mac;	/* mac frame pointer */
+unsigned off;		/* start address within buffer memory */
+int len ;		/* lenght of the frame including the FC */
+{
+	int	i ;
+	u_long	*p ;
+
+	CHECK_NPP() ;
+	MARW(off) ;		/* set memory address reg for writes */
+
+	p = (u_long *) mac ;
+	for (i = (len + 3)/4 ; i ; i--) {
+		if (i == 1) {
+			/* last word, set the tag bit */
+			outpw(FM_A(FM_CMDREG2),FM_ISTTB) ;
+		}
+		write_mdr(smc,MDR_REVERSE(*p)) ;
+		p++ ;
+	}
+
+	outpw(FM_A(FM_CMDREG2),FM_ISTTB) ;	/* set the tag bit */
+	write_mdr(smc,td) ;	/* write over memory data reg to buffer */
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(module;tests;3)
+	How to test directed beacon frames
+	----------------------------------------------------------------
+
+	o Insert a break point in the function build_claim_beacon()
+	  before calling copy_tx_mac() for building the claim frame.
+	o Modify the RM3_DETECT case so that the RM6_DETECT state
+	  will always entered from the RM3_DETECT state (function rmt_fsm(),
+	  rmt.c)
+	o Compile the driver.
+	o Set the parameter TREQ in the protocol.ini or net.cfg to a
+	  small value to make sure your station will win the claim
+	  process.
+	o Start the driver.
+	o When you reach the break point, modify the SA and DA address
+	  of the claim frame (e.g. SA = DA = 10005affffff).
+	o When you see RM3_DETECT and RM6_DETECT, observe the direct
+	  beacon frames on the UPPSLANA.
+
+	END_MANUAL_ENTRY
+ */
+static void directed_beacon(smc)
+struct s_smc *smc ;
+{
+	SK_LOC_DECL(u_long,a[2]) ;
+
+	/*
+	 * set UNA in frame
+	 * enable FORMAC to send endless queue of directed beacon
+	 * important: the UNA starts at byte 1 (not at byte 0)
+	 */
+	* (char *) a = (char) ((long)DBEACON_INFO<<24L) ;
+	a[1] = 0 ;
+	memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ;
+
+	CHECK_NPP() ;
+	 /* set memory address reg for writes */
+	MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ;
+	write_mdr(smc,MDR_REVERSE(a[0])) ;
+	outpw(FM_A(FM_CMDREG2),FM_ISTTB) ;	/* set the tag bit */
+	write_mdr(smc,MDR_REVERSE(a[1])) ;
+
+	outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ;
+}
+
+/*
+	setup claim & beacon pointer
+	NOTE :
+		special frame packets end with a pointer to their own
+		descriptor, and the MORE bit is set in the descriptor
+*/
+static void build_claim_beacon(smc,t_request)
+struct s_smc *smc ;
+u_long t_request;
+{
+	u_long	td ;
+	int	len ;
+	struct fddi_mac_sf *mac ;
+
+	/*
+	 * build claim packet
+	 */
+	len = 17 ;
+	td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ;
+	mac = &smc->hw.fp.mac_sfb ;
+	mac->mac_fc = FC_CLAIM ;
+	/* DA == SA in claim frame */
+	mac->mac_source = mac->mac_dest = MA ;
+	/* 2's complement */
+	set_long((char *)mac->mac_info,(long)t_request) ;
+
+	copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+		smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ;
+	/* set CLAIM start pointer */
+	outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ;
+
+	/*
+	 * build beacon packet
+	 */
+	len = 17 ;
+	td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ;
+	mac->mac_fc = FC_BEACON ;
+	mac->mac_source = MA ;
+	mac->mac_dest = null_addr ;		/* DA == 0 in beacon frame */
+	set_long((char *) mac->mac_info,((long)BEACON_INFO<<24L) + 0 ) ;
+
+	copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+		smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ;
+	/* set beacon start pointer */
+	outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ;
+
+	/*
+	 * build directed beacon packet
+	 * contains optional UNA
+	 */
+	len = 23 ;
+	td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ;
+	mac->mac_fc = FC_BEACON ;
+	mac->mac_source = MA ;
+	mac->mac_dest = dbeacon_multi ;		/* multicast */
+	set_long((char *) mac->mac_info,((long)DBEACON_INFO<<24L) + 0 ) ;
+	set_long((char *) mac->mac_info+4,0L) ;
+	set_long((char *) mac->mac_info+8,0L) ;
+
+	copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+		smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF,len) ;
+
+	/* end of claim/beacon queue */
+	outpw(FM_A(FM_EACB),smc->hw.fp.fifo.rx1_fifo_start-1) ;
+
+	outpw(FM_A(FM_WPXSF),0) ;
+	outpw(FM_A(FM_RPXSF),0) ;
+}
+
+void formac_rcv_restart(smc)
+struct s_smc *smc ;
+{
+	/* enable receive function */
+	SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ;
+
+	outpw(FM_A(FM_CMDREG1),FM_ICLLR) ;	/* clear receive lock */
+}
+
+void formac_tx_restart(smc)
+struct s_smc *smc ;
+{
+	outpw(FM_A(FM_CMDREG1),FM_ICLLS) ;	/* clear s-frame lock */
+	outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ;	/* clear a-frame lock */
+}
+
+static void enable_formac(smc)
+struct s_smc *smc ;
+{
+	/* set formac IMSK : 0 enables irq */
+	outpw(FM_A(FM_IMSK1U),~mac_imsk1u) ;
+	outpw(FM_A(FM_IMSK1L),~mac_imsk1l) ;
+	outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ;
+	outpw(FM_A(FM_IMSK2L),~mac_imsk2l) ;
+	outpw(FM_A(FM_IMSK3U),~mac_imsk3u) ;
+	outpw(FM_A(FM_IMSK3L),~mac_imsk3l) ;
+}
+
+#if 0	/* Removed because the driver should use the ASICs TX complete IRQ. */
+	/* The FORMACs tx complete IRQ should be used any longer */
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;4)
+
+	void enable_tx_irq(smc, queue)
+	struct s_smc *smc ;
+	u_short	queue ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		enable_tx_irq() enables the FORMACs transmit complete
+		interrupt of the queue.
+
+Para	queue	= QUEUE_S:	synchronous queue
+		= QUEUE_A0:	asynchronous queue
+
+Note	After any ring operational change the transmit complete
+	interrupts are disabled.
+	The operating system dependent module must enable
+	the transmit complete interrupt of a queue,
+		- when it queues the first frame,
+		  because of no transmit resources are beeing
+		  available and
+		- when it escapes from the function llc_restart_tx
+		  while some frames are still queued.
+
+	END_MANUAL_ENTRY
+ */
+void enable_tx_irq(smc, queue)
+struct s_smc *smc ;
+u_short	queue ;		/* 0 = synchronous queue, 1 = asynchronous queue 0 */
+{
+	u_short	imask ;
+
+	imask = ~(inpw(FM_A(FM_IMSK1U))) ;
+
+	if (queue == 0) {
+		outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMS)) ;
+	}
+	if (queue == 1) {
+		outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMA0)) ;
+	}
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;4)
+
+	void disable_tx_irq(smc, queue)
+	struct s_smc *smc ;
+	u_short	queue ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		disable_tx_irq disables the FORMACs transmit complete
+		interrupt of the queue
+
+Para	queue	= QUEUE_S:	synchronous queue
+		= QUEUE_A0:	asynchronous queue
+
+Note	The operating system dependent module should disable
+	the transmit complete interrupts if it escapes from the
+	function llc_restart_tx and no frames are queued.
+
+	END_MANUAL_ENTRY
+ */
+void disable_tx_irq(smc, queue)
+struct s_smc *smc ;
+u_short	queue ;		/* 0 = synchronous queue, 1 = asynchronous queue 0 */
+{
+	u_short	imask ;
+
+	imask = ~(inpw(FM_A(FM_IMSK1U))) ;
+
+	if (queue == 0) {
+		outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMS)) ;
+	}
+	if (queue == 1) {
+		outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMA0)) ;
+	}
+}
+#endif
+
+static void disable_formac(smc)
+struct s_smc *smc ;
+{
+	/* clear formac IMSK : 1 disables irq */
+	outpw(FM_A(FM_IMSK1U),MW) ;
+	outpw(FM_A(FM_IMSK1L),MW) ;
+	outpw(FM_A(FM_IMSK2U),MW) ;
+	outpw(FM_A(FM_IMSK2L),MW) ;
+	outpw(FM_A(FM_IMSK3U),MW) ;
+	outpw(FM_A(FM_IMSK3L),MW) ;
+}
+
+
+static void mac_ring_up(smc,up)
+struct s_smc *smc ;
+int up;
+{
+	if (up) {
+		formac_rcv_restart(smc) ;	/* enable receive function */
+		smc->hw.mac_ring_is_up = TRUE ;
+		llc_restart_tx(smc) ;		/* TX queue */
+	}
+	else {
+		/* disable receive function */
+		SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ;
+
+		/* abort current transmit activity */
+		outpw(FM_A(FM_CMDREG2),FM_IACTR) ;
+
+		smc->hw.mac_ring_is_up = FALSE ;
+	}
+}
+
+/*--------------------------- ISR handling ----------------------------------*/
+/*
+ * mac1_irq is in drvfbi.c
+ */
+
+/*
+ * mac2_irq:	status bits for the receive queue 1, and ring status
+ * 		ring status indication bits
+ */
+void mac2_irq(smc,code_s2u,code_s2l)
+struct s_smc *smc ;
+u_short code_s2u ;
+u_short code_s2l ;
+{
+	u_short	change_s2l ;
+	u_short	change_s2u ;
+
+	/* (jd) 22-Feb-1999
+	 * Restart 2_DMax Timer after end of claiming or beaconing
+	 */
+	if (code_s2u & (FM_SCLM|FM_SHICLM|FM_SBEC|FM_SOTRBEC)) {
+		queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ;
+	}
+	else if (code_s2l & (FM_STKISS)) {
+		queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ;
+	}
+
+	/*
+	 * XOR current st bits with the last to avoid useless RMT event queuing
+	 */
+	change_s2l = smc->hw.fp.s2l ^ code_s2l ;
+	change_s2u = smc->hw.fp.s2u ^ code_s2u ;
+
+	if ((change_s2l & FM_SRNGOP) ||
+		(!smc->hw.mac_ring_is_up && ((code_s2l & FM_SRNGOP)))) {
+		if (code_s2l & FM_SRNGOP) {
+			mac_ring_up(smc,1) ;
+			queue_event(smc,EVENT_RMT,RM_RING_OP) ;
+			smc->mib.m[MAC0].fddiMACRingOp_Ct++ ;
+		}
+		else {
+			mac_ring_up(smc,0) ;
+			queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ;
+		}
+		goto mac2_end ;
+	}
+	if (code_s2l & FM_SMISFRM) {	/* missed frame */
+		smc->mib.m[MAC0].fddiMACNotCopied_Ct++ ;
+	}
+	if (code_s2u & (FM_SRCVOVR |	/* recv. FIFO overflow */
+			FM_SRBFL)) {	/* recv. buffer full */
+		smc->hw.mac_ct.mac_r_restart_counter++ ;
+/*		formac_rcv_restart(smc) ;	*/
+		smt_stat_counter(smc,1) ;
+/*		goto mac2_end ;			*/
+	}
+	if (code_s2u & FM_SOTRBEC)
+		queue_event(smc,EVENT_RMT,RM_OTHER_BEACON) ;
+	if (code_s2u & FM_SMYBEC)
+		queue_event(smc,EVENT_RMT,RM_MY_BEACON) ;
+	if (change_s2u & code_s2u & FM_SLOCLM) {
+		DB_RMTN(2,"RMT : lower claim received\n",0,0) ;
+	}
+	if ((code_s2u & FM_SMYCLM) && !(code_s2l & FM_SDUPCLM)) {
+		/*
+		 * This is my claim and that claim is not detected as a
+		 * duplicate one.
+		 */
+		queue_event(smc,EVENT_RMT,RM_MY_CLAIM) ;
+	}
+	if (code_s2l & FM_SDUPCLM) {
+		/*
+		 * If a duplicate claim frame (same SA but T_Bid != T_Req)
+		 * this flag will be set.
+		 * In the RMT state machine we need a RM_VALID_CLAIM event
+		 * to do the appropriate state change.
+		 * RM(34c)
+		 */
+		queue_event(smc,EVENT_RMT,RM_VALID_CLAIM) ;
+	}
+	if (change_s2u & code_s2u & FM_SHICLM) {
+		DB_RMTN(2,"RMT : higher claim received\n",0,0) ;
+	}
+	if ( (code_s2l & FM_STRTEXP) ||
+	     (code_s2l & FM_STRTEXR) )
+		queue_event(smc,EVENT_RMT,RM_TRT_EXP) ;
+	if (code_s2l & FM_SMULTDA) {
+		/*
+		 * The MAC has found a 2. MAC with the same address.
+		 * Signal dup_addr_test = failed to RMT state machine.
+		 * RM(25)
+		 */
+		smc->r.dup_addr_test = DA_FAILED ;
+		queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+	}
+	if (code_s2u & FM_SBEC)
+		smc->hw.fp.err_stats.err_bec_stat++ ;
+	if (code_s2u & FM_SCLM)
+		smc->hw.fp.err_stats.err_clm_stat++ ;
+	if (code_s2l & FM_STVXEXP)
+		smc->mib.m[MAC0].fddiMACTvxExpired_Ct++ ;
+	if ((code_s2u & (FM_SBEC|FM_SCLM))) {
+		if (!(change_s2l & FM_SRNGOP) && (smc->hw.fp.s2l & FM_SRNGOP)) {
+			mac_ring_up(smc,0) ;
+			queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ;
+
+			mac_ring_up(smc,1) ;
+			queue_event(smc,EVENT_RMT,RM_RING_OP) ;
+			smc->mib.m[MAC0].fddiMACRingOp_Ct++ ;
+		}
+	}
+	if (code_s2l & FM_SPHINV)
+		smc->hw.fp.err_stats.err_phinv++ ;
+	if (code_s2l & FM_SSIFG)
+		smc->hw.fp.err_stats.err_sifg_det++ ;
+	if (code_s2l & FM_STKISS)
+		smc->hw.fp.err_stats.err_tkiss++ ;
+	if (code_s2l & FM_STKERR)
+		smc->hw.fp.err_stats.err_tkerr++ ;
+	if (code_s2l & FM_SFRMCTR)
+		smc->mib.m[MAC0].fddiMACFrame_Ct += 0x10000L ;
+	if (code_s2l & FM_SERRCTR)
+		smc->mib.m[MAC0].fddiMACError_Ct += 0x10000L ;
+	if (code_s2l & FM_SLSTCTR)
+		smc->mib.m[MAC0].fddiMACLost_Ct  += 0x10000L ;
+	if (code_s2u & FM_SERRSF) {
+		SMT_PANIC(smc,SMT_E0114, SMT_E0114_MSG) ;
+	}
+mac2_end:
+	/* notice old status */
+	smc->hw.fp.s2l = code_s2l ;
+	smc->hw.fp.s2u = code_s2u ;
+	outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ;
+}
+
+/*
+ * mac3_irq:	receive queue 2 bits and address detection bits
+ */
+void mac3_irq(smc,code_s3u,code_s3l)
+struct s_smc *smc ;
+u_short code_s3u ;
+u_short code_s3l ;
+{
+	UNUSED(code_s3l) ;
+
+	if (code_s3u & (FM_SRCVOVR2 |	/* recv. FIFO overflow */
+			FM_SRBFL2)) {	/* recv. buffer full */
+		smc->hw.mac_ct.mac_r_restart_counter++ ;
+		smt_stat_counter(smc,1);
+	}
+
+
+	if (code_s3u & FM_SRPERRQ2) {	/* parity error receive queue 2 */
+		SMT_PANIC(smc,SMT_E0115, SMT_E0115_MSG) ;
+	}
+	if (code_s3u & FM_SRPERRQ1) {	/* parity error receive queue 2 */
+		SMT_PANIC(smc,SMT_E0116, SMT_E0116_MSG) ;
+	}
+}
+
+
+/*
+ * take formac offline
+ */
+static void formac_offline(smc)
+struct s_smc *smc ;
+{
+	outpw(FM_A(FM_CMDREG2),FM_IACTR) ;/* abort current transmit activity */
+
+	/* disable receive function */
+	SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ;
+
+	/* FORMAC+ 'Initialize Mode' */
+	SETMASK(FM_A(FM_MDREG1),FM_MINIT,FM_MMODE) ;
+
+	disable_formac(smc) ;
+	smc->hw.mac_ring_is_up = FALSE ;
+	smc->hw.hw_state = STOPPED ;
+}
+
+/*
+ * bring formac online
+ */
+static void formac_online(smc)
+struct s_smc *smc ;
+{
+	enable_formac(smc) ;
+	SETMASK(FM_A(FM_MDREG1),FM_MONLINE | FM_SELRA | MDR1INIT |
+		smc->hw.fp.rx_mode, FM_MMODE | FM_SELRA | FM_ADDRX) ;
+}
+
+/*
+ * FORMAC+ full init. (tx, rx, timer, counter, claim & beacon)
+ */
+int init_fplus(smc)
+struct s_smc *smc ;
+{
+	smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ;
+	smc->hw.fp.rx_mode = FM_MDAMA ;
+	smc->hw.fp.group_addr = fddi_broadcast ;
+	smc->hw.fp.func_addr = 0 ;
+	smc->hw.fp.frselreg_init = 0 ;
+
+	init_driver_fplus(smc) ;
+	if (smc->s.sas == SMT_DAS)
+		smc->hw.fp.mdr3init |= FM_MENDAS ;
+
+	smc->hw.mac_ct.mac_nobuf_counter = 0 ;
+	smc->hw.mac_ct.mac_r_restart_counter = 0 ;
+
+	smc->hw.fp.fm_st1u = (HW_PTR) ADDR(B0_ST1U) ;
+	smc->hw.fp.fm_st1l = (HW_PTR) ADDR(B0_ST1L) ;
+	smc->hw.fp.fm_st2u = (HW_PTR) ADDR(B0_ST2U) ;
+	smc->hw.fp.fm_st2l = (HW_PTR) ADDR(B0_ST2L) ;
+	smc->hw.fp.fm_st3u = (HW_PTR) ADDR(B0_ST3U) ;
+	smc->hw.fp.fm_st3l = (HW_PTR) ADDR(B0_ST3L) ;
+
+	smc->hw.fp.s2l = smc->hw.fp.s2u = 0 ;
+	smc->hw.mac_ring_is_up = 0 ;
+
+	mac_counter_init(smc) ;
+
+	/* convert BCKL units to symbol time */
+	smc->hw.mac_pa.t_neg = (u_long)0 ;
+	smc->hw.mac_pa.t_pri = (u_long)0 ;
+
+	/* make sure all PCI settings are correct */
+	mac_do_pci_fix(smc) ;
+
+	return(init_mac(smc,1)) ;
+	/* enable_formac(smc) ; */
+}
+
+static int init_mac(smc,all)
+struct s_smc *smc ;
+int all ;
+{
+	u_short	t_max,x ;
+	u_long	time=0 ;
+
+	/*
+	 * clear memory
+	 */
+	outpw(FM_A(FM_MDREG1),FM_MINIT) ;	/* FORMAC+ init mode */
+	set_formac_addr(smc) ;
+	outpw(FM_A(FM_MDREG1),FM_MMEMACT) ;	/* FORMAC+ memory activ mode */
+	/* Note: Mode register 2 is set here, incase parity is enabled. */
+	outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ;
+
+	if (all) {
+		init_ram(smc) ;
+	}
+	else {
+		/*
+		 * reset the HPI, the Master and the BMUs
+		 */
+		outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+		time = hwt_quick_read(smc) ;
+	}
+
+	/*
+	 * set all pointers, frames etc
+	 */
+	smt_split_up_fifo(smc) ;
+
+	init_tx(smc) ;
+	init_rx(smc) ;
+	init_rbc(smc) ;
+
+	build_claim_beacon(smc,smc->mib.m[MAC0].fddiMACT_Req) ;
+
+	/* set RX threshold */
+	/* see Errata #SN2 Phantom receive overflow */
+	outpw(FM_A(FM_FRMTHR),14<<12) ;		/* switch on */
+
+	/* set formac work mode */
+	outpw(FM_A(FM_MDREG1),MDR1INIT | FM_SELRA | smc->hw.fp.rx_mode) ;
+	outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ;
+	outpw(FM_A(FM_MDREG3),smc->hw.fp.mdr3init) ;
+	outpw(FM_A(FM_FRSELREG),smc->hw.fp.frselreg_init) ;
+
+	/* set timer */
+	/*
+	 * errata #22 fplus:
+	 * T_MAX must not be FFFE
+	 * or one of FFDF, FFB8, FF91 (-0x27 etc..)
+	 */
+	t_max = (u_short)(smc->mib.m[MAC0].fddiMACT_Max/32) ;
+	x = t_max/0x27 ;
+	x *= 0x27 ;
+	if ((t_max == 0xfffe) || (t_max - x == 0x16))
+		t_max-- ;
+	outpw(FM_A(FM_TMAX),(u_short)t_max) ;
+
+	/* BugFix for report #10204 */
+	if (smc->mib.m[MAC0].fddiMACTvxValue < (u_long) (- US2BCLK(52))) {
+		outpw(FM_A(FM_TVX), (u_short) (- US2BCLK(52))/255 & MB) ;
+	} else {
+		outpw(FM_A(FM_TVX),
+			(u_short)((smc->mib.m[MAC0].fddiMACTvxValue/255) & MB)) ;
+	}
+
+	outpw(FM_A(FM_CMDREG1),FM_ICLLS) ;	/* clear s-frame lock */
+	outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ;	/* clear a-frame lock */
+	outpw(FM_A(FM_CMDREG1),FM_ICLLR);	/* clear receive lock */
+
+	/* Auto unlock receice threshold for receive queue 1 and 2 */
+	outpw(FM_A(FM_UNLCKDLY),(0xff|(0xff<<8))) ;
+
+	rtm_init(smc) ;				/* RT-Monitor */
+
+	if (!all) {
+		/*
+		 * after 10ms, reset the BMUs and repair the rings
+		 */
+		hwt_wait_time(smc,time,MS2BCLK(10)) ;
+		outpd(ADDR(B0_R1_CSR),CSR_SET_RESET) ;
+		outpd(ADDR(B0_XA_CSR),CSR_SET_RESET) ;
+		outpd(ADDR(B0_XS_CSR),CSR_SET_RESET) ;
+		outp(ADDR(B0_CTRL), CTRL_HPI_CLR) ;
+		outpd(ADDR(B0_R1_CSR),CSR_CLR_RESET) ;
+		outpd(ADDR(B0_XA_CSR),CSR_CLR_RESET) ;
+		outpd(ADDR(B0_XS_CSR),CSR_CLR_RESET) ;
+		if (!smc->hw.hw_is_64bit) {
+			outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
+			outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
+			outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
+		}
+		smc->hw.hw_state = STOPPED ;
+		mac_drv_repair_descr(smc) ;
+	}
+	smc->hw.hw_state = STARTED ;
+
+	return(0) ;
+}
+
+
+/*
+ * called by CFM
+ */
+void config_mux(smc,mux)
+struct s_smc *smc ;
+int mux;
+{
+	plc_config_mux(smc,mux) ;
+
+	SETMASK(FM_A(FM_MDREG1),FM_SELRA,FM_SELRA) ;
+}
+
+/*
+ * called by RMT
+ * enable CLAIM/BEACON interrupts
+ * (only called if these events are of interest, e.g. in DETECT state
+ * the interrupt must not be permanently enabled
+ * RMT calls this function periodically (timer driven polling)
+ */
+void sm_mac_check_beacon_claim(smc)
+struct s_smc *smc ;
+{
+	/* set formac IMSK : 0 enables irq */
+	outpw(FM_A(FM_IMSK2U),~(mac_imsk2u | mac_beacon_imsk2u)) ;
+	/* the driver must receive the directed beacons */
+	formac_rcv_restart(smc) ;
+	process_receive(smc) ;
+}
+
+/*-------------------------- interface functions ----------------------------*/
+/*
+ * control ODL output
+ */
+void sm_pm_control(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * if PCM logic has set LS_REQUEST = Transmit QUIET Line State
+	 *	/FOTOFF signal turn activ -> ODL disable
+	 */
+	switch(mode) {
+	case PM_TRANSMIT_DISABLE :
+		break ;
+	case PM_TRANSMIT_ENABLE :
+		break ;
+	}
+}
+
+/*
+ * control MAC layer	(called by RMT)
+ */
+void sm_ma_control(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+	switch(mode) {
+	case MA_OFFLINE :
+		/* Add to make the MAC offline in RM0_ISOLATED state */
+		formac_offline(smc) ;
+		break ;
+	case MA_RESET :
+		(void)init_mac(smc,0) ;
+		break ;
+	case MA_BEACON :
+		formac_online(smc) ;
+		break ;
+	case MA_DIRECTED :
+		directed_beacon(smc) ;
+		break ;
+	case MA_TREQ :
+		/*
+		 * no actions necessary, TREQ is already set
+		 */
+		break ;
+	}
+}
+
+int sm_mac_get_tx_state(smc)
+struct s_smc *smc ;
+{
+	return((inpw(FM_A(FM_STMCHN))>>4)&7) ;
+}
+
+/*
+ * multicast functions
+ */
+
+static struct s_fpmc	*mac_get_mc_table(smc,user,own,del,can)
+struct s_smc *smc ;
+struct fddi_addr *user ;
+struct fddi_addr *own ;
+int del ;
+int can ;
+{
+	struct s_fpmc	*tb ;
+	struct s_fpmc	*slot ;
+	u_char	*p ;
+	int i ;
+
+	/*
+	 * set own = can(user)
+	 */
+	*own = *user ;
+	if (can) {
+		p = own->a ;
+		for (i = 0 ; i < 6 ; i++, p++)
+			*p = canonical[*p] ;
+	}
+	slot = 0 ;
+	for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
+		if (!tb->n) {		/* not used */
+			if (!del && !slot)	/* if !del save first free */
+				slot = tb ;
+			continue ;
+		}
+		if (memcmp((char *)&tb->a,(char *)own,6))
+			continue ;
+		return(tb) ;
+	}
+	return(slot) ;			/* return first free or NULL */
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	void mac_clear_multicast(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Clear all multicast entries
+
+	END_MANUAL_ENTRY()
+ */
+void mac_clear_multicast(smc)
+struct s_smc *smc ;
+{
+	struct s_fpmc	*tb ;
+	int i ;
+
+	smc->hw.fp.os_slots_used = 0 ;	/* note the SMT addresses */
+					/* will not be deleted */
+	for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
+		if (!tb->perm) {
+			tb->n = 0 ;
+		}
+	}
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	int mac_set_func_addr(smc,f_addr)
+	struct s_smc *smc ;
+	u_long f_addr ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Set a Token-Ring functional address, the address will
+		be activated after calling mac_update_multicast()
+
+Para	f_addr	functional bits in non-canonical format
+
+Returns	0: always success
+
+	END_MANUAL_ENTRY()
+ */
+int mac_set_func_addr(smc,f_addr)
+struct s_smc *smc ;
+u_long f_addr ;
+{
+	smc->hw.fp.func_addr = f_addr ;
+	return(0) ;
+}
+
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	int mac_add_multicast(smc,addr,can)
+	struct s_smc *smc ;
+	struct fddi_addr *addr ;
+	int can ;
+
+Function	DOWNCALL	(SMC, fplustm.c)
+		Add an entry to the multicast table
+
+Para	addr	pointer to a multicast address
+	can	= 0:	the multicast address has the physical format
+		= 1:	the multicast address has the canonical format
+		| 0x80	permanent
+
+Returns	0: success
+	1: address table full
+
+Note	After a 'driver reset' or a 'station set address' all
+	entries of the multicast table are cleared.
+	In this case the driver has to fill the multicast table again.
+	After the operating system dependent module filled
+	the multicast table it must call mac_update_multicast
+	to activate the new multicast addresses!
+
+	END_MANUAL_ENTRY()
+ */
+int mac_add_multicast(smc,addr,can)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+int can ;
+{
+	SK_LOC_DECL(struct fddi_addr,own) ;
+	struct s_fpmc	*tb ;
+
+	/*
+	 * check if there are free table entries
+	 */
+	if (can & 0x80) {
+		if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) {
+			return(1) ;
+		}
+	}
+	else {
+		if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) {
+			return(1) ;
+		}
+	}
+
+	/*
+	 * find empty slot
+	 */
+	if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80)))
+		return(1) ;
+	tb->n++ ;
+	tb->a = own ;
+	tb->perm = (can & 0x80) ? 1 : 0 ;
+
+	if (can & 0x80)
+		smc->hw.fp.smt_slots_used++ ;
+	else
+		smc->hw.fp.os_slots_used++ ;
+
+	return(0) ;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	void mac_del_multicast(smc,addr,can)
+	struct s_smc *smc ;
+	struct fddi_addr *addr ;
+	int can ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Delete an entry from the multicast table
+
+Para	addr	pointer to a multicast address
+	can	= 0:	the multicast address has the physical format
+		= 1:	the multicast address has the canonical format
+		| 0x80	permanent
+
+	END_MANUAL_ENTRY()
+ */
+void mac_del_multicast(smc,addr,can)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+int can ;
+{
+	SK_LOC_DECL(struct fddi_addr,own) ;
+	struct s_fpmc	*tb ;
+
+	if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
+		return ;
+	/*
+	 * permanent addresses must be deleted with perm bit
+	 * and vice versa
+	 */
+	if (( tb->perm &&  (can & 0x80)) ||
+	    (!tb->perm && !(can & 0x80))) {
+		/*
+		 * delete it
+		 */
+		if (tb->n) {
+			tb->n-- ;
+			if (tb->perm) {
+				smc->hw.fp.smt_slots_used-- ;
+			}
+			else {
+				smc->hw.fp.os_slots_used-- ;
+			}
+		}
+	}
+}
+
+/*
+ * mode
+ */
+
+#define RX_MODE_PROM		0x1
+#define RX_MODE_ALL_MULTI	0x2
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	void mac_update_multicast(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Update FORMAC multicast registers
+
+	END_MANUAL_ENTRY()
+ */
+void mac_update_multicast(smc)
+struct s_smc *smc ;
+{
+	struct s_fpmc	*tb ;
+	u_char	*fu ;
+	int	i ;
+
+	/*
+	 * invalidate the CAM
+	 */
+	outpw(FM_A(FM_AFCMD),FM_IINV_CAM) ;
+
+	/*
+	 * set the functional address
+	 */
+	if (smc->hw.fp.func_addr) {
+		fu = (u_char *) &smc->hw.fp.func_addr ;
+		outpw(FM_A(FM_AFMASK2),0xffff) ;
+		outpw(FM_A(FM_AFMASK1),(u_short) ~((fu[0] << 8) + fu[1])) ;
+		outpw(FM_A(FM_AFMASK0),(u_short) ~((fu[2] << 8) + fu[3])) ;
+		outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ;
+		outpw(FM_A(FM_AFCOMP2), 0xc000) ;
+		outpw(FM_A(FM_AFCOMP1), 0x0000) ;
+		outpw(FM_A(FM_AFCOMP0), 0x0000) ;
+		outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ;
+	}
+
+	/*
+	 * set the mask and the personality register(s)
+	 */
+	outpw(FM_A(FM_AFMASK0),0xffff) ;
+	outpw(FM_A(FM_AFMASK1),0xffff) ;
+	outpw(FM_A(FM_AFMASK2),0xffff) ;
+	outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ;
+
+	for (i = 0, tb = smc->hw.fp.mc.table; i < FPMAX_MULTICAST; i++, tb++) {
+		if (tb->n) {
+			CHECK_CAM() ;
+
+			/*
+			 * wirte the multicast addres into the CAM
+			 */
+			outpw(FM_A(FM_AFCOMP2),
+				(u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ;
+			outpw(FM_A(FM_AFCOMP1),
+				(u_short)((tb->a.a[2]<<8)+tb->a.a[3])) ;
+			outpw(FM_A(FM_AFCOMP0),
+				(u_short)((tb->a.a[4]<<8)+tb->a.a[5])) ;
+			outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ;
+		}
+	}
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;3)
+
+	void mac_set_rx_mode(smc,mode)
+	struct s_smc *smc ;
+	int mode ;
+
+Function	DOWNCALL/INTERN	(SMT, fplustm.c)
+		This function enables / disables the selected receive.
+		Don't call this function if the hardware module is
+		used -- use mac_drv_rx_mode() instead of.
+
+Para	mode =	1	RX_ENABLE_ALLMULTI	enable all multicasts
+		2	RX_DISABLE_ALLMULTI	disable "enable all multicasts"
+		3	RX_ENABLE_PROMISC	enable promiscous
+		4	RX_DISABLE_PROMISC	disable promiscous
+		5	RX_ENABLE_NSA		enable reception of NSA frames
+		6	RX_DISABLE_NSA		disable reception of NSA frames
+
+Note	The selected receive modes will be lost after 'driver reset'
+	or 'set station address'
+
+	END_MANUAL_ENTRY
+ */
+void mac_set_rx_mode(smc,mode)
+struct s_smc *smc ;
+int mode ;
+{
+	switch (mode) {
+	case RX_ENABLE_ALLMULTI :
+		smc->hw.fp.rx_prom |= RX_MODE_ALL_MULTI ;
+		break ;
+	case RX_DISABLE_ALLMULTI :
+		smc->hw.fp.rx_prom &= ~RX_MODE_ALL_MULTI ;
+		break ;
+	case RX_ENABLE_PROMISC :
+		smc->hw.fp.rx_prom |= RX_MODE_PROM ;
+		break ;
+	case RX_DISABLE_PROMISC :
+		smc->hw.fp.rx_prom &= ~RX_MODE_PROM ;
+		break ;
+	case RX_ENABLE_NSA :
+		smc->hw.fp.nsa_mode = FM_MDAMA ;
+		smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) |
+			smc->hw.fp.nsa_mode ;
+		break ;
+	case RX_DISABLE_NSA :
+		smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ;
+		smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) |
+			smc->hw.fp.nsa_mode ;
+		break ;
+	}
+	if (smc->hw.fp.rx_prom & RX_MODE_PROM) {
+		smc->hw.fp.rx_mode = FM_MLIMPROM ;
+	}
+	else if (smc->hw.fp.rx_prom & RX_MODE_ALL_MULTI) {
+		smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode | FM_EXGPA0 ;
+	}
+	else
+		smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode ;
+	SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ;
+	mac_update_multicast(smc) ;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(module;tests;3)
+	How to test the Restricted Token Monitor
+	----------------------------------------------------------------
+
+	o Insert a break point in the function rtm_irq()
+	o Remove all stations with a restricted token monitor from the
+	  network.
+	o Connect a UPPS ISA or EISA station to the network.
+	o Give the FORMAC of UPPS station the command to send
+	  restricted tokens until the ring becomes instable.
+	o Now connect your test test client.
+	o The restricted token monitor should detect the restricted token,
+	  and your break point will be reached.
+	o You can ovserve how the station will clean the ring.
+
+	END_MANUAL_ENTRY
+ */
+void rtm_irq(smc)
+struct s_smc *smc ;
+{
+	outpw(ADDR(B2_RTM_CRTL),TIM_CL_IRQ) ;		/* clear IRQ */
+	if (inpw(ADDR(B2_RTM_CRTL)) & TIM_RES_TOK) {
+		outpw(FM_A(FM_CMDREG1),FM_ICL) ;	/* force claim */
+		DB_RMT("RMT: fddiPATHT_Rmode expired\n",0,0) ;
+		AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
+				(u_long) FDDI_SMT_EVENT,
+				(u_long) FDDI_RTT, smt_get_event_word(smc));
+	}
+	outpw(ADDR(B2_RTM_CRTL),TIM_START) ;	/* enable RTM monitoring */
+}
+
+static void rtm_init(smc)
+struct s_smc *smc ;
+{
+	outpd(ADDR(B2_RTM_INI),0) ;		/* timer = 0 */
+	outpw(ADDR(B2_RTM_CRTL),TIM_START) ;	/* enable IRQ */
+}
+
+void rtm_set_timer(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * MIB timer and hardware timer have the same resolution of 80nS
+	 */
+	DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns \n",
+		(int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ;
+	outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ;
+}
+
+static void smt_split_up_fifo(smc)
+struct s_smc *smc ;
+{
+
+/*
+	BEGIN_MANUAL_ENTRY(module;mem;1)
+	-------------------------------------------------------------
+	RECEIVE BUFFER MEMORY DIVERSION
+	-------------------------------------------------------------
+
+	R1_RxD == SMT_R1_RXD_COUNT
+	R2_RxD == SMT_R2_RXD_COUNT
+
+	SMT_R1_RXD_COUNT must be unequal zero
+
+		   | R1_RxD R2_RxD |R1_RxD R2_RxD | R1_RxD R2_RxD
+		   |   x      0	   |  x	    1-3	  |   x     < 3
+	----------------------------------------------------------------------
+		   |   63,75 kB	   |    54,75	  |	R1_RxD
+	rx queue 1 | RX_FIFO_SPACE | RX_LARGE_FIFO| ------------- * 63,75 kB
+		   |		   |		  | R1_RxD+R2_RxD
+	----------------------------------------------------------------------
+		   |		   |    9 kB	  |     R2_RxD
+	rx queue 2 |	0 kB	   | RX_SMALL_FIFO| ------------- * 63,75 kB
+		   |  (not used)   |		  | R1_RxD+R2_RxD
+
+	END_MANUAL_ENTRY
+*/
+
+	if (SMT_R1_RXD_COUNT == 0) {
+		SMT_PANIC(smc,SMT_E0117, SMT_E0117_MSG) ;
+	}
+
+	switch(SMT_R2_RXD_COUNT) {
+	case 0:
+		smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE ;
+		smc->hw.fp.fifo.rx2_fifo_size = 0 ;
+		break ;
+	case 1:
+	case 2:
+	case 3:
+		smc->hw.fp.fifo.rx1_fifo_size = RX_LARGE_FIFO ;
+		smc->hw.fp.fifo.rx2_fifo_size = RX_SMALL_FIFO ;
+		break ;
+	default:	/* this is not the real defaule */
+		smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE *
+		SMT_R1_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ;
+		smc->hw.fp.fifo.rx2_fifo_size = RX_FIFO_SPACE *
+		SMT_R2_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ;
+		break ;
+	}
+
+/*
+	BEGIN_MANUAL_ENTRY(module;mem;1)
+	-------------------------------------------------------------
+	TRANSMIT BUFFER MEMORY DIVERSION
+	-------------------------------------------------------------
+
+
+		 | no sync bw	| sync bw available and | sync bw available and
+		 | available	| SynchTxMode = SPLIT	| SynchTxMode = ALL
+	-----------------------------------------------------------------------
+	sync tx	 |     0 kB	|	32 kB		|	55 kB
+	queue	 |		|   TX_MEDIUM_FIFO	|   TX_LARGE_FIFO
+	-----------------------------------------------------------------------
+	async tx |    64 kB	|	32 kB		|	 9 k
+	queue	 | TX_FIFO_SPACE|   TX_MEDIUM_FIFO	|   TX_SMALL_FIFO
+
+	END_MANUAL_ENTRY
+*/
+
+	/*
+	 * set the tx mode bits
+	 */
+	if (smc->mib.a[PATH0].fddiPATHSbaPayload) {
+#ifdef ESS
+		smc->hw.fp.fifo.fifo_config_mode |=
+			smc->mib.fddiESSSynchTxMode | SYNC_TRAFFIC_ON ;
+#endif
+	}
+	else {
+		smc->hw.fp.fifo.fifo_config_mode &=
+			~(SEND_ASYNC_AS_SYNC|SYNC_TRAFFIC_ON) ;
+	}
+
+	/*
+	 * split up the FIFO
+	 */
+	if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON) {
+		if (smc->hw.fp.fifo.fifo_config_mode & SEND_ASYNC_AS_SYNC) {
+			smc->hw.fp.fifo.tx_s_size = TX_LARGE_FIFO ;
+			smc->hw.fp.fifo.tx_a0_size = TX_SMALL_FIFO ;
+		}
+		else {
+			smc->hw.fp.fifo.tx_s_size = TX_MEDIUM_FIFO ;
+			smc->hw.fp.fifo.tx_a0_size = TX_MEDIUM_FIFO ;
+		}
+	}
+	else {
+			smc->hw.fp.fifo.tx_s_size = 0 ;
+			smc->hw.fp.fifo.tx_a0_size = TX_FIFO_SPACE ;
+	}
+
+	smc->hw.fp.fifo.rx1_fifo_start = smc->hw.fp.fifo.rbc_ram_start +
+		RX_FIFO_OFF ;
+	smc->hw.fp.fifo.tx_s_start = smc->hw.fp.fifo.rx1_fifo_start +
+		smc->hw.fp.fifo.rx1_fifo_size ;
+	smc->hw.fp.fifo.tx_a0_start = smc->hw.fp.fifo.tx_s_start +
+		smc->hw.fp.fifo.tx_s_size ;
+	smc->hw.fp.fifo.rx2_fifo_start = smc->hw.fp.fifo.tx_a0_start +
+		smc->hw.fp.fifo.tx_a0_size ;
+
+	DB_SMT("FIFO split: mode = %x\n",smc->hw.fp.fifo.fifo_config_mode,0) ;
+	DB_SMT("rbc_ram_start =	%x	 rbc_ram_end = 	%x\n",
+		smc->hw.fp.fifo.rbc_ram_start, smc->hw.fp.fifo.rbc_ram_end) ;
+	DB_SMT("rx1_fifo_start = %x	 tx_s_start = 	%x\n",
+		smc->hw.fp.fifo.rx1_fifo_start, smc->hw.fp.fifo.tx_s_start) ;
+	DB_SMT("tx_a0_start =	%x	 rx2_fifo_start = 	%x\n",
+		smc->hw.fp.fifo.tx_a0_start, smc->hw.fp.fifo.rx2_fifo_start) ;
+}
+
+void formac_reinit_tx(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * Split up the FIFO and reinitialize the MAC if synchronous
+	 * bandwidth becomes available but no synchronous queue is
+	 * configured.
+	 */
+	if (!smc->hw.fp.fifo.tx_s_size && smc->mib.a[PATH0].fddiPATHSbaPayload){
+		(void)init_mac(smc,0) ;
+	}
+}
+
+
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/cmtdef.h linux/drivers/net/skfp/h/cmtdef.h
--- v2.3.46/linux/drivers/net/skfp/h/cmtdef.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/cmtdef.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,801 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_CMTDEF_
+#define _CMTDEF_
+
+/* **************************************************************** */
+
+/*
+ * implementation specific constants
+ * MODIIFY THE FOLLWOING THREE DEFINES
+ */
+#define AMDPLC			/* if Amd PLC chip used */
+#ifdef	CONC
+#define NUMPHYS		12	/* 2 for SAS or DAS, more for Concentrator */
+#else
+#ifdef	CONC_II
+#define NUMPHYS		24	/* 2 for SAS or DAS, more for Concentrator */
+#else
+#define NUMPHYS		2	/* 2 for SAS or DAS, more for Concentrator */
+#endif
+#endif
+#define NUMMACS		1	/* only 1 supported at the moment */
+#define NUMPATHS	2	/* primary and secondary path supported */
+
+/*
+ * DO NOT MODIFY BEYOND THIS POINT
+ */
+
+/* **************************************************************** */
+
+#if	NUMPHYS > 2
+#define CONCENTRATOR
+#endif
+
+/*
+ * Definitions for comfortable LINT usage
+ */
+#ifdef	lint
+#define LINT_USE(x)	(x)=(x)
+#else
+#define LINT_USE(x)
+#endif
+
+#ifdef	DEBUG
+#define	DB_PR(flag,a,b,c)	{ if (flag) printf(a,b,c) ; }
+#else
+#define	DB_PR(flag,a,b,c)
+#endif
+
+#ifdef DEBUG_BRD
+#define DB_ECM(a,b,c)		DB_PR((smc->debug.d_smt&1),a,b,c)
+#define DB_ECMN(n,a,b,c)	DB_PR((smc->debug.d_ecm >=(n)),a,b,c)
+#define DB_RMT(a,b,c)		DB_PR((smc->debug.d_smt&2),a,b,c)
+#define DB_RMTN(n,a,b,c)	DB_PR((smc->debug.d_rmt >=(n)),a,b,c)
+#define DB_CFM(a,b,c)		DB_PR((smc->debug.d_smt&4),a,b,c)
+#define DB_CFMN(n,a,b,c)	DB_PR((smc->debug.d_cfm >=(n)),a,b,c)
+#define DB_PCM(a,b,c)		DB_PR((smc->debug.d_smt&8),a,b,c)
+#define DB_PCMN(n,a,b,c)	DB_PR((smc->debug.d_pcm >=(n)),a,b,c)
+#define DB_SMT(a,b,c)		DB_PR((smc->debug.d_smtf),a,b,c)
+#define DB_SMTN(n,a,b,c)	DB_PR((smc->debug.d_smtf >=(n)),a,b,c)
+#define DB_SBA(a,b,c)		DB_PR((smc->debug.d_sba),a,b,c)
+#define DB_SBAN(n,a,b,c)	DB_PR((smc->debug.d_sba >=(n)),a,b,c)
+#define DB_ESS(a,b,c)		DB_PR((smc->debug.d_ess),a,b,c)
+#define DB_ESSN(n,a,b,c)	DB_PR((smc->debug.d_ess >=(n)),a,b,c)
+#else
+#define DB_ECM(a,b,c)		DB_PR((debug.d_smt&1),a,b,c)
+#define DB_ECMN(n,a,b,c)	DB_PR((debug.d_ecm >=(n)),a,b,c)
+#define DB_RMT(a,b,c)		DB_PR((debug.d_smt&2),a,b,c)
+#define DB_RMTN(n,a,b,c)	DB_PR((debug.d_rmt >=(n)),a,b,c)
+#define DB_CFM(a,b,c)		DB_PR((debug.d_smt&4),a,b,c)
+#define DB_CFMN(n,a,b,c)	DB_PR((debug.d_cfm >=(n)),a,b,c)
+#define DB_PCM(a,b,c)		DB_PR((debug.d_smt&8),a,b,c)
+#define DB_PCMN(n,a,b,c)	DB_PR((debug.d_pcm >=(n)),a,b,c)
+#define DB_SMT(a,b,c)		DB_PR((debug.d_smtf),a,b,c)
+#define DB_SMTN(n,a,b,c)	DB_PR((debug.d_smtf >=(n)),a,b,c)
+#define DB_SBA(a,b,c)		DB_PR((debug.d_sba),a,b,c)
+#define DB_SBAN(n,a,b,c)	DB_PR((debug.d_sba >=(n)),a,b,c)
+#define DB_ESS(a,b,c)		DB_PR((debug.d_ess),a,b,c)
+#define DB_ESSN(n,a,b,c)	DB_PR((debug.d_ess >=(n)),a,b,c)
+#endif
+
+#ifndef	SS_NOT_DS
+#define	SK_LOC_DECL(type,var)	type var
+#else
+#define	SK_LOC_DECL(type,var)	static type var
+#endif
+/*
+ * PHYs and PORTS
+ * Note: Don't touch the definition of PA and PB. Those might be used
+ *	by some "for" loops.
+ */
+#define PA		0
+#define PB		1
+#if	defined(SUPERNET_3) || defined(CONC_II)
+/*
+ * The port indices have to be different,
+ * because the MAC output goes through the 2. PLC
+ * Conc II: It has to be the first port in the row.
+ */
+#define PS		0	/* Internal PLC which is the same as PA */
+#else
+#define PS		1
+#endif
+#define PM		2		/* PM .. PA+NUM_PHYS-1 */
+
+/*
+ * PHY types - as in path descriptor 'fddiPHYType'
+ */
+#define TA			0	/* A port */
+#define TB			1	/* B port */
+#define TS			2	/* S port */
+#define TM			3	/* M port */
+#define TNONE			4
+
+
+/*
+ * indexes in MIB
+ */
+#define INDEX_MAC	1
+#define INDEX_PATH	1
+#define INDEX_PORT	1
+
+
+/*
+ * policies
+ */
+#define POLICY_AA	(1<<0)		/* reject AA */
+#define POLICY_AB	(1<<1)		/* reject AB */
+#define POLICY_AS	(1<<2)		/* reject AS */
+#define POLICY_AM	(1<<3)		/* reject AM */
+#define POLICY_BA	(1<<4)		/* reject BA */
+#define POLICY_BB	(1<<5)		/* reject BB */
+#define POLICY_BS	(1<<6)		/* reject BS */
+#define POLICY_BM	(1<<7)		/* reject BM */
+#define POLICY_SA	(1<<8)		/* reject SA */
+#define POLICY_SB	(1<<9)		/* reject SB */
+#define POLICY_SS	(1<<10)		/* reject SS */
+#define POLICY_SM	(1<<11)		/* reject SM */
+#define POLICY_MA	(1<<12)		/* reject MA */
+#define POLICY_MB	(1<<13)		/* reject MB */
+#define POLICY_MS	(1<<14)		/* reject MS */
+#define POLICY_MM	(1<<15)		/* reject MM */
+
+/*
+ * commands
+ */
+
+/*
+ * EVENTS
+ * event classes
+ */
+#define EVENT_ECM	1		/* event class ECM */
+#define EVENT_CFM	2		/* event class CFM */
+#define EVENT_RMT	3		/* event class RMT */
+#define EVENT_SMT	4		/* event class SMT */
+#define EVENT_PCM	5		/* event class PCM */
+#define EVENT_PCMA	5		/* event class PCMA */
+#define EVENT_PCMB	6		/* event class PCMB */
+
+/* WARNING :
+ * EVENT_PCM* must be last in the above list
+ * if more then two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1
+ * are used !
+ */
+
+#define EV_TOKEN(class,event)	(((u_long)(class)<<16L)|((u_long)(event)))
+#define EV_T_CLASS(token)	((int)((token)>>16)&0xffff)
+#define EV_T_EVENT(token)	((int)(token)&0xffff)
+
+/*
+ * ECM events
+ */
+#define EC_CONNECT	1		/* connect request */
+#define EC_DISCONNECT	2		/* disconnect request */
+#define EC_TRACE_PROP	3		/* trace propagation */
+#define EC_PATH_TEST	4		/* path test */
+#define EC_TIMEOUT_TD	5		/* timer TD_min */
+#define EC_TIMEOUT_TMAX	6		/* timer trace_max */
+#define EC_TIMEOUT_IMAX	7		/* timer I_max */
+#define EC_TIMEOUT_INMAX 8		/* timer IN_max */
+#define EC_TEST_DONE	9		/* path test done */
+
+/*
+ * CFM events
+ */
+#define CF_LOOP		1		/* cf_loop flag from PCM */
+#define CF_LOOP_A	1		/* cf_loop flag from PCM */
+#define CF_LOOP_B	2		/* cf_loop flag from PCM */
+#define CF_JOIN		3		/* cf_join flag from PCM */
+#define CF_JOIN_A	3		/* cf_join flag from PCM */
+#define CF_JOIN_B	4		/* cf_join flag from PCM */
+
+/*
+ * PCM events
+ */
+#define PC_START		1
+#define PC_STOP			2
+#define PC_LOOP			3
+#define PC_JOIN			4
+#define PC_SIGNAL		5
+#define PC_REJECT		6
+#define PC_MAINT    		7
+#define PC_TRACE		8
+#define PC_PDR			9
+#define PC_ENABLE		10
+#define PC_DISABLE		11
+
+/*
+ * must be ordered as in LineStateType
+ */
+#define PC_QLS			12
+#define PC_ILS			13
+#define PC_MLS			14
+#define PC_HLS			15
+#define PC_LS_PDR		16
+#define PC_LS_NONE		17
+#define LS2MIB(x)	((x)-PC_QLS)
+#define MIB2LS(x)	((x)+PC_QLS)
+
+#define PC_TIMEOUT_TB_MAX	18	/* timer TB_max */
+#define PC_TIMEOUT_TB_MIN	19	/* timer TB_min */
+#define PC_TIMEOUT_C_MIN	20	/* timer C_Min */
+#define PC_TIMEOUT_T_OUT	21	/* timer T_Out */
+#define PC_TIMEOUT_TL_MIN	22	/* timer TL_Min */
+#define PC_TIMEOUT_T_NEXT	23	/* timer t_next[] */
+#define PC_TIMEOUT_LCT		24
+#define PC_NSE			25	/* NOISE hardware timer */
+#define PC_LEM			26	/* LEM done */
+
+/*
+ * RMT events				  meaning		from
+ */
+#define RM_RING_OP	1		/* ring operational	MAC	*/
+#define RM_RING_NON_OP	2		/* ring not operational	MAC	*/
+#define RM_MY_BEACON	3		/* recvd my beacon	MAC	*/
+#define RM_OTHER_BEACON	4		/* recvd other beacon	MAC	*/
+#define RM_MY_CLAIM	5		/* recvd my claim	MAC	*/
+#define RM_TRT_EXP	6		/* TRT exp		MAC	*/
+#define RM_VALID_CLAIM	7		/* claim from dup addr	MAC	*/
+#define RM_JOIN		8		/* signal rm_join	CFM	*/
+#define RM_LOOP		9		/* signal rm_loop	CFM	*/
+#define RM_DUP_ADDR	10		/* dup_addr_test hange	SMT-NIF	*/
+#define RM_ENABLE_FLAG	11		/* enable flag */
+
+#define RM_TIMEOUT_NON_OP	12	/* timeout T_Non_OP	*/
+#define RM_TIMEOUT_T_STUCK	13	/* timeout T_Stuck	*/
+#define RM_TIMEOUT_ANNOUNCE	14	/* timeout T_Announce	*/
+#define RM_TIMEOUT_T_DIRECT	15	/* timeout T_Direct	*/
+#define RM_TIMEOUT_D_MAX	16	/* timeout D_Max	*/
+#define RM_TIMEOUT_POLL		17	/* claim/beacon poller	*/
+#define RM_TX_STATE_CHANGE	18	/* To restart timer for D_Max */
+
+/*
+ * SMT events
+ */
+#define SM_TIMER	1		/* timer */
+#define SM_FAST		2		/* smt_force_irq */
+
+/* PC modes */
+#define PM_NONE		0
+#define PM_PEER		1
+#define PM_TREE		2
+
+/*
+ * PCM withhold codes
+ * MIB PC-WithholdType ENUM
+ */
+#define PC_WH_NONE	0		/* ok */
+#define PC_WH_M_M	1		/* M to M */
+#define PC_WH_OTHER	2		/* other incompatible phys */
+#define PC_WH_PATH	3		/* path not available */
+/*
+ * LCT duration
+ */
+#define LC_SHORT	1		/* short LCT */
+#define LC_MEDIUM	2		/* medium LCT */
+#define LC_LONG		3		/* long LCT */
+#define LC_EXTENDED	4		/* extended LCT */
+
+/*
+ * path_test values
+ */
+#define PT_NONE		0
+#define PT_TESTING	1		/* test is running */
+#define PT_PASSED	2		/* test passed */
+#define PT_FAILED	3		/* test failed */
+#define PT_PENDING	4		/* path test follows */
+#define PT_EXITING	5		/* disconnected while in trace/leave */
+
+/*
+ * duplicate address test
+ * MIB DupAddressTest ENUM
+ */
+#define DA_NONE		0		/* 		*/
+#define DA_PASSED	1		/* test passed */
+#define DA_FAILED	2		/* test failed */
+
+
+/*
+ * optical bypass
+ */
+#define BP_DEINSERT	0		/* disable bypass */
+#define BP_INSERT	1		/* enable bypass */
+
+/*
+ * ODL enable/disable
+ */
+#define PM_TRANSMIT_DISABLE	0	/* disable xmit */
+#define PM_TRANSMIT_ENABLE	1	/* enable xmit */
+
+/*
+ * parameter for config_mux
+ * note : number is index in config_endec table !
+ */
+#define MUX_THRUA	0		/* through A */
+#define MUX_THRUB	1		/* through B */
+#define MUX_WRAPA	2		/* wrap A */
+#define MUX_WRAPB	3		/* wrap B */
+#define MUX_ISOLATE	4		/* isolated */
+#define MUX_WRAPS	5		/* SAS */
+
+/*
+ * MAC control
+ */
+#define MA_RESET	0
+#define MA_BEACON	1
+#define MA_CLAIM	2
+#define MA_DIRECTED	3		/* directed beacon */
+#define MA_TREQ		4		/* change T_Req */
+#define MA_OFFLINE	5		/* switch MAC to offline */
+
+
+/*
+ * trace prop
+ * bit map for trace propagation
+ */
+#define ENTITY_MAC	(NUMPHYS)
+#define ENTITY_PHY(p)	(p)
+#define ENTITY_BIT(m)	(1<<(m))
+
+/*
+ * Resource Tag Types
+ */
+#define PATH_ISO	0	/* isolated */
+#define PATH_PRIM	3	/* primary path */
+#define PATH_THRU	5	/* through path */
+
+#define RES_MAC		2	/* resource type MAC */
+#define RES_PORT	4	/* resource type PORT */
+
+
+/*
+ * CFM state
+ * oops: MUST MATCH CF-StateType in SMT7.2 !
+ */
+#define SC0_ISOLATED	0		/* isolated */
+#define SC1_WRAP_A	5		/* wrap A (not used) */
+#define SC2_WRAP_B	6		/* wrap B (not used) */
+#define SC4_THRU_A	12		/* through A */
+#define SC5_THRU_B	7		/* through B (used in SMT 6.2) */
+#define SC7_WRAP_S	8		/* SAS (not used) */
+#define SC9_C_WRAP_A	9		/* c wrap A */
+#define SC10_C_WRAP_B	10		/* c wrap B */
+#define SC11_C_WRAP_S	11		/* c wrap S */
+
+/*
+ * convert MIB time in units of 80nS to uS
+ */
+#define MIB2US(t)		((t)/12)
+#define SEC2MIB(s)	((s)*12500000L)
+/*
+ * SMT timer
+ */
+struct smt_timer {
+	struct smt_timer	*tm_next ;	/* linked list */
+	struct s_smc		*tm_smc ;	/* pointer to context */
+	u_long			tm_delta ;	/* delta time */
+	u_long			tm_token ;	/* token value */
+	u_short			tm_active ;	/* flag : active/inactive */
+	u_short			tm_pad ;	/* pad field */
+} ;
+
+/*
+ * communication structures
+ */
+struct mac_parameter {
+	u_long	t_neg ;		/* T_Neg parameter */
+	u_long	t_pri ;		/* T_Pri register in MAC */
+} ;
+
+/*
+ * MAC counters
+ */
+struct mac_counter {
+	u_long	mac_nobuf_counter ;	/* MAC SW counter: no buffer */
+	u_long	mac_r_restart_counter ;	/* MAC SW counter: rx restarted */
+} ;
+
+/*
+ * para struct context for SMT parameters
+ */
+struct s_pcon {
+	int	pc_len ;
+	int	pc_err ;
+	int	pc_badset ;
+	void	*pc_p ;
+} ;
+
+
+/*
+ * link error monitor
+ */
+#define LEM_AVG	5
+struct lem_counter {
+#ifdef	AM29K
+	int	lem_on	;
+	u_long	lem_errors ;
+	u_long	lem_symbols ;
+	u_long	lem_tsymbols ;
+	int	lem_s_count ;
+	int	lem_n_s ;
+	int	lem_values ;
+	int	lem_index ;
+	int	lem_avg_ber[LEM_AVG] ;
+	int	lem_sum ;
+#else
+	u_short	lem_float_ber ;		/* 10E-nn bit error rate */
+	u_long	lem_errors ;		/* accumulated error count */
+	u_short	lem_on	;
+#endif
+} ;
+
+#define NUMBITS	10
+
+
+#ifdef	AMDPLC
+
+/*
+ * PLC state table
+ */
+struct s_plc {
+	u_short	p_state ;		/* current state */
+	u_short	p_bits ;		/* number of bits to send */
+	u_short	p_start ;		/* first bit pos */
+	u_short	p_pad ;			/* padding for alignment */
+	u_long soft_err ;		/* error counter */
+	u_long parity_err ;		/* error counter */
+	u_long ebuf_err ;		/* error counter */
+	u_long ebuf_cont ;		/* continous error counter */
+	u_long phyinv ;			/* error counter */
+	u_long vsym_ctr ;		/* error counter */
+	u_long mini_ctr ;		/* error counter */
+	u_long tpc_exp ;		/* error counter */
+	u_long np_err ;			/* error counter */
+	u_long b_pcs ;			/* error counter */
+	u_long b_tpc ;			/* error counter */
+	u_long b_tne ;			/* error counter */
+	u_long b_qls ;			/* error counter */
+	u_long b_ils ;			/* error counter */
+	u_long b_hls ;			/* error counter */
+} ;
+#endif
+
+#ifdef	PROTOTYP_INC
+#include "fddi/driver.pro"
+#else	/* PROTOTYP_INC */
+/*
+ * function prototypes
+ */
+#include "h/mbuf.h"	/* Type definitions for MBUFs */
+void hwt_restart(                       /* hwt.c */
+#ifdef ANSIC
+        struct s_smc *smc
+#endif
+	) ;
+
+SMbuf *smt_build_frame(                 /* smt.c */
+#ifdef ANSIC
+        struct s_smc *smc,
+        int class,
+        int type,
+        int length
+#endif
+	) ;
+
+SMbuf *smt_get_mbuf(                     /* drvsr.c */
+#ifdef ANSIC
+        struct s_smc *smc
+#endif
+	) ;
+
+void *sm_to_para(                       /* smt.c */
+#ifdef ANSIC
+	struct s_smc *smc,
+        struct smt_header *sm,
+        int para
+#endif
+	) ;
+
+#ifndef SK_UNUSED
+#define SK_UNUSED(var)		(void)(var)
+#endif
+
+void queue_event() ;
+void ecm() ;
+void ecm_init() ;
+void rmt() ;
+void rmt_init() ;
+void pcm() ;
+void pcm_init() ;
+void cfm() ;
+void cfm_init() ;
+void smt_timer_start() ;
+void smt_timer_stop() ;
+void pcm_status_state() ;
+void plc_config_mux() ;
+void sm_lem_evaluate() ;
+void smt_clear_una_dna() ;
+void mac_status_para() ;
+void mac_update_counter() ;
+void sm_pm_ls_latch() ;
+void sm_ma_control() ;
+void sm_mac_check_beacon_claim() ;
+void config_mux() ;
+void smt_agent_init() ;
+void smt_timer_init() ;
+void smt_received_pack() ;
+void smt_add_para() ;
+void smt_swap_para() ;
+void ev_init() ;
+void hwt_init() ;
+u_long hwt_read() ;
+void hwt_stop() ;
+void hwt_start() ;
+void smt_send_mbuf() ;
+void smt_free_mbuf() ;
+void sm_pm_bypass_req() ;
+void rmt_indication() ;
+void cfm_state_change() ;
+void rx_indication() ;
+void tx_indication() ;
+#ifndef NO_SMT_PANIC
+void smt_panic() ;
+#else
+#ifdef	DEBUG
+void smt_panic() ;
+#else
+#define	smt_panic(smc,text)
+#endif	/* DEBUG */
+#endif	/* NO_SMT_PANIC */
+void smt_stat_counter() ;
+void smt_timer_poll() ;
+u_long smt_get_time() ;
+u_long smt_get_tid() ;
+void smt_timer_done() ;
+void smt_set_defaults() ;
+void smt_fixup_mib() ;
+void smt_reset_defaults() ;
+void smt_agent_task() ;
+void smt_please_reconnect() ;
+int smt_check_para() ;
+void driver_get_bia() ;
+#ifdef	SUPERNET_3
+void drv_reset_indication() ;
+#endif	/* SUPERNET_3 */
+void smt_start_watchdog() ;
+
+void smt_event() ;
+void pcm_event() ;
+void rmt_event() ;
+void cfm_event() ;
+void timer_event() ;
+void ev_dispatcher() ;
+
+void smt_get_state() ;
+void ecm_get_state() ;
+void pcm_get_state() ;
+void rmt_get_state() ;
+
+void ecm_state_change() ;
+int sm_pm_bypass_present() ;
+void pcm_state_change() ;
+void rmt_state_change() ;
+int sm_pm_get_ls() ;
+int pcm_get_s_port() ;
+int pcm_rooted_station() ;
+int cfm_get_mac_input() ;
+int cfm_get_mac_output() ;
+int port_to_mib() ;
+int cem_build_path() ;
+int sm_mac_get_tx_state() ;
+int is_individual() ;
+int is_my_addr() ;
+int is_broadcast() ;
+int is_equal() ;
+char *get_pcmstate() ;
+
+int smt_action() ;
+u_short smt_online() ;
+void smt_force_irq() ;
+void smt_pmf_received_pack() ;
+void smt_send_frame() ;
+void smt_set_timestamp() ;
+void mac_set_rx_mode() ;
+int mac_add_multicast() ;
+int mac_set_func_addr() ;
+void mac_del_multicast() ;
+void mac_update_multicast() ;
+void mac_clear_multicast() ;
+void mac_rx_directed_beacon() ;
+void set_formac_tsync() ;
+void formac_reinit_tx() ;
+void formac_tx_restart() ;
+void process_receive() ;
+void init_driver_fplus() ;
+
+void rtm_irq() ;
+void rtm_set_timer() ;
+void ring_status_indication() ;
+void llc_recover_tx() ;
+void llc_restart_tx() ;
+void plc_clear_irq() ;
+void plc_irq() ;
+int smt_set_mac_opvalues() ;
+#ifdef	TAG_MODE
+void mac_drv_pci_fix() ;
+void mac_do_pci_fix() ;
+void mac_drv_clear_tx_queue() ;
+void mac_drv_repair_descr() ;
+u_long hwt_quick_read() ;
+void hwt_wait_time() ;
+#endif
+
+#ifdef SMT_PNMI
+#ifdef ANSIC
+int pnmi_init (struct s_smc* smc);
+int pnmi_process_ndis_id (struct s_smc* smc, u_long ndis_oid, void* buf,
+		int len, int* BytesAccessed, int* BytesNeeded, u_char action);
+#else
+int pnmi_init ();
+int pnmi_process_ndis_id ();
+#endif
+#endif
+
+#ifdef	SBA
+#ifndef _H2INC
+void sba() ;
+#endif
+void sba_raf_received_pack() ;
+void sba_timer_poll() ;
+void smt_init_sba() ;
+#endif
+#ifdef	ESS
+int ess_raf_received_pack() ;
+void ess_timer_poll() ;
+void ess_para_change() ;
+#endif
+
+#ifdef	BOOT
+#define smt_srf_event(a,b,c,d)
+#define smt_init_evc(a)
+#else
+void smt_init_evc() ;
+void smt_srf_event() ;
+#endif
+
+#ifndef SMT_REAL_TOKEN_CT
+void smt_emulate_token_ct();
+#endif
+
+#if defined(DEBUG) && !defined(BOOT)
+void dump_smt() ;
+#else
+#define	dump_smt(smc,sm,text)
+#endif
+
+#ifdef	DEBUG
+char	*addr_to_string() ;
+void	dump_hex() ;
+#endif
+#endif	/* PROTOTYP_INC */
+
+/* PNMI default defines */
+#ifndef PNMI_INIT
+#define	PNMI_INIT(smc)	/* Nothing */
+#endif
+#ifndef PNMI_GET_ID
+#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \
+		( 1 ? (-1) : (-1) )
+#endif
+#ifndef PNMI_SET_ID
+#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \
+		set_type) ( 1 ? (-1) : (-1) )
+#endif
+
+/*
+ * SMT_PANIC defines
+ */
+#ifndef	SMT_PANIC
+#define	SMT_PANIC(smc,nr,msg)	smt_panic (smc, msg)
+#endif
+
+#ifndef	SMT_ERR_LOG
+#define	SMT_ERR_LOG(smc,nr,msg)	SMT_PANIC (smc, nr, msg)
+#endif
+
+#ifndef	SMT_EBASE
+#define	SMT_EBASE	100
+#endif
+
+#define	SMT_E0100	SMT_EBASE + 0
+#define	SMT_E0100_MSG	"cfm FSM: illegal ce_type"
+#define	SMT_E0101	SMT_EBASE + 1
+#define	SMT_E0101_MSG	"CEM: case ???"
+#define	SMT_E0102	SMT_EBASE + 2
+#define	SMT_E0102_MSG	"CEM A: illegal state"
+#define	SMT_E0103	SMT_EBASE + 3
+#define	SMT_E0103_MSG	"CEM B: illegal state"
+#define	SMT_E0104	SMT_EBASE + 4
+#define	SMT_E0104_MSG	"CEM M: illegal state"
+#define	SMT_E0105	SMT_EBASE + 5
+#define	SMT_E0105_MSG	"CEM S: illegal state"
+#define	SMT_E0106	SMT_EBASE + 6
+#define	SMT_E0106_MSG	"CFM : illegal state"
+#define	SMT_E0107	SMT_EBASE + 7
+#define	SMT_E0107_MSG	"ECM : illegal state"
+#define	SMT_E0108	SMT_EBASE + 8
+#define	SMT_E0108_MSG	"prop_actions : NAC in DAS CFM"
+#define	SMT_E0109	SMT_EBASE + 9
+#define	SMT_E0109_MSG	"ST2U.FM_SERRSF error in special frame"
+#define	SMT_E0110	SMT_EBASE + 10
+#define	SMT_E0110_MSG	"ST2U.FM_SRFRCTOV recv. count. overflow"
+#define	SMT_E0111	SMT_EBASE + 11
+#define	SMT_E0111_MSG	"ST2U.FM_SNFSLD NP & FORMAC simult. load"
+#define	SMT_E0112	SMT_EBASE + 12
+#define	SMT_E0112_MSG	"ST2U.FM_SRCVFRM single-frame recv.-mode"
+#define	SMT_E0113	SMT_EBASE + 13
+#define	SMT_E0113_MSG	"FPLUS: Buffer Memory Error"
+#define	SMT_E0114	SMT_EBASE + 14
+#define	SMT_E0114_MSG	"ST2U.FM_SERRSF error in special frame"
+#define	SMT_E0115	SMT_EBASE + 15
+#define	SMT_E0115_MSG	"ST3L: parity error in receive queue 2"
+#define	SMT_E0116	SMT_EBASE + 16
+#define	SMT_E0116_MSG	"ST3L: parity error in receive queue 1"
+#define	SMT_E0117	SMT_EBASE + 17
+#define	SMT_E0117_MSG	"E_SMT_001: RxD count for receive queue 1 = 0"
+#define	SMT_E0118	SMT_EBASE + 18
+#define	SMT_E0118_MSG	"PCM : illegal state"
+#define	SMT_E0119	SMT_EBASE + 19
+#define	SMT_E0119_MSG	"smt_add_para"
+#define	SMT_E0120	SMT_EBASE + 20
+#define	SMT_E0120_MSG	"smt_set_para"
+#define	SMT_E0121	SMT_EBASE + 21
+#define	SMT_E0121_MSG	"illegal event in dispatcher"
+#define	SMT_E0122	SMT_EBASE + 22
+#define	SMT_E0122_MSG	"RMT : illegal state"
+#define	SMT_E0123	SMT_EBASE + 23
+#define	SMT_E0123_MSG	"SBA: state machine has illegal state"
+#define	SMT_E0124	SMT_EBASE + 24
+#define	SMT_E0124_MSG	"sba_free_session() called with NULL pointer"
+#define	SMT_E0125	SMT_EBASE + 25
+#define	SMT_E0125_MSG	"SBA : illegal session pointer"
+#define	SMT_E0126	SMT_EBASE + 26
+#define	SMT_E0126_MSG	"smt_free_mbuf() called with NULL pointer\n"
+#define	SMT_E0127	SMT_EBASE + 27
+#define	SMT_E0127_MSG	"sizeof evcs"
+#define	SMT_E0128	SMT_EBASE + 28
+#define	SMT_E0128_MSG	"evc->evc_cond_state = 0"
+#define	SMT_E0129	SMT_EBASE + 29
+#define	SMT_E0129_MSG	"evc->evc_multiple = 0"
+#define	SMT_E0130	SMT_EBASE + 30
+#define	SMT_E0130_MSG	write_mdr_warning
+#define	SMT_E0131	SMT_EBASE + 31
+#define	SMT_E0131_MSG	cam_warning
+#define SMT_E0132	SMT_EBASE + 32
+#define SMT_E0132_MSG	"ST1L.FM_SPCEPDx parity/coding error"
+#define SMT_E0133	SMT_EBASE + 33
+#define SMT_E0133_MSG	"ST1L.FM_STBURx tx buffer underrun"
+#define SMT_E0134	SMT_EBASE + 34
+#define SMT_E0134_MSG	"ST1L.FM_SPCEPDx parity error"
+#define SMT_E0135	SMT_EBASE + 35
+#define SMT_E0135_MSG	"RMT: duplicate MAC address detected. Ring left!"
+#define SMT_E0136	SMT_EBASE + 36
+#define SMT_E0136_MSG	"Elasticity Buffer hang-up"
+#define SMT_E0137	SMT_EBASE + 37
+#define SMT_E0137_MSG	"SMT: queue overrun"
+#define SMT_E0138	SMT_EBASE + 38
+#define SMT_E0138_MSG	"RMT: duplicate MAC address detected. Ring NOT left!"
+#endif	/* _CMTDEF_ */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/fddi.h linux/drivers/net/skfp/h/fddi.h
--- v2.3.46/linux/drivers/net/skfp/h/fddi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/fddi.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_FDDI_
+#define _FDDI_
+
+struct fddi_addr {
+	u_char	a[6] ;
+} ;
+
+#define GROUP_ADDR	0x80		/* MSB in a[0] */
+
+struct fddi_mac {
+	struct fddi_addr	mac_dest ;
+	struct fddi_addr	mac_source ;
+	u_char			mac_info[4478] ;
+} ;
+
+#define FDDI_MAC_SIZE	(12)
+#define FDDI_RAW_MTU	(4500-5)	/* exl. Pr,SD, ED/FS */
+#define FDDI_RAW	(4500)
+
+/*
+ * FC values
+ */
+#define FC_VOID		0x40		/* void frame */
+#define FC_TOKEN	0x80		/* token */
+#define FC_RES_TOKEN	0xc0		/* restricted token */
+#define FC_SMT_INFO	0x41		/* SMT Info frame */
+/*
+ * FC_SMT_LAN_LOC && FC_SMT_LOC are SK specific !
+ */
+#define FC_SMT_LAN_LOC	0x42		/* local SMT Info frame */
+#define FC_SMT_LOC	0x43		/* local SMT Info frame */
+#define FC_SMT_NSA	0x4f		/* SMT NSA frame */
+#define FC_MAC		0xc0		/* MAC frame */
+#define FC_BEACON	0xc2		/* MAC beacon frame */
+#define FC_CLAIM	0xc3		/* MAC claim frame */
+#define FC_SYNC_LLC	0xd0		/* sync. LLC frame */
+#define FC_ASYNC_LLC	0x50		/* async. LLC frame */
+#define FC_SYNC_BIT	0x80		/* sync. bit in FC */
+
+#define FC_LLC_PRIOR	0x07		/* priority bits */
+
+#define BEACON_INFO	0		/* beacon type */
+#define DBEACON_INFO	1		/* beacon type DIRECTED */
+
+
+/*
+ * indicator bits
+ */
+#define C_INDICATOR	(1<<0)
+#define A_INDICATOR	(1<<1)
+#define E_INDICATOR	(1<<2)
+#define I_INDICATOR	(1<<6)		/* SK specific */ 
+#define L_INDICATOR	(1<<7)		/* SK specific */
+
+#endif	/* _FDDI_ */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/fddimib.h linux/drivers/net/skfp/h/fddimib.h
--- v2.3.46/linux/drivers/net/skfp/h/fddimib.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/fddimib.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,349 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FDDI MIB
+ */
+
+/*
+ * typedefs
+ */
+
+typedef	u_long	Counter ;
+typedef u_char	TimeStamp[8] ;
+typedef struct fddi_addr LongAddr ;
+typedef	u_long	Timer_2 ;
+typedef	u_long	Timer ;
+typedef	u_short	ResId ;
+typedef u_short	SMTEnum ;
+typedef	u_char	SMTFlag ;
+
+typedef struct {
+	Counter		count ;
+	TimeStamp	timestamp ;
+} SetCountType ;
+
+/*
+ * bits for bit string "available_path"
+ */
+#define MIB_PATH_P	(1<<0)
+#define MIB_PATH_S	(1<<1)
+#define MIB_PATH_L	(1<<2)
+
+/*
+ * bits for bit string PermittedPaths & RequestedPaths (SIZE(8))
+ */
+#define MIB_P_PATH_LOCAL	(1<<0)
+#define MIB_P_PATH_SEC_ALTER	(1<<1)
+#define MIB_P_PATH_PRIM_ALTER	(1<<2)
+#define MIB_P_PATH_CON_ALTER	(1<<3)
+#define MIB_P_PATH_SEC_PREFER	(1<<4)
+#define MIB_P_PATH_PRIM_PREFER	(1<<5)
+#define MIB_P_PATH_CON_PREFER	(1<<6)
+#define MIB_P_PATH_THRU		(1<<7)
+
+/*
+ * enum current path
+ */
+#define MIB_PATH_ISOLATED	0
+#define MIB_PATH_LOCAL		1
+#define MIB_PATH_SECONDARY	2
+#define MIB_PATH_PRIMARY	3
+#define MIB_PATH_CONCATENATED	4
+#define MIB_PATH_THRU		5
+
+/*
+ * enum PMDClass
+ */
+#define MIB_PMDCLASS_MULTI	0
+#define MIB_PMDCLASS_SINGLE1	1
+#define MIB_PMDCLASS_SINGLE2	2
+#define MIB_PMDCLASS_SONET	3
+#define MIB_PMDCLASS_LCF	4
+#define MIB_PMDCLASS_TP		5
+#define MIB_PMDCLASS_UNKNOWN	6
+#define MIB_PMDCLASS_UNSPEC	7
+
+/*
+ * enum SMTStationStatus
+ */
+#define MIB_SMT_STASTA_CON	0
+#define MIB_SMT_STASTA_SEPA	1
+#define MIB_SMT_STASTA_THRU	2
+
+
+struct fddi_mib {
+	/*
+	 * private
+	 */
+	u_char			fddiPRPMFPasswd[8] ;
+	struct smt_sid		fddiPRPMFStation ;
+
+#ifdef	ESS
+	/*
+	 * private variables for static allocation of the
+	 * End Station Support
+	 */
+	u_long	fddiESSPayload ;	/* payload for static alloc */
+	u_long	fddiESSOverhead ;	/* frame ov for static alloc */
+	u_long	fddiESSMaxTNeg ;	/* maximum of T-NEG */
+	u_long	fddiESSMinSegmentSize ;	/* min size of the sync frames */
+	u_long	fddiESSCategory ;	/* category for the Alloc req */
+	short	fddiESSSynchTxMode ;	/* send all LLC frames as sync */
+#endif	/* ESS */
+#ifdef	SBA
+	/*
+	 * private variables for the Synchronous Bandwidth Allocator
+	 */
+	char	fddiSBACommand ;	/* holds the parsed SBA cmd */
+	u_char	fddiSBAAvailable ;	/* SBA allocatable value */
+#endif	/* SBA */
+
+	/*
+	 * SMT standard mib
+	 */
+	struct smt_sid		fddiSMTStationId ;
+	u_short			fddiSMTOpVersionId ;
+	u_short			fddiSMTHiVersionId ;
+	u_short			fddiSMTLoVersionId ;
+	u_char			fddiSMTManufacturerData[32] ;
+	u_char			fddiSMTUserData[32] ;
+	u_short			fddiSMTMIBVersionId ;
+
+	/*
+	 * ConfigGrp
+	 */
+	u_char			fddiSMTMac_Ct ;
+	u_char			fddiSMTNonMaster_Ct ;
+	u_char			fddiSMTMaster_Ct ;
+	u_char			fddiSMTAvailablePaths ;
+	u_short			fddiSMTConfigCapabilities ;
+	u_short			fddiSMTConfigPolicy ;
+	u_short			fddiSMTConnectionPolicy ;
+	u_short			fddiSMTTT_Notify ;
+	u_char			fddiSMTStatRptPolicy ;
+	u_long			fddiSMTTrace_MaxExpiration ;
+	u_short			fddiSMTPORTIndexes[NUMPHYS] ;
+	u_short			fddiSMTMACIndexes ;
+	u_char			fddiSMTBypassPresent ;
+
+	/*
+	 * StatusGrp
+	 */
+	SMTEnum			fddiSMTECMState ;
+	SMTEnum			fddiSMTCF_State ;
+	SMTEnum			fddiSMTStationStatus ;
+	u_char			fddiSMTRemoteDisconnectFlag ;
+	u_char			fddiSMTPeerWrapFlag ;
+
+	/*
+	 * MIBOperationGrp
+	 */
+	TimeStamp		fddiSMTTimeStamp ;
+	TimeStamp		fddiSMTTransitionTimeStamp ;
+	SetCountType		fddiSMTSetCount ;
+	struct smt_sid		fddiSMTLastSetStationId ;
+
+	struct fddi_mib_m {
+		u_short		fddiMACFrameStatusFunctions ;
+		Timer_2		fddiMACT_MaxCapabilitiy ;
+		Timer_2		fddiMACTVXCapabilitiy ;
+
+		/* ConfigGrp */
+		u_char		fddiMACMultiple_N ;	/* private */
+		u_char		fddiMACMultiple_P ;	/* private */
+		u_char		fddiMACDuplicateAddressCond ;/* private */
+		u_char		fddiMACAvailablePaths ;
+		u_short		fddiMACCurrentPath ;
+		LongAddr	fddiMACUpstreamNbr ;
+		LongAddr	fddiMACDownstreamNbr ;
+		LongAddr	fddiMACOldUpstreamNbr ;
+		LongAddr	fddiMACOldDownstreamNbr ;
+		SMTEnum		fddiMACDupAddressTest ;
+		u_short		fddiMACRequestedPaths ;
+		SMTEnum		fddiMACDownstreamPORTType ;
+		ResId		fddiMACIndex ;
+
+		/* AddressGrp */
+		LongAddr	fddiMACSMTAddress ;
+
+		/* OperationGrp */
+		Timer_2		fddiMACT_Min ;	/* private */
+		Timer_2		fddiMACT_ReqMIB ;
+		Timer_2		fddiMACT_Req ;	/* private */
+		Timer_2		fddiMACT_Neg ;
+		Timer_2		fddiMACT_MaxMIB ;
+		Timer_2		fddiMACT_Max ;	/* private */
+		Timer_2		fddiMACTvxValueMIB ;
+		Timer_2		fddiMACTvxValue ; /* private */
+		Timer_2		fddiMACT_Pri0 ;
+		Timer_2		fddiMACT_Pri1 ;
+		Timer_2		fddiMACT_Pri2 ;
+		Timer_2		fddiMACT_Pri3 ;
+		Timer_2		fddiMACT_Pri4 ;
+		Timer_2		fddiMACT_Pri5 ;
+		Timer_2		fddiMACT_Pri6 ;
+
+		/* CountersGrp */
+		Counter		fddiMACFrame_Ct ;
+		Counter		fddiMACCopied_Ct ;
+		Counter		fddiMACTransmit_Ct ;
+		Counter		fddiMACToken_Ct ;
+		Counter		fddiMACError_Ct ;
+		Counter		fddiMACLost_Ct ;
+		Counter		fddiMACTvxExpired_Ct ;
+		Counter		fddiMACNotCopied_Ct ;
+		Counter		fddiMACRingOp_Ct ;
+
+		Counter		fddiMACSMTCopied_Ct ;		/* private */
+		Counter		fddiMACSMTTransmit_Ct ;		/* private */
+
+		/* private for delta ratio */
+		Counter		fddiMACOld_Frame_Ct ;
+		Counter		fddiMACOld_Copied_Ct ;
+		Counter		fddiMACOld_Error_Ct ;
+		Counter		fddiMACOld_Lost_Ct ;
+		Counter		fddiMACOld_NotCopied_Ct ;
+
+		/* FrameErrorConditionGrp */
+		u_short		fddiMACFrameErrorThreshold ;
+		u_short		fddiMACFrameErrorRatio ;
+
+		/* NotCopiedConditionGrp */
+		u_short		fddiMACNotCopiedThreshold ;
+		u_short		fddiMACNotCopiedRatio ;
+
+		/* StatusGrp */
+		SMTEnum		fddiMACRMTState ;
+		SMTFlag		fddiMACDA_Flag ;
+		SMTFlag		fddiMACUNDA_Flag ;
+		SMTFlag		fddiMACFrameErrorFlag ;
+		SMTFlag		fddiMACNotCopiedFlag ;
+		SMTFlag		fddiMACMA_UnitdataAvailable ;
+		SMTFlag		fddiMACHardwarePresent ;
+		SMTFlag		fddiMACMA_UnitdataEnable ;
+
+	} m[NUMMACS] ;
+#define MAC0	0
+
+	struct fddi_mib_a {
+		ResId		fddiPATHIndex ;
+		u_long		fddiPATHSbaPayload ;
+		u_long		fddiPATHSbaOverhead ;
+		/* fddiPATHConfiguration is built on demand */
+		/* u_long		fddiPATHConfiguration ; */
+		Timer		fddiPATHT_Rmode ;
+		u_long		fddiPATHSbaAvailable ;
+		Timer_2		fddiPATHTVXLowerBound ;
+		Timer_2		fddiPATHT_MaxLowerBound ;
+		Timer_2		fddiPATHMaxT_Req ;
+	} a[NUMPATHS] ;
+#define PATH0	0
+
+	struct fddi_mib_p {
+		/* ConfigGrp */
+		SMTEnum		fddiPORTMy_Type ;
+		SMTEnum		fddiPORTNeighborType ;
+		u_char		fddiPORTConnectionPolicies ;
+		struct {
+			u_char	T_val ;
+			u_char	R_val ;
+		} fddiPORTMacIndicated ;
+		SMTEnum		fddiPORTCurrentPath ;
+		/* must be 4: is 32 bit in SMT format
+		 * indices :
+		 *	1	none
+		 *	2	tree
+		 *	3	peer
+		 */
+		u_char		fddiPORTRequestedPaths[4] ;
+		u_short		fddiPORTMACPlacement ;
+		u_char		fddiPORTAvailablePaths ;
+		u_char		fddiPORTConnectionCapabilities ;
+		SMTEnum		fddiPORTPMDClass ;
+		ResId		fddiPORTIndex ;
+
+		/* OperationGrp */
+		SMTEnum		fddiPORTMaint_LS ;
+		SMTEnum		fddiPORTPC_LS ;
+		u_char		fddiPORTBS_Flag ;
+
+		/* ErrorCtrsGrp */
+		Counter		fddiPORTLCTFail_Ct ;
+		Counter		fddiPORTEBError_Ct ;
+		Counter		fddiPORTOldEBError_Ct ;
+
+		/* LerGrp */
+		Counter		fddiPORTLem_Reject_Ct ;
+		Counter		fddiPORTLem_Ct ;
+		u_char		fddiPORTLer_Estimate ;
+		u_char		fddiPORTLer_Cutoff ;
+		u_char		fddiPORTLer_Alarm ;
+
+		/* StatusGrp */
+		SMTEnum		fddiPORTConnectState ;
+		SMTEnum		fddiPORTPCMState ;	/* real value */
+		SMTEnum		fddiPORTPCMStateX ;	/* value for MIB */
+		SMTEnum		fddiPORTPC_Withhold ;
+		SMTFlag		fddiPORTHardwarePresent ;
+		u_char		fddiPORTLerFlag ;
+
+		u_char		fddiPORTMultiple_U ;	/* private */
+		u_char		fddiPORTMultiple_P ;	/* private */
+		u_char		fddiPORTEB_Condition ;	/* private */
+	} p[NUMPHYS] ;
+	struct {
+		Counter		fddiPRIVECF_Req_Rx ;	/* ECF req received */
+		Counter		fddiPRIVECF_Reply_Rx ;	/* ECF repl received */
+		Counter		fddiPRIVECF_Req_Tx ;	/* ECF req transm */
+		Counter		fddiPRIVECF_Reply_Tx ;	/* ECF repl transm */
+		Counter		fddiPRIVPMF_Get_Rx ;	/* PMF Get rec */
+		Counter		fddiPRIVPMF_Set_Rx ;	/* PMF Set rec */
+		Counter		fddiPRIVRDF_Rx ;	/* RDF received */
+		Counter		fddiPRIVRDF_Tx ;	/* RDF transmitted */
+	} priv ;
+} ;
+
+/*
+ * OIDs for statistics
+ */
+#define	SMT_OID_CF_STATE	1	/* fddiSMTCF_State */
+#define	SMT_OID_PCM_STATE_A	2	/* fddiPORTPCMState port A */
+#define	SMT_OID_PCM_STATE_B	17	/* fddiPORTPCMState port B */
+#define	SMT_OID_RMT_STATE	3	/* fddiMACRMTState */
+#define	SMT_OID_UNA		4	/* fddiMACUpstreamNbr */
+#define	SMT_OID_DNA		5	/* fddiMACOldDownstreamNbr */
+#define	SMT_OID_ERROR_CT	6	/* fddiMACError_Ct */
+#define	SMT_OID_LOST_CT		7	/* fddiMACLost_Ct */
+#define	SMT_OID_LEM_CT		8	/* fddiPORTLem_Ct */
+#define	SMT_OID_LEM_CT_A	11	/* fddiPORTLem_Ct port A */
+#define	SMT_OID_LEM_CT_B	12	/* fddiPORTLem_Ct port B */
+#define	SMT_OID_LCT_FAIL_CT	9	/* fddiPORTLCTFail_Ct */
+#define	SMT_OID_LCT_FAIL_CT_A	13	/* fddiPORTLCTFail_Ct port A */
+#define	SMT_OID_LCT_FAIL_CT_B	14	/* fddiPORTLCTFail_Ct port B */
+#define	SMT_OID_LEM_REJECT_CT	10	/* fddiPORTLem_Reject_Ct */
+#define	SMT_OID_LEM_REJECT_CT_A	15	/* fddiPORTLem_Reject_Ct port A */
+#define	SMT_OID_LEM_REJECT_CT_B	16	/* fddiPORTLem_Reject_Ct port B */
+
+/*
+ * SK MIB
+ */
+#define SMT_OID_ECF_REQ_RX	20	/* ECF requests received */
+#define SMT_OID_ECF_REPLY_RX	21	/* ECF replies received */
+#define SMT_OID_ECF_REQ_TX	22	/* ECF requests transmitted */
+#define SMT_OID_ECF_REPLY_TX	23	/* ECF replies transmitted */
+#define SMT_OID_PMF_GET_RX	24	/* PMF get requests received */
+#define SMT_OID_PMF_SET_RX	25	/* PMF set requests received */
+#define SMT_OID_RDF_RX		26	/* RDF received */
+#define SMT_OID_RDF_TX		27	/* RDF transmitted */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/fplustm.h linux/drivers/net/skfp/h/fplustm.h
--- v2.3.46/linux/drivers/net/skfp/h/fplustm.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/fplustm.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,274 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	AMD Fplus in tag mode data structs
+ *	defs for fplustm.c
+ */
+
+#ifndef	_FPLUS_
+#define _FPLUS_
+
+#ifndef	HW_PTR
+#ifdef	MEM_MAPPED_IO
+#define	HW_PTR	u_long
+#else
+#define	HW_PTR	u_short
+#endif
+#endif
+
+/*
+ * fplus error statistic structure
+ */
+struct err_st {
+	u_long err_valid ;		/* memory status valid */
+	u_long err_abort ;		/* memory status receive abort */
+	u_long err_e_indicator ;	/* error indicator */
+	u_long err_crc ;		/* error detected (CRC or length) */
+	u_long err_llc_frame ;		/* LLC frame */
+	u_long err_mac_frame ;		/* MAC frame */
+	u_long err_smt_frame ;		/* SMT frame */
+	u_long err_imp_frame ;		/* implementer frame */
+	u_long err_no_buf ;		/* no buffer available */
+	u_long err_too_long ;		/* longer than max. buffer */
+	u_long err_bec_stat ;		/* beacon state entered */
+	u_long err_clm_stat ;		/* claim state entered */
+	u_long err_sifg_det ;		/* short interframe gap detect */
+	u_long err_phinv ;		/* PHY invalid */
+	u_long err_tkiss ;		/* token issued */
+	u_long err_tkerr ;		/* token error */
+} ;
+
+/*
+ *	Transmit Descriptor struct
+ */
+struct s_smt_fp_txd {
+	u_long txd_tbctrl ;		/* transmit buffer control */
+	u_long txd_txdscr ;		/* transmit frame status word */
+	u_long txd_tbadr ;		/* physical tx buffer address */
+	u_long txd_ntdadr ;		/* physical pointer to the next TxD */
+#ifdef	ENA_64BIT_SUP
+	u_long txd_tbadr_hi ;		/* physical tx buffer addr (high dword)*/
+#endif
+	char far *txd_virt ;		/* virtual pointer to the data frag */
+					/* virt pointer to the next TxD */
+	struct s_smt_fp_txd volatile far *txd_next ;
+	struct s_txd_os txd_os ;	/* OS - specific struct */
+} ;
+
+/*
+ *	Receive Descriptor struct
+ */
+struct s_smt_fp_rxd {
+	u_long rxd_rbctrl ;		/* receive buffer control */
+	u_long rxd_rfsw ;		/* receive frame status word */
+	u_long rxd_rbadr ;		/* physical rx buffer address */
+	u_long rxd_nrdadr ;		/* physical pointer to the next RxD */
+#ifdef	ENA_64BIT_SUP
+	u_long rxd_rbadr_hi ;		/* physical tx buffer addr (high dword)*/
+#endif
+	char far *rxd_virt ;		/* virtual pointer to the data frag */
+					/* virt pointer to the next RxD */
+	struct s_smt_fp_rxd volatile far *rxd_next ;
+	struct s_rxd_os rxd_os ;	/* OS - specific struct */
+} ;
+
+/*
+ *	Descriptor Union Definition
+ */
+union s_fp_descr {
+	struct	s_smt_fp_txd t ;		/* pointer to the TxD */
+	struct	s_smt_fp_rxd r ;		/* pointer to the RxD */
+} ;
+
+/*
+ *	TxD Ring Control struct
+ */
+struct s_smt_tx_queue {
+	struct s_smt_fp_txd volatile *tx_curr_put ; /* next free TxD */
+	struct s_smt_fp_txd volatile *tx_prev_put ; /* shadow put pointer */
+	struct s_smt_fp_txd volatile *tx_curr_get ; /* next TxD to release*/
+	u_short tx_free ;			/* count of free TxD's */
+	u_short tx_used ;			/* count of used TxD's */
+	HW_PTR tx_bmu_ctl ;			/* BMU addr for tx start */
+	HW_PTR tx_bmu_dsc ;			/* BMU addr for curr dsc. */
+} ;
+
+/*
+ *	RxD Ring Control struct
+ */
+struct s_smt_rx_queue {
+	struct s_smt_fp_rxd volatile *rx_curr_put ; /* next RxD to queue into */
+	struct s_smt_fp_rxd volatile *rx_prev_put ; /* shadow put pointer */
+	struct s_smt_fp_rxd volatile *rx_curr_get ; /* next RxD to fill */
+	u_short rx_free ;			/* count of free RxD's */
+	u_short rx_used ;			/* count of used RxD's */
+	HW_PTR rx_bmu_ctl ;			/* BMU addr for rx start */
+	HW_PTR rx_bmu_dsc ;			/* BMU addr for curr dsc. */
+} ;
+
+#define VOID_FRAME_OFF		0x00
+#define CLAIM_FRAME_OFF		0x08
+#define BEACON_FRAME_OFF	0x10
+#define DBEACON_FRAME_OFF	0x18
+#define RX_FIFO_OFF		0x21		/* to get a prime number for */
+						/* the RX_FIFO_SPACE */
+
+#define RBC_MEM_SIZE		0x8000
+#define SEND_ASYNC_AS_SYNC	0x1
+#define	SYNC_TRAFFIC_ON		0x2
+
+/* big FIFO memory */
+#define	RX_FIFO_SPACE		0x4000 - RX_FIFO_OFF
+#define	TX_FIFO_SPACE		0x4000
+
+#define	TX_SMALL_FIFO		0x0900
+#define	TX_MEDIUM_FIFO		TX_FIFO_SPACE / 2	
+#define	TX_LARGE_FIFO		TX_FIFO_SPACE - TX_SMALL_FIFO	
+
+#define	RX_SMALL_FIFO		0x0900
+#define	RX_LARGE_FIFO		RX_FIFO_SPACE - RX_SMALL_FIFO	
+
+struct s_smt_fifo_conf {
+	u_short	rbc_ram_start ;		/* FIFO start address */
+	u_short	rbc_ram_end ;		/* FIFO size */
+	u_short	rx1_fifo_start ;	/* rx queue start address */
+	u_short	rx1_fifo_size ;		/* rx queue size */
+	u_short	rx2_fifo_start ;	/* rx queue start address */
+	u_short	rx2_fifo_size ;		/* rx queue size */
+	u_short	tx_s_start ;		/* sync queue start address */
+	u_short	tx_s_size ;		/* sync queue size */
+	u_short	tx_a0_start ;		/* async queue A0 start address */
+	u_short	tx_a0_size ;		/* async queue A0 size */
+	u_short	fifo_config_mode ;	/* FIFO configuration mode */
+} ;
+
+#define FM_ADDRX	(FM_ADDET|FM_EXGPA0|FM_EXGPA1)
+
+struct s_smt_fp {
+	u_short	mdr2init ;		/* mode register 2 init value */
+	u_short	mdr3init ;		/* mode register 3 init value */
+	u_short frselreg_init ;		/* frame selection register init val */
+	u_short	rx_mode ;		/* address mode broad/multi/promisc */
+	u_short	nsa_mode ;
+	u_short rx_prom ;
+	u_short	exgpa ;
+
+	struct err_st err_stats ;	/* error statistics */
+
+	/*
+	 * MAC buffers
+	 */
+	struct fddi_mac_sf {		/* special frame build buffer */
+		u_char			mac_fc ;
+		struct fddi_addr	mac_dest ;
+		struct fddi_addr	mac_source ;
+		u_char			mac_info[0x20] ;
+	} mac_sfb ;
+
+
+	/*
+	 * queues
+	 */
+#define QUEUE_S			0
+#define QUEUE_A0		1
+#define QUEUE_R1		0
+#define QUEUE_R2		1
+#define USED_QUEUES		2
+
+	/*
+	 * queue pointers; points to the queue dependent variables
+	 */
+	struct s_smt_tx_queue *tx[USED_QUEUES] ;
+	struct s_smt_rx_queue *rx[USED_QUEUES] ;
+
+	/*
+	 * queue dependent variables
+	 */
+	struct s_smt_tx_queue tx_q[USED_QUEUES] ;
+	struct s_smt_rx_queue rx_q[USED_QUEUES] ;
+
+	/*
+	 * FIFO configuration struct
+	 */
+	struct	s_smt_fifo_conf	fifo ;
+
+	/* last formac status */
+	u_short	 s2u ;
+	u_short	 s2l ;
+
+	/* calculated FORMAC+ reg.addr. */
+	HW_PTR	fm_st1u ;
+	HW_PTR	fm_st1l ;
+	HW_PTR	fm_st2u ;
+	HW_PTR	fm_st2l ;
+	HW_PTR	fm_st3u ;
+	HW_PTR	fm_st3l ;
+
+
+	/*
+	 * multicast table
+	 */
+#define FPMAX_MULTICAST 32 
+#define	SMT_MAX_MULTI	4
+	struct {
+		struct s_fpmc {
+			struct fddi_addr	a ;	/* mc address */
+			u_char			n ;	/* usage counter */
+			u_char			perm ;	/* flag: permanent */
+		} table[FPMAX_MULTICAST] ;
+	} mc ;
+	struct fddi_addr	group_addr ;
+	u_long	func_addr ;		/* functional address */
+	int	smt_slots_used ;	/* count of table entries for the SMT */
+	int	os_slots_used ;		/* count of table entries */ 
+					/* used by the os-specific module */
+} ;
+
+/*
+ * modes for mac_set_rx_mode()
+ */
+#define RX_ENABLE_ALLMULTI	1	/* enable all multicasts */
+#define RX_DISABLE_ALLMULTI	2	/* disable "enable all multicasts" */
+#define RX_ENABLE_PROMISC	3	/* enable promiscous */
+#define RX_DISABLE_PROMISC	4	/* disable promiscous */
+#define RX_ENABLE_NSA		5	/* enable reception of NSA frames */
+#define RX_DISABLE_NSA		6	/* disable reception of NSA frames */
+
+
+/*
+ * support for byte reversal in AIX
+ * (descriptors and pointers must be byte reversed in memory
+ *  CPU is big endian; M-Channel is little endian)
+ */
+#ifdef	AIX
+#define MDR_REV
+#define	AIX_REVERSE(x)		((((x)<<24L)&0xff000000L)	+	\
+				 (((x)<< 8L)&0x00ff0000L)	+	\
+				 (((x)>> 8L)&0x0000ff00L)	+	\
+				 (((x)>>24L)&0x000000ffL))
+#else
+#define	AIX_REVERSE(x)	(x)
+#endif
+
+#ifdef	MDR_REV	
+#define	MDR_REVERSE(x)		((((x)<<24L)&0xff000000L)	+	\
+				 (((x)<< 8L)&0x00ff0000L)	+	\
+				 (((x)>> 8L)&0x0000ff00L)	+	\
+				 (((x)>>24L)&0x000000ffL))
+#else
+#define	MDR_REVERSE(x)	(x)
+#endif
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/hwmtm.h linux/drivers/net/skfp/h/hwmtm.h
--- v2.3.46/linux/drivers/net/skfp/h/hwmtm.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/hwmtm.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,424 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_HWM_
+#define	_HWM_
+
+#include "h/mbuf.h"
+
+/*
+ * MACRO for DMA synchronization:
+ *	The descriptor 'desc' is flushed for the device 'flag'.
+ *	Devices are the CPU (DDI_DMA_SYNC_FORCPU) and the
+ *	adapter (DDI_DMA_SYNC_FORDEV).
+ *
+ *	'desc'	Pointer to a Rx or Tx descriptor.
+ *	'flag'	Flag for direction (view for CPU or DEVICE) that
+ *		should be synchronized.
+ *
+ *	Empty macros and defines are specified here. The real macro
+ *	is os-specific and should be defined in osdef1st.h.
+ */
+#ifndef DRV_BUF_FLUSH
+#define DRV_BUF_FLUSH(desc,flag)
+#define DDI_DMA_SYNC_FORCPU
+#define DDI_DMA_SYNC_FORDEV
+#endif
+
+	/*
+	 * hardware modul dependent receive modes
+	 */
+#define	RX_ENABLE_PASS_SMT	21
+#define	RX_DISABLE_PASS_SMT	22
+#define	RX_ENABLE_PASS_NSA	23
+#define	RX_DISABLE_PASS_NSA	24
+#define	RX_ENABLE_PASS_DB	25
+#define	RX_DISABLE_PASS_DB	26
+#define	RX_DISABLE_PASS_ALL	27
+#define	RX_DISABLE_LLC_PROMISC	28
+#define	RX_ENABLE_LLC_PROMISC	29
+
+
+#ifndef	DMA_RD
+#define DMA_RD		1	/* memory -> hw */
+#endif
+#ifndef DMA_WR
+#define DMA_WR		2	/* hw -> memory */
+#endif
+#define SMT_BUF		0x80
+
+	/*
+	 * bits of the frame status byte
+	 */
+#define EN_IRQ_EOF	0x02	/* get IRQ after end of frame transmission */
+#define	LOC_TX		0x04	/* send frame to the local SMT */
+#define LAST_FRAG	0x08	/* last TxD of the frame */
+#define	FIRST_FRAG	0x10	/* first TxD of the frame */
+#define	LAN_TX		0x20	/* send frame to network if set */
+#define RING_DOWN	0x40	/* error: unable to send, ring down */
+#define OUT_OF_TXD	0x80	/* error: not enough TxDs available */
+
+
+#ifndef NULL
+#define NULL 		0
+#endif
+
+#ifdef	LITTLE_ENDIAN
+#define HWM_REVERSE(x)	(x)
+#else
+#define	HWM_REVERSE(x)		((((x)<<24L)&0xff000000L)	+	\
+				 (((x)<< 8L)&0x00ff0000L)	+	\
+				 (((x)>> 8L)&0x0000ff00L)	+	\
+				 (((x)>>24L)&0x000000ffL))
+#endif
+
+#define C_INDIC		(1L<<25)
+#define A_INDIC		(1L<<26)
+#define	RD_FS_LOCAL	0x80
+
+	/*
+	 * DEBUG FLAGS
+	 */
+#define	DEBUG_SMTF	1
+#define	DEBUG_SMT	2
+#define	DEBUG_ECM	3
+#define	DEBUG_RMT	4
+#define	DEBUG_CFM	5
+#define	DEBUG_PCM	6
+#define	DEBUG_SBA	7
+#define	DEBUG_ESS	8
+
+#define	DB_HWM_RX	10
+#define	DB_HWM_TX	11
+#define DB_HWM_GEN	12
+
+struct s_mbuf_pool {
+#ifndef	MB_OUTSIDE_SMC
+	SMbuf		mb[MAX_MBUF] ;		/* mbuf pool */
+#endif
+	SMbuf		*mb_start ;		/* points to the first mb */
+	SMbuf		*mb_free ;		/* free queue */
+} ;
+
+struct hwm_r {
+	/*
+	 * hardware modul specific receive variables
+	 */
+	u_int			len ;		/* length of the whole frame */
+	char			*mb_pos ;	/* SMbuf receive position */
+} ;
+
+struct hw_modul {
+	/*
+	 * All hardware modul specific variables
+	 */
+	struct	s_mbuf_pool	mbuf_pool ;
+	struct	hwm_r	r ;
+
+	union s_fp_descr volatile *descr_p ; /* points to the desriptor area */
+
+	u_short pass_SMT ;		/* pass SMT frames */
+	u_short pass_NSA ;		/* pass all NSA frames */
+	u_short pass_DB ;		/* pass Direct Beacon Frames */
+	u_short pass_llc_promisc ;	/* pass all llc frames (default ON) */
+
+	SMbuf	*llc_rx_pipe ;		/* points to the first queued llc fr */
+	SMbuf	*llc_rx_tail ;		/* points to the last queued llc fr */
+	int	queued_rx_frames ;	/* number of queued frames */
+
+	SMbuf	*txd_tx_pipe ;		/* points to first mb in the txd ring */
+	SMbuf	*txd_tx_tail ;		/* points to last mb in the txd ring */
+	int	queued_txd_mb ;		/* number of SMT MBufs in txd ring */
+
+	int	rx_break ;		/* rev. was breaked because ind. off */
+	int	leave_isr ;		/* leave fddi_isr immedeately if set */
+	int	isr_flag ;		/* set, when HWM is entered from isr */
+	/*
+	 * varaibles for the current transmit frame
+	 */
+	struct s_smt_tx_queue *tx_p ;	/* pointer to the transmit queue */
+	u_long	tx_descr ;		/* tx descriptor for FORMAC+ */
+	int	tx_len ;		/* tx frame length */
+	SMbuf	*tx_mb ;		/* SMT tx MBuf pointer */
+	char	*tx_data ;		/* data pointer to the SMT tx Mbuf */
+
+	int	detec_count ;		/* counter for out of RxD condition */
+	u_long	rx_len_error ;		/* rx len FORMAC != sum of fragments */
+} ;
+
+
+/*
+ * DEBUG structs and macros
+ */
+
+#ifdef	DEBUG
+struct os_debug {
+	int	hwm_rx ;
+	int	hwm_tx ;
+	int	hwm_gen ;
+} ;
+#endif
+
+#ifdef	DEBUG
+#ifdef	DEBUG_BRD
+#define	DB_P	smc->debug
+#else
+#define DB_P	debug
+#endif
+
+#define DB_RX(a,b,c,lev) if (DB_P.d_os.hwm_rx >= (lev))	printf(a,b,c)
+#define DB_TX(a,b,c,lev) if (DB_P.d_os.hwm_tx >= (lev))	printf(a,b,c)
+#define DB_GEN(a,b,c,lev) if (DB_P.d_os.hwm_gen >= (lev)) printf(a,b,c)
+#else	/* DEBUG */
+#define DB_RX(a,b,c,lev)
+#define DB_TX(a,b,c,lev)
+#define DB_GEN(a,b,c,lev)
+#endif	/* DEBUG */
+
+#ifndef	SK_BREAK
+#define	SK_BREAK()
+#endif
+
+
+/*
+ * HWM Macros
+ */
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_TX_PHYS)
+ *	u_long HWM_GET_TX_PHYS(txd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the physical address of the specified TxD.
+ *
+ * para	txd	pointer to the TxD
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_TX_PHYS(txd)		(u_long)AIX_REVERSE((txd)->txd_tbadr)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_TX_LEN)
+ *	int HWM_GET_TX_LEN(txd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the fragment length of the specified TxD
+ *
+ * para	rxd	pointer to the TxD
+ *
+ * return	the length of the fragment in bytes
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_TX_LEN(txd)	((int)AIX_REVERSE((txd)->txd_tbctrl)& RD_LENGTH)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_TX_USED)
+ *	txd *HWM_GET_TX_USED(smc,queue)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get the
+ *		number of used TxDs for the queue, specified by the index.
+ *
+ * para	queue	the number of the send queue: Can be specified by
+ *		QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0)
+ *
+ * return	number of used TxDs for this send queue
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_TX_USED(smc,queue)	(int) (smc)->hw.fp.tx_q[queue].tx_used
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_CURR_TXD)
+ *	txd *HWM_GET_CURR_TXD(smc,queue)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get the
+ *		pointer to the TxD which points to the current queue put
+ *		position.
+ *
+ * para	queue	the number of the send queue: Can be specified by
+ *		QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0)
+ *
+ * return	pointer to the current TxD
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_CURR_TXD(smc,queue)	(struct s_smt_fp_txd volatile *)\
+					(smc)->hw.fp.tx_q[queue].tx_curr_put
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
+ *	void HWM_TX_CHECK(smc,frame_status,low_water)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro is invoked by the OS-specific before it left it's
+ *		driver_send function. This macro calls mac_drv_clear_txd
+ *		if the free TxDs of the current transmit queue is equal or
+ *		lower than the given low water mark.
+ *
+ * para	frame_status	status of the frame, see design description
+ *	low_water	low water mark of free TxD's
+ *
+ *	END_MANUAL_ENTRY
+ */
+#ifndef HWM_NO_FLOW_CTL
+#define	HWM_TX_CHECK(smc,frame_status,low_water) {\
+	if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
+		mac_drv_clear_txd(smc) ;\
+	}\
+}
+#else
+#define	HWM_TX_CHECK(smc,frame_status,low_water)	mac_drv_clear_txd(smc)
+#endif
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
+ *	int HWM_GET_RX_FRAG_LEN(rxd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the fragment length of the specified RxD
+ *
+ * para	rxd	pointer to the RxD
+ *
+ * return	the length of the fragment in bytes
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_FRAG_LEN(rxd)	((int)AIX_REVERSE((rxd)->rxd_rbctrl)& \
+				RD_LENGTH)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_PHYS)
+ *	u_long HWM_GET_RX_PHYS(rxd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the physical address of the specified RxD.
+ *
+ * para	rxd	pointer to the RxD
+ *
+ * return	the RxD's physical pointer to the data fragment
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_PHYS(rxd)	(u_long)AIX_REVERSE((rxd)->rxd_rbadr)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_USED)
+ *	int HWM_GET_RX_USED(smc)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get
+ *		the count of used RXDs in receive queue 1.
+ *
+ * return	the used RXD count of receive queue 1
+ *
+ * NOTE: Remember, because of an ASIC bug at least one RXD should be unused
+ *	 in the descriptor ring !
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_USED(smc)	((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_used)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_FREE)
+ *	int HWM_GET_RX_FREE(smc)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get
+ *		the rxd_free count of receive queue 1.
+ *
+ * return	the rxd_free count of receive queue 1
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_FREE(smc)	((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_free-1)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_CURR_RXD)
+ *	rxd *HWM_GET_CURR_RXD(smc)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get the
+ *		pointer to the RxD which points to the current queue put
+ *		position.
+ *
+ * return	pointer to the current RxD
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_CURR_RXD(smc)	(struct s_smt_fp_rxd volatile *)\
+				(smc)->hw.fp.rx_q[QUEUE_R1].rx_curr_put
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_RX_CHECK)
+ *	void HWM_RX_CHECK(smc,low_water)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro is invoked by the OS-specific before it left the
+ *		function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd
+ *		if the number of used RxDs is equal or lower than the
+ *		the given low water mark.
+ *
+ * para	low_water	low water mark of used RxD's
+ *
+ *	END_MANUAL_ENTRY
+ */
+#ifndef HWM_NO_FLOW_CTL
+#define	HWM_RX_CHECK(smc,low_water) {\
+	if ((low_water) >= (smc)->hw.fp.rx_q[QUEUE_R1].rx_used) {\
+		mac_drv_fill_rxd(smc) ;\
+	}\
+}
+#else
+#define	HWM_RX_CHECK(smc,low_water)		mac_drv_fill_rxd(smc)
+#endif
+
+#ifndef	HWM_EBASE
+#define	HWM_EBASE	500
+#endif
+
+#define	HWM_E0001	HWM_EBASE + 1
+#define	HWM_E0001_MSG	"HWM: Wrong size of s_rxd_os struct"
+#define	HWM_E0002	HWM_EBASE + 2
+#define	HWM_E0002_MSG	"HWM: Wrong size of s_txd_os struct"
+#define	HWM_E0003	HWM_EBASE + 3
+#define	HWM_E0003_MSG	"HWM: smt_free_mbuf() called with NULL pointer"
+#define	HWM_E0004	HWM_EBASE + 4
+#define	HWM_E0004_MSG	"HWM: Parity error rx queue 1"
+#define	HWM_E0005	HWM_EBASE + 5
+#define	HWM_E0005_MSG	"HWM: Encoding error rx queue 1"
+#define	HWM_E0006	HWM_EBASE + 6
+#define	HWM_E0006_MSG	"HWM: Encoding error async tx queue"
+#define	HWM_E0007	HWM_EBASE + 7
+#define	HWM_E0007_MSG	"HWM: Encoding error sync tx queue"
+#define	HWM_E0008	HWM_EBASE + 8
+#define	HWM_E0008_MSG	""
+#define	HWM_E0009	HWM_EBASE + 9
+#define	HWM_E0009_MSG	"HWM: Out of RxD condition detected"
+#define	HWM_E0010	HWM_EBASE + 10
+#define	HWM_E0010_MSG	"HWM: A protocol layer has tried to send a frame with an invalid frame control"
+#define HWM_E0011	HWM_EBASE + 11
+#define HWM_E0011_MSG	"HWM: mac_drv_clear_tx_queue was called although the hardware wasn't stopped"
+#define HWM_E0012	HWM_EBASE + 12
+#define HWM_E0012_MSG	"HWM: mac_drv_clear_rx_queue was called although the hardware wasn't stopped"
+#define HWM_E0013	HWM_EBASE + 13
+#define HWM_E0013_MSG	"HWM: mac_drv_repair_descr was called although the hardware wasn't stopped"
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/lnkstat.h linux/drivers/net/skfp/h/lnkstat.h
--- v2.3.46/linux/drivers/net/skfp/h/lnkstat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/lnkstat.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Definition of the Error Log Structure
+ * This structure will be copied into the Error Log buffer
+ * during the NDIS General Request ReadErrorLog by the MAC Driver
+ */
+
+struct	s_error_log {
+
+	/*
+	 * place holder for token ring adapter error log (zeros)
+	 */
+	u_char	reserved_0 ;			/* byte 0 inside Error Log */
+	u_char	reserved_1 ;			/* byte 1 */
+	u_char	reserved_2 ;			/* byte 2 */	
+	u_char	reserved_3 ;			/* byte 3 */
+	u_char	reserved_4 ;			/* byte 4 */
+	u_char	reserved_5 ;			/* byte 5 */
+	u_char	reserved_6 ;			/* byte 6 */
+	u_char	reserved_7 ;			/* byte 7 */
+	u_char	reserved_8 ;			/* byte 8 */
+	u_char	reserved_9 ;			/* byte 9 */
+	u_char	reserved_10 ;			/* byte 10 */
+	u_char	reserved_11 ;			/* byte 11 */
+	u_char	reserved_12 ;			/* byte 12 */
+	u_char	reserved_13 ;			/* byte 13 */
+
+	/*
+	 * FDDI link statistics 
+	 */
+/*
+ * smt error low
+ */
+#define SMT_ERL_AEB	(1<<15)			/* A elast. buffer */
+#define SMT_ERL_BLC	(1<<14)			/* B link error condition */
+#define SMT_ERL_ALC	(1<<13)			/* A link error condition */
+#define SMT_ERL_NCC	(1<<12)			/* not copied condition */
+#define SMT_ERL_FEC	(1<<11)			/* frame error condition */
+
+/*
+ * smt event low
+ */
+#define SMT_EVL_NCE	(1<<5)
+
+	u_short	smt_error_low ;			/* byte 14/15 */
+	u_short	smt_error_high ;		/* byte 16/17 */
+	u_short	smt_event_low ;			/* byte 18/19 */
+	u_short	smt_event_high ;		/* byte 20/21 */
+	u_short	connection_policy_violation ;	/* byte 22/23 */
+	u_short port_event ;			/* byte 24/25 */
+	u_short set_count_low ;			/* byte 26/27 */
+	u_short set_count_high ;		/* byte 28/29 */
+	u_short	aci_id_code ;			/* byte 30/31 */
+	u_short	purge_frame_counter ;		/* byte 32/33 */
+
+	/*
+	 * CMT and RMT state machines
+	 */
+	u_short	ecm_state ;			/* byte 34/35 */
+	u_short	pcm_a_state ;			/* byte 36/37 */
+	u_short pcm_b_state ;			/* byte 38/39 */
+	u_short	cfm_state ;			/* byte 40/41 */
+	u_short	rmt_state ;			/* byte 42/43 */
+
+	u_short	not_used[30] ;			/* byte 44-103 */
+
+	u_short	ucode_version_level ;		/* byte 104/105 */
+
+	u_short	not_used_1 ;			/* byte 106/107 */
+	u_short not_used_2 ;			/* byte 108/109 */
+} ;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/mbuf.h linux/drivers/net/skfp/h/mbuf.h
--- v2.3.46/linux/drivers/net/skfp/h/mbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/mbuf.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_MBUF_
+#define _MBUF_
+
+#ifndef PCI
+#define M_SIZE	4550
+#else
+#define M_SIZE	4504
+#endif
+
+#ifndef MAX_MBUF
+#define MAX_MBUF	4
+#endif
+
+#ifndef NO_STD_MBUF
+#define sm_next         m_next
+#define sm_off          m_off
+#define sm_len          m_len
+#define sm_data         m_data
+#define SMbuf           Mbuf
+#define mtod		smtod
+#define mtodoff		smtodoff
+#endif
+
+struct s_mbuf {
+	struct s_mbuf	*sm_next ;		/* low level linked list */
+	short		sm_off ;			/* offset in m_data */
+	u_int		sm_len ;			/* len of data */
+#ifdef	PCI
+	int		sm_use_count ;
+#endif
+	char		sm_data[M_SIZE] ;
+} ;
+
+typedef struct s_mbuf SMbuf ;
+
+/* mbuf head, to typed data */
+#define	smtod(x,t)	((t)((x)->sm_data + (x)->sm_off))
+#define	smtodoff(x,t,o)	((t)((x)->sm_data + (o)))
+
+#endif	/* _MBUF_ */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/osdef1st.h linux/drivers/net/skfp/h/osdef1st.h
--- v2.3.46/linux/drivers/net/skfp/h/osdef1st.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/osdef1st.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/* 
+ * Operating system-dependant definitions that have to be defined
+ * before any other header files are included.
+ */
+
+// HWM (HardWare Module) Definitions
+// -----------------------
+
+#ifdef __LITTLE_ENDIAN
+#define LITTLE_ENDIAN
+#else
+#define BIG_ENDIAN
+#endif
+
+// this is set in the makefile
+// #define PCI			/* only PCI adapters supported by this driver */
+// #define MEM_MAPPED_IO	/* use memory mapped I/O */
+
+
+#define USE_CAN_ADDR		/* DA and SA in MAC header are canonical. */
+
+#define MB_OUTSIDE_SMC		/* SMT Mbufs outside of smc struct. */
+
+// -----------------------
+
+
+// SMT Definitions 
+// -----------------------
+#define SYNC	       		/* allow synchronous frames */
+
+// #define SBA			/* Synchronous Bandwidth Allocator support */
+				/* not available as free source */
+
+#define ESS			/* SBA End Station Support */
+
+#define	SMT_PANIC(smc, nr, msg)	printk(KERN_INFO "SMT PANIC: code: %d, msg: %s\n",nr,msg)
+
+
+#ifdef DEBUG
+#define printf(s,args...) printk(KERN_INFO s, ## args)
+#endif
+
+// #define HW_PTR	u_long
+// -----------------------
+
+
+
+// HWM and OS-specific buffer definitions
+// -----------------------
+
+// default number of receive buffers.
+#define NUM_RECEIVE_BUFFERS		10
+
+// default number of transmit buffers.
+#define NUM_TRANSMIT_BUFFERS		10
+
+// Number of SMT buffers (Mbufs).
+#define NUM_SMT_BUF	4
+
+// Number of TXDs for asynchronous transmit queue.
+#define HWM_ASYNC_TXD_COUNT	(NUM_TRANSMIT_BUFFERS + NUM_SMT_BUF)
+
+// Number of TXDs for synchronous transmit queue.
+#define HWM_SYNC_TXD_COUNT	HWM_ASYNC_TXD_COUNT
+
+
+// Number of RXDs for receive queue #1.
+// Note: Workaround for ASIC Errata #7: One extra RXD is required.
+#if (NUM_RECEIVE_BUFFERS > 100)
+#define SMT_R1_RXD_COUNT	(1 + 100)
+#else
+#define SMT_R1_RXD_COUNT	(1 + NUM_RECEIVE_BUFFERS)
+#endif
+
+// Number of RXDs for receive queue #2.
+#define SMT_R2_RXD_COUNT	0	// Not used.
+// -----------------------
+
+
+
+/*
+ * OS-specific part of the transmit/receive descriptor structure (TXD/RXD).
+ *
+ * Note: The size of these structures must follow this rule:
+ *
+ *	size = 8 + n * 16, n >= 0
+ *
+ * NOTE: The size of this structures may not be changed, because
+ *       libskfddi.a depends on it. But the dummy fields can be
+ *       used freely.
+ */
+
+struct s_txd_os {	// os-specific part of transmit descriptor
+	struct sk_buff *skb;
+	long dummy;
+} ;
+
+struct s_rxd_os {	// os-specific part of receive descriptor
+	struct sk_buff *skb;
+	long dummy;
+} ;
+
+
+
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/sba.h linux/drivers/net/skfp/h/sba.h
--- v2.3.46/linux/drivers/net/skfp/h/sba.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/sba.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Synchronous Bandwith Allocation (SBA) structs
+ */
+ 
+#ifndef _SBA_
+#define _SBA_
+
+#include "h/mbuf.h"
+#include "h/sba_def.h"
+
+#ifdef	SBA
+
+/* Timer Cell Template */
+struct timer_cell {
+	struct timer_cell	*next_ptr ;
+	struct timer_cell	*prev_ptr ;
+	u_long			start_time ;
+	struct s_sba_node_vars	*node_var ;
+} ;
+
+/*
+ * Node variables
+ */
+struct s_sba_node_vars {
+	u_char			change_resp_flag ;
+	u_char			report_resp_flag ;
+	u_char			change_req_flag ;
+	u_char			report_req_flag ;
+	long			change_amount ;
+	long			node_overhead ;
+	long			node_payload ;
+	u_long			node_status ;
+	u_char			deallocate_status ;
+	u_char			timer_state ;
+	u_short			report_cnt ;
+	long			lastrep_req_tranid ;
+	struct fddi_addr	mac_address ;
+	struct s_sba_sessions 	*node_sessions ;
+	struct timer_cell	timer ;
+} ;
+
+/*
+ * Session variables
+ */
+struct s_sba_sessions {
+	u_long			deallocate_status ;
+	long			session_overhead ;
+	u_long			min_segment_size ;
+	long			session_payload ;
+	u_long			session_status ;
+	u_long			sba_category ;
+	long			lastchg_req_tranid ;
+	u_short			session_id ;
+	u_char			class ;
+	u_char			fddi2 ;
+	u_long			max_t_neg ;
+	struct s_sba_sessions	*next_session ;
+} ;
+
+struct s_sba {
+
+	struct s_sba_node_vars	node[MAX_NODES] ;
+	struct s_sba_sessions	session[MAX_SESSIONS] ;
+
+	struct s_sba_sessions	*free_session ;	/* points to the first */
+						/* free session */
+
+	struct timer_cell	*tail_timer ;	/* points to the last timer cell */
+
+	/*
+	 * variables for allocation actions
+	 */
+	long	total_payload ;		/* Total Payload */
+	long	total_overhead ;	/* Total Overhead */
+	long	sba_allocatable ;	/* allocatable sync bandwidth */
+
+	/*
+	 * RAF message receive parameters
+	 */
+	long		msg_path_index ;	/* Path Type */
+	long		msg_sba_pl_req ;	/* Payload Request */
+	long		msg_sba_ov_req ;	/* Overhead Request */
+	long		msg_mib_pl ;		/* Current Payload for this Path */
+	long		msg_mib_ov ;		/* Current Overhead for this Path*/
+	long		msg_category ;		/* Category of the Allocation */
+	u_long		msg_max_t_neg ;		/* longest T_Neg acceptable */
+	u_long		msg_min_seg_siz ;	/* minimum segement size */
+	struct smt_header	*sm ;		/* points to the rec message */
+	struct fddi_addr	*msg_alloc_addr ;	/* Allocation Address */
+
+	/*
+	 * SBA variables
+	 */
+	u_long	sba_t_neg ;		/* holds the last T_NEG */
+	long	sba_max_alloc ;		/* the parsed value of SBAAvailable */	
+
+	/*
+	 * SBA state machine variables
+	 */
+	short	sba_next_state ;	/* the next state of the SBA */
+	char	sba_command ;		/* holds the execuded SBA cmd */
+	u_char	sba_available ;		/* parsed value after possible check */
+} ;
+
+#endif	/* SBA */
+
+	/*
+	 * variables for the End Station Support
+	 */
+struct s_ess {
+
+	/*
+	 * flags and counters
+	 */
+	u_char	sync_bw_available ;	/* is set if sync bw is allocated */
+	u_char	local_sba_active ;	/* set when a local sba is available */
+	char	raf_act_timer_poll ;	/* activate the timer to send allc req */
+	char	timer_count ;		/* counts every timer function call */
+
+	SMbuf	*sba_reply_pend ;	/* local reply for the sba is pending */
+	
+	/*
+	 * variables for the ess bandwidth control
+	 */
+	long	sync_bw ;		/* holds the allocaed sync bw */
+	u_long	alloc_trans_id ;	/* trans id of the last alloc req */
+} ;
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/sba_def.h linux/drivers/net/skfp/h/sba_def.h
--- v2.3.46/linux/drivers/net/skfp/h/sba_def.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/sba_def.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#define PHYS			0		/* physical addr */
+#define PERM_ADDR		0x80		/* permanet address */
+#define SB_STATIC		0x00000001
+#define MAX_PAYLOAD		1562
+#define PRIMARY_RING		0x00000001
+#ifndef NULL
+#define NULL			0x00
+#endif
+
+/*********************** SB_Input Variable Values ***********************/
+/*	 may be needed when ever the SBA state machine is called	*/
+
+#define UNKNOWN_SYNC_SOURCE	0x0001
+#define REQ_ALLOCATION		0x0002
+#define REPORT_RESP		0x0003
+#define CHANGE_RESP		0x0004
+#define TNEG			0x0005
+#define NIF			0x0006
+#define SB_STOP			0x0007
+#define SB_START		0x0008
+#define REPORT_TIMER		0x0009
+#define CHANGE_REQUIRED		0x000A
+
+#define DEFAULT_OV		50
+
+#ifdef SBA
+/**************************** SBA STATES *****************************/
+
+#define SBA_STANDBY		0x00000000
+#define SBA_ACTIVE		0x00000001
+#define SBA_RECOVERY		0x00000002
+#define SBA_REPORT		0x00000003
+#define SBA_CHANGE		0x00000004
+
+/**************************** OTHERS *********************************/
+
+#define FIFTY_PERCENT		50		/* bytes per second */
+#define MAX_SESSIONS		150	
+#define TWO_MINUTES		13079		/* 9.175 ms/tick */
+#define FIFTY_BYTES		50
+#define SBA_DENIED		0x0000000D
+#define I_NEED_ONE		0x00000000
+#define MAX_NODES		50
+/*#define T_REPORT		0x59682F00L*/	/* 120s/80ns in Hex */
+#define	TWO_MIN			120		/* seconds */
+#define SBA_ST_UNKNOWN		0x00000002
+#define SBA_ST_ACTIVE		0x00000001
+#define S_CLEAR			0x00000000L
+#define ZERO			0x00000000
+#define FULL			0x00000000	/* old: 0xFFFFFFFFF */
+#define S_SET			0x00000001L
+#define LOW_PRIO		0x02		/* ??????? */
+#define OK			0x01		/* ??????? */
+#define NOT_OK			0x00		/* ??????? */
+
+/****************************************/
+/* deallocate_status[ni][si] values	*/
+/****************************************/
+#define TX_CHANGE		0X00000001L
+#define PENDING			0x00000002L
+#define NONE			0X00000000L
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/skfbi.h linux/drivers/net/skfp/h/skfbi.h
--- v2.3.46/linux/drivers/net/skfp/h/skfbi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/skfbi.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,1920 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_SKFBI_H_
+#define	_SKFBI_H_
+
+#ifdef SYNC
+#define exist_board_far			exist_board
+#define get_board_para_far		get_board_para
+#endif
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#ifndef	PCI
+#define	ADDR(a)	((a)+smc->hw.iop)
+#define	ADDRS(smc,a) ((a)+(smc)->hw.iop)
+#endif
+
+/*
+ * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)})
+ *	address calculation & function defines
+ */
+
+#ifdef	EISA
+
+/*
+ * Configuration PROM:	 !! all 8-Bit IO's !!
+ *					    |<-	  MAC-Address	 ->|
+ *	/-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
+ * val:	  |PROD_ID0..3|	   | free      |    |00|00|5A|40|    |nn|mm|00|00|
+ *	/-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
+ * IO-	  ^	      ^	   ^		    ^		     ^
+ * port	0C80	    0C83  0C88		   0C90		    0C98
+ *	  |	       \
+ *	  |		\
+ *	  |		 \______________________________________________
+ * EISA Expansion Board Product ID:					\
+ * BIT:	  |7 6 5 4 3 2 1 0|						 \
+ *	  | PROD_ID0	  | PROD_ID1	  | PROD_ID2	  | PROD_ID3	  |
+ *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *	  |0| MAN_C0  | MAN_C1	| MAN_C2  | PROD1 | PROD0 | REV1  | REV0  |
+ *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *	   ^=reserved			  | product numb. | revision numb |
+ * MAN_Cx = compressed manufacterer code (x:=0..2)
+ *	ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!)
+ */
+
+#ifndef	MULT_OEM
+#ifndef	OEM_CONCEPT
+#define	MAN_C0		('S'-0x40)
+#define	MAN_C1		('K'-0x40)
+#define	MAN_C2		('D'-0x40)
+#define	PROD_ID0	(u_char)((MAN_C0<<2) | (MAN_C1>>3))
+#define	PROD_ID1	(u_char)(((MAN_C1<<5) & 0xff) | MAN_C2)
+#define	PROD_ID2	(u_char)(1)	/* prod. nr. */
+#define	PROD_ID3	(u_char)(0)	/* rev. nr. */
+
+#ifndef	OEM_USER_DATA
+#define	OEM_USER_DATA	"SK-NET FDDI V2.0 Userdata"
+#endif
+#else	/*  OEM_CONCEPT */
+
+/* MAN_C(0|1|2) no longer present (ra). */
+#define	PROD_ID0	(u_char)OEM_PROD_ID0
+#define	PROD_ID1	(u_char)OEM_PROD_ID1
+#define	PROD_ID2	(u_char)OEM_PROD_ID2
+#define	PROD_ID3	(u_char)OEM_PROD_ID3
+#endif	/* OEM_CONCEPT */
+
+#define	SKLOGO		PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3
+#endif	/* MULT_OEM */
+
+#define	SADDRL	(0)		/* start address SKLOGO */
+#define	SA_MAC	(0x10)		/* start addr. MAC_AD within the PROM */
+#define	PRA_OFF	(4)
+#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type */
+
+#define	SKFDDI_PSZ	32		/* address PROM size */
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define FMA(a)	(0x0400|((a)<<1))	/* FORMAC+ (r/w) */
+#define P1A(a)	(0x0800|((a)<<1))	/* PLC1 (r/w) */
+#define P2A(a)	(0x0840|((a)<<1))	/* PLC2 (r/w) */
+#define TIA(a)	(0x0880|((a)<<1))	/* Timer (r/w) */
+#define PRA(a)	(0x0c80| (a))		/* configuration PROM */
+#define	C0A(a)	(0x0c84| (a))		/* config. RAM */
+#define	C1A(a)	(0x0ca0| (a))		/* IRQ-, DMA-nr., EPROM type */
+#define	C2A(a)	(0x0ca4| (a))		/* EPROM and PAGE selector */
+
+#define	CONF	C0A(0)			/* config RAM (card enable bit port) */
+#define PGRA	C2A(0)			/* Flash page register */
+#define	CDID	PRA(0)			/* Card ID I/O port addr. offset */
+
+
+/*
+ * physical address offset + slot specific IO-Port base address
+ */
+#define FM_A(a)	(FMA(a)+smc->hw.iop)	/* FORMAC Plus physical addr */
+#define P1_A(a)	(P1A(a)+smc->hw.iop)	/* PLC1 (r/w) */
+#define P2_A(a)	(P2A(a)+smc->hw.iop)	/* PLC2 (r/w) */
+#define TI_A(a)	(TIA(a)+smc->hw.iop)	/* Timer (r/w) */
+#define PR_A(a)	(PRA(a)+smc->hw.iop)	/* config. PROM */
+#define C0_A(a)	(C0A(a)+smc->hw.iop)	/* config. RAM */
+#define C1_A(a)	(C1A(a)+smc->hw.iop)	/* config. RAM */
+#define C2_A(a)	(C2A(a)+smc->hw.iop)	/* config. RAM */
+
+
+#define	CSRA	0x0008		/* control/status register address (r/w) */
+#define	ISRA	0x0008		/* int. source register address (upper 8Bits) */
+#define PLC1I	0x001a		/* clear PLC1 interrupt (write only) */
+#define PLC2I	0x0020		/* clear PLC2 interrupt (write only) */
+#define CSFA	0x001c		/* control/status FIFO BUSY flags (read only) */
+#define RQAA	0x001c		/* Request reg. (write only) */
+#define WCTA	0x001e		/* word counter (r/w) */
+#define	FFLAG	0x005e		/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+#define	CSR_A	(CSRA+smc->hw.iop)	/* control/status register address (r/w) */
+#ifdef UNIX
+#define	CSR_AS(smc)	(CSRA+(smc)->hw.iop)	/* control/status register address (r/w) */
+#endif
+#define	ISR_A	(ISRA+smc->hw.iop)	/* int. source register address (upper 8Bits) */
+#define PLC1_I	(PLC1I+smc->hw.iop)	/* clear PLC1 internupt (write only) */
+#define PLC2_I	(PLC2I+smc->hw.iop)	/* clear PLC2 interrupt (write only) */
+#define CSF_A	(CSFA+smc->hw.iop)	/* control/status FIFO BUSY flags (r/w) */
+#define RQA_A	(RQAA+smc->hw.iop)	/* Request reg. (write only) */
+#define WCT_A	(WCTA+smc->hw.iop)	/* word counter (r/w) */
+#define	FFLAG_A	(FFLAG+smc->hw.iop)	/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+/*
+ * control/status register CSRA	bits
+ */
+/* write */
+#define CS_CRESET	0x01		/* Card reset (0=reset) */
+#define	CS_RESET_FIFO	0x02		/* FIFO reset (0=reset) */
+#define	CS_IMSK		0x04		/* enable IRQ (1=enable, 0=disable) */
+#define	CS_EN_IRQ_TC	0x08		/* enable IRQ from transfer counter */
+#define CS_BYPASS	0x20		/* bypass switch (0=remove, 1=insert)*/
+#define CS_LED_0	0x40		/* switch LED 0 */
+#define	CS_LED_1	0x80		/* switch LED 1 */
+/* read */
+#define	CS_BYSTAT	0x40		/* 0=Bypass exist, 1= ..not */
+#define	CS_SAS		0x80		/* single attachement station (=1) */
+
+/*
+ * control/status register CSFA bits (FIFO)
+ */
+#define	CSF_MUX0	0x01
+#define	CSF_MUX1	0x02
+#define	CSF_HSREQ0	0x04
+#define	CSF_HSREQ1	0x08
+#define	CSF_HSREQ2	0x10
+#define	CSF_BUSY_DMA	0x40
+#define	CSF_BUSY_FIFO	0x80
+
+/*
+ * Interrupt source register ISRA (upper 8 data bits) read only & low activ.
+ */
+#define IS_MINTR1	0x0100		/* FORMAC ST1U/L & ~IMSK1U/L*/
+#define IS_MINTR2	0x0200		/* FORMAC ST2U/L & ~IMSK2U/L*/
+#define IS_PLINT1	0x0400		/* PLC1 */
+#define IS_PLINT2	0x0800		/* PLC2 */
+#define IS_TIMINT	0x1000		/* Timer 82C54-2 */
+#define	IS_TC		0x2000		/* transf. counter */
+
+#define	ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC)
+
+/*
+ * CONFIG<0> RAM (C0_A())
+ */
+#define	CFG_CARD_EN	0x01		/* card enable */
+
+/*
+ * CONFIG<1> RAM (C1_A())
+ */
+#define	CFG_IRQ_SEL	0x03		/* IRQ select (4 nr.) */
+#define	CFG_IRQ_TT	0x04		/* IRQ trigger type (LEVEL/EDGE) */
+#define	CFG_DRQ_SEL	0x18		/* DMA requ. (4 nr.) */
+#define	CFG_BOOT_EN	0x20		/* 0=BOOT-, 1=Application Software */
+#define	CFG_PROG_EN	0x40		/* V_Prog for FLASH_PROM (1=on) */
+
+/*
+ * CONFIG<2> RAM (C2_A())
+ */
+#define	CFG_EPROM_SEL	0x0f		/* FPROM start address selection */
+#define	CFG_PAGE	0xf0		/* FPROM page selection */
+
+
+#define	READ_PROM(a)	((u_char)inp(a))
+#define	GET_PAGE(i)	outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE))
+#define	FPROM_SW()	(inp(C1_A(0)) & CFG_BOOT_EN)
+
+#define	MAX_PAGES	16		/* 16 pages */
+#define	MAX_FADDR	0x2000		/* 8K per page */
+#define	VPP_ON()	outp(C1_A(0),inp(C1_A(0)) |  CFG_PROG_EN)
+#define	VPP_OFF()	outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN)
+
+#define	DMA_BUSY()	(inpw(CSF_A) & CSF_BUSY_DMA)
+#define FIFO_BUSY()	(inpw(CSF_A) & CSF_BUSY_FIFO)
+#define	DMA_FIFO_BUSY()	(inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
+#define	BUS_CHECK()
+
+#ifdef UNISYS
+/* For UNISYS use another macro with drv_usecewait function */
+#define CHECK_DMA() {u_long k = 1000000; \
+		while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \
+		if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+#else
+#define CHECK_DMA() {u_long k = 1000000 ;\
+		while (k && (DMA_BUSY())) k-- ;\
+		if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+#endif
+
+#define CHECK_FIFO() {u_long k = 1000000 ;\
+		while (k && (FIFO_BUSY())) k-- ;\
+		if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
+
+#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
+		while (k && (DMA_FIFO_BUSY())) k-- ;\
+		if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
+
+#define	GET_ISR()	~inpw(ISR_A)
+#define CHECK_ISR()	~inpw(ISR_A)
+
+#ifndef UNIX
+#ifndef	WINNT
+#define	CLI_FBI()	outpw(CSR_A,(inpw(CSR_A)&\
+			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
+#else	/* WINNT */
+#define CLI_FBI()	outpw(CSR_A,(l_inpw(CSR_A)&\
+			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
+#endif	/* WINNT */
+#else	/* UNIX */
+#define	CLI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
+			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led)
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outpw(CSR_A,(inpw(CSR_A)&\
+		(CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led)
+#else
+#define	STI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
+		(CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led)
+#endif
+
+/* EISA DMA Controller */
+#define DMA_WRITE_SINGLE_MASK_BIT_M	0x0a	/* Master DMA Controller */
+#define DMA_WRITE_SINGLE_MASK_BIT_S	0xd4	/* Slave DMA Controller */
+#define DMA_CLEAR_BYTE_POINTER_M	0x0c
+#define DMA_CLEAR_BYTE_POINTER_S	0xd8
+
+#endif	/* EISA */
+
+#ifdef	MCA
+
+/*
+ * POS Register:	 !! all I/O's are 8-Bit !!
+ */
+#define	POS_SYS_SETUP	0x94	/* system setup register */
+#define	POS_SYSTEM	0xff	/* system mode */
+
+#define	POS_CHANNEL_POS	0x96	/* register slot ID */
+#define	POS_CHANNEL_BIT	0x08	/* mask for -"- */
+
+#define	POS_BASE	0x100	/* POS base address */
+#define	POS_ID_LOW	POS_BASE	/* card ID low */
+#define	POS_ID_HIGH	(POS_BASE+1)	/* card ID high */
+#define	POS_102		(POS_BASE+2)	/* card en., arbitration level .. */
+#define	POS_103		(POS_BASE+3)	/* FPROM addr, page */
+#define	POS_104		(POS_BASE+4)	/* I/O, IRQ */
+#define	POS_105		(POS_BASE+5)	/* POS_CHCK */
+#define	POS_106		(POS_BASE+6)	/* to read VPD */
+#define	POS_107		(POS_BASE+7)	/* added without function */
+
+/* FM1 card IDs */
+#define	FM1_CARD_ID0	0x83
+#define	FM1_CARD_ID1	0
+
+#define	FM1_IBM_ID0	0x9c
+#define	FM1_IBM_ID1	0x8f
+
+
+/* FM2 card IDs */
+#define	FM2_CARD_ID0	0xab
+#define	FM2_CARD_ID1	0
+
+#define	FM2_IBM_ID0	0x7e
+#define	FM2_IBM_ID1	0x8f
+
+/* Board revision. */
+#define FM1_REV		0
+#define FM2_REV		1
+
+#define	MAX_SLOT	8
+
+/*
+ * POS_102
+ */
+#define	POS_CARD_EN	0x01	/* card enable =1 */
+#define	POS_SDAT_EN	0x02	/* enable 32-bit streaming data mode */
+#define	POS_EN_CHKINT	0x04	/* enable int. from check line asserted */
+#define	POS_EN_BUS_ERR	0x08	/* enable int. on invalid busmaster transf. */
+#define	POS_FAIRNESS	0x10	/* fairnes on =1 */
+/* attention: arbitration level used with bit 0 POS 105 */
+#define	POS_LARBIT	0xe0	/* arbitration level	(0,0,0)->level = 0x8
+							(1,1,1)->level = 0xf */
+/*
+ * POS_103
+ */
+#define	POS_PAGE	0x07	/* FPROM page selection */
+#define	POS_BOOT_EN	0x08	/* boot PROM enable =1 */
+#define	POS_MSEL	0x70	/* memory start address for FPROM mapping */
+#define	PROG_EN		0x80	/* FM1: Vpp prog on/off */
+#define	POS_SDR		0x80	/* FM2: Streaming data bit */
+
+/*
+ * POS_104
+ */
+#define	POS_IOSEL	0x3f	/* selected I/O base address */
+#define	POS_IRQSEL	0xc0	/* selected interrupt */
+
+/*
+ * POS_105
+ */
+#define	POS_CHCK	0x80
+#define POS_SYNC_ERR	0x20	/* FM2: synchronous error reporting	*/
+#define POS_PAR_DATA	0x10	/* FM2: data parity enable bit	*/
+#define POS_PAR_ADDR	0x08	/* FM2: address parity enable bit	*/
+#define	POS_IRQHSEL	0x02	/* FM2: Highest bit for IRQ_selection	*/
+#define POS_HARBIT	0x01	/* Highest bit in Bus arbitration selection */
+
+#define	SA_MAC	(0)		/* start addr. MAC_AD within the PROM	*/
+#define	PRA_OFF	(0)
+#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type	*/
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define	FMA(a)	(0x0100|((a)<<1))	/* FORMAC+ (r/w) */
+#define	P2(a)	(0x00c0|((a)<<1))	/* PLC2 (r/w) (DAS) */
+#define	P1(a)	(0x0080|((a)<<1))	/* PLC1 (r/w) */
+#define	TI(a)	(0x0060|((a)<<1))	/* Timer (r/w) */
+#define	PR(a)	(0x0040|((a)<<1))	/* configuration PROM */
+#define	CS(a)	(0x0020| (a))		/* control/status */
+#define	FF(a)	(0x0010|((a)<<1))	/* FIFO ASIC */
+#define	CT(a)	(0x0000|((a)<<1))	/* counter */
+
+/*
+ * counter
+ */
+#define	ACLA	CT(0)		/* address counter low */
+#define	ACHA	CT(1)		/* address counter high */
+#define	BCN	CT(2)		/* byte counter */
+#define	MUX	CT(3)		/* MUX-register */
+#define	WCN	CT(0x08)	/* word counter */
+#define	FFLG	CT(0x09)	/* FIFO Flags */
+
+/*
+ * test/control register (FM2 only)
+ */
+#define CNT_TST	0x018		/* Counter test control register */
+#define CNT_STP 0x01a		/* Counter test step reg. (8 Bit) */
+
+/*
+ * CS register (read only)
+ */
+#define	CSRA	CS(0)		/* control/status register address */
+#define	CSFA	CS(2)		/* control/status FIFO BUSY ...	 */
+#define	ISRA	CS(4)		/* first int. source register address */
+#define	ISR2	CS(6)		/* second int. source register address */
+#define	LEDR	CS(0x0c)	/* LED register r/w */
+#define	CSIL	CS(0x10)	/* I/O mapped POS_ID_low (100) */
+#define	CSIH	CS(0x12)	/*	- " - POS_ID_HIGH (101) */
+#define	CSA	CS(0x14)	/*	- " - POS_102 */
+#define	CSM	CS(0x0e)	/*	- " - POS_103 */
+#define	CSM_FM1	CS(0x16)	/*	- " - POS_103 (copy in FM1) */
+#define	CSI	CS(0x18)	/*	- " - POS_104 */
+#define	CSS	CS(0x1a)	/*	- " - POS_105 */
+#define	CSP_06	CS(0x1c)	/*	- " - POS_106 */
+#define	WDOG_ST		0x1c	/* Watchdog status (FM2 only)	*/
+#define	WDOG_EN		0x1c	/* Watchdog enabling (FM2 only, 8Bit)	*/
+#define	WDOG_DIS	0x1e	/* Watchdog disabling (FM2 only, 8Bit)	*/
+
+#define PGRA	CSM		/* Flash page register */
+
+
+#define	WCTA	FF(0)		/* word counter */
+#define	FFLAG	FF(1)		/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+/*
+ * Timer register (FM2 only)
+ */
+#define RTM_CNT		0x28		/* RTM Counter */
+#define TI_DIV		0x60		/* Timer Prescaler */
+#define TI_CH1		0x62		/* Timer channel 1 counter */
+#define TI_STOP		0x64		/* Stop timer on channel 1 */
+#define TI_STRT		0x66		/* Start timer on channel 1 */
+#define TI_INI2		0x68		/* Timer: Bus master preemption */
+#define TI_CNT2		0x6a		/* Timer */
+#define TI_INI3		0x6c		/* Timer: Streaming data */
+#define TI_CNT3		0x6e		/* Timer */
+#define WDOG_LO		0x70		/* Watchdog counter low */
+#define WDOG_HI		0x72		/* Watchdog counter high */
+#define RTM_PRE		0x74		/* restr. token prescaler */
+#define RTM_TIM		0x76		/* restr. token timer */
+
+/*
+ * Recommended Timeout values (for FM2 timer only)
+ */
+#define TOUT_BM_PRE	188		/* 3.76 usec	*/
+#define TOUT_S_DAT	374		/* 7.48 usec	*/
+
+/*
+ * CS register (write only)
+ */
+#define	HSR(p)	CS(0x18|(p))	/* Host request register */
+
+#define	RTM_PUT		0x36		/* restr. token counter write */
+#define	RTM_GET		0x28		/*	- " -	clear */
+#define	RTM_CLEAR	0x34		/*	- " -	read */
+
+/*
+ * BCN	Bit definitions
+ */
+#define BCN_BUSY	0x8000		/* DMA Busy flag */
+#define BCN_AZERO	0x4000		/* Almost zero flag (BCN < 4) */
+#define BCN_STREAM	0x2000		/* Allow streaming data (BCN >= 8) */
+
+/*
+ * WCN	Bit definitions
+ */
+#define WCN_ZERO	0x2000		/* Zero flag (counted to zero) */
+#define WCN_AZERO	0x1000		/* Almost zero flag (BCN < 4) */
+
+/*
+ * CNT_TST	Bit definitions
+ */
+#define CNT_MODE	0x01		/* Go into test mode */
+#define	CNT_D32		0x02		/* 16/32 BIT test mode */
+
+/*
+ * FIFO Flag		FIFO Flags/Vfull register
+ */
+#define FF_VFULL	0x003f		/* V_full value mask */
+#define FFLG_FULL	0x2000		/* FULL flag */
+#define FFLG_A_FULL	0x1000		/* Almost full flag */
+#define FFLG_VFULL	0x0800		/* V_full Flag */
+#define FFLG_A_EMP	0x0400		/* almost empty flag */
+#define FFLG_EMP	0x0200		/* empty flag */
+#define FFLG_T_EMP	0x0100		/* totally empty flag */
+
+/*
+ * WDOG		Watchdog status register
+ */
+#define WDOG_ALM	0x01		/* Watchdog alarm Bit */
+#define WDOG_ACT	0x02		/* Watchdog active Bit */
+
+/*
+ * CS(0)	CONTROLS
+ */
+#define	CS_CRESET	0x0001
+#define	FIFO_RST	0x0002
+#define	CS_IMSK		0x0004
+#define	EN_IRQ_CHCK	0x0008
+#define	EN_IRQ_TOKEN	0x0010
+#define	EN_IRQ_TC	0x0020
+#define	TOKEN_STATUS	0x0040
+#define	RTM_CHANGE	0x0080
+
+#define	CS_SAS		0x0100
+#define	CS_BYSTAT	0x0200	/* bypass connected (0=conn.) */
+#define	CS_BYPASS	0x0400	/* bypass on/off indication */
+
+/*
+ * CS(2)	FIFOSTAT
+ */
+#define	HSREQ		0x0007
+#define	BIGDIR		0x0008
+#define	CSF_BUSY_FIFO	0x0010
+#define	CSF_BUSY_DMA	0x0020
+#define	SLOT_32		0x0040
+
+#define	LED_0		0x0001
+#define	LED_1		0x0002
+#define	LED_2		0x0100
+
+#define	MAX_PAGES	8		/* pages */
+#define	MAX_FADDR	0x4000		/* 16K per page */
+
+/*
+ *	IRQ = ISRA || ISR2 ;
+ *
+ *	ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ;
+ *	ISR2 = IRQ_TC_EN && IS_TC ;
+ *
+ *	IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) ||
+ *		 (IRQ_EN_TOKEN && IS_TOKEN) ;
+ *	IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ;
+ */
+/*
+ *	ISRA	!!! activ high !!!
+ */
+#define	IS_MINTR1	0x0001		/* FORMAC ST1U/L & ~IMSK1U/L*/
+#define	IS_MINTR2	0x0002		/* FORMAC ST2U/L & ~IMSK2U/L*/
+#define	IS_PLINT1	0x0004		/* PLC1 */
+#define	IS_PLINT2	0x0008		/* PLC2 */
+#define	IS_TIMINT	0x0010		/* Timer 82C54-2 */
+#define	IS_TOKEN	0x0020		/* restrictet token monitoring */
+#define	IS_CHCK_L	0x0040		/* check line asserted */
+#define	IS_BUSERR	0x0080		/* bus error */
+/*
+ *	ISR2
+ */
+#define	IS_TC		0x0001		/* terminal count irq */
+#define IS_SFDBKRTN	0x0002		/* selected feedback return */
+#define IS_D16		0x0004		/* DS16 */
+#define	IS_D32		0x0008		/* DS32 */
+#define IS_DPEI		0x0010		/* Data Parity Indication */
+
+#define	ALL_IRSR	0x00ff
+
+#define	FM_A(a)	ADDR(FMA(a))	/* FORMAC Plus physical addr */
+#define	P1_A(a)	ADDR(P1(a))	/* PLC1 (r/w) */
+#define	P2_A(a)	ADDR(P2(a))	/* PLC2 (r/w) (DAS) */
+#define	TI_A(a)	ADDR(TI(a))	/* Timer (r/w) FM1 only! */
+#define	PR_A(a)	ADDR(PR(a))	/* config. PROM */
+#define	CS_A(a)	ADDR(CS(a))	/* control/status */
+
+#define	ISR1_A	ADDR(ISRA)	/* first int. source register address */
+#define	ISR2_A	ADDR(ISR2)	/* second	-"-	 */
+#define	CSR_A	ADDR(CSRA)	/* control/status register address */
+#define	CSF_A	ADDR(CSFA)	/* control/status FIFO BUSY flags (r/w) */
+
+#define	CSIL_A	ADDR(CSIL)	/* I/O mapped POS_ID_low (102) */
+#define	CSIH_A	ADDR(CSIH)	/*	- " - POS_ID_HIGH (101) */
+#define	CSA_A	ADDR(CSA)	/*	- " - POS_102 */
+#define	CSI_A	ADDR(CSI)	/*	- " - POS_104 */
+#define	CSM_A	ADDR(CSM)	/*	- " - POS_103 */
+#define	CSM_FM1_A	ADDR(CSM_FM1)	/*	- " - POS_103 (2nd copy, FM1) */
+#define	CSP_06_A	ADDR(CSP_06)	/*	- " - POS_106 */
+
+#define	WCT_A	ADDR(WCTA)	/* word counter (r/w) */
+#define	FFLAG_A	ADDR(FFLAG)	/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+#define	ACL_A	ADDR(ACLA)	/* address counter low */
+#define	ACH_A	ADDR(ACHA)	/* address counter high */
+#define	BCN_A	ADDR(BCN)	/* byte counter */
+#define	MUX_A	ADDR(MUX)	/* MUX-register */
+
+#define	ISR_A	ADDR(ISRA)	/* Interrupt Source Register */
+#define	FIFO_RESET_A	ADDR(FIFO_RESET)	/* reset the FIFO */
+#define	FIFO_EN_A	ADDR(FIFO_EN)		/* enable the FIFO */
+
+#define WDOG_EN_A	ADDR(WDOG_EN)		/* reset and start the WDOG */
+#define WDOG_DIS_A	ADDR(WDOG_DIS)		/* disable the WDOG */
+/*
+ * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A)
+ */
+#define	HSR_A(p)	ADDR(HSR(p))	/* Host request register */
+
+#define	STAT_BYP	0		/* bypass station */
+#define	STAT_INS	2		/* insert station */
+#define	BYPASS(o)	CS(0x10|(o))	/* o=STAT_BYP || STAT_INS */
+
+#define	IRQ_TC_EN	CS(0x0b)	/* enable/disable IRQ on TC */
+#define	IRQ_TC_DIS	CS(0x0a)
+#define	IRQ_TOKEN_EN	CS(9)		/* enable/disable IRQ on restr. Token */
+#define	IRQ_TOKEN_DIS	CS(8)
+#define	IRQ_CHCK_EN	CS(7)		/*	-"-	IRQ after CHCK line */
+#define	IRQ_CHCK_DIS	CS(6)
+#define	IRQ_OTH_EN	CS(5)		/*	-"-	other IRQ's */
+#define	IRQ_OTH_DIS	CS(4)
+#define	FIFO_EN		CS(3)		/* disable (reset), enable FIFO */
+#define	FIFO_RESET	CS(2)
+#define	CARD_EN		CS(1)		/* disable (reset), enable card */
+#define	CARD_DIS	CS(0)
+
+#define	LEDR_A		ADDR(LEDR)	/* D0=green, D1=yellow, D8=L2 */
+#define	PAGE_RG_A	ADDR(CSM)	/* D<2..0> */
+#define	IRQ_CHCK_EN_A	ADDR(IRQ_CHCK_EN)
+#define IRQ_CHCK_DIS_A	ADDR(IRQ_CHCK_DIS)
+
+#define	GET_PAGE(bank)	outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\
+				(~POS_PAGE)) |(int) (bank))
+#define	VPP_ON()	if (smc->hw.rev == FM1_REV) {	\
+				outpw(PAGE_RG_A,	\
+				(inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \
+			}
+#define	VPP_OFF()	if (smc->hw.rev == FM1_REV) {	\
+				outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \
+			}
+
+#define	SKFDDI_PSZ	16		/* address PROM size */
+
+#define	READ_PROM(a)	((u_char)inp(a))
+
+#define	GET_ISR()	~inpw(ISR1_A)
+#ifndef	TCI
+#define	CHECK_ISR()	~inpw(ISR1_A)
+#define	CHECK_ISR_SMP(iop)	~inpw((iop)+ISRA)
+#else
+#define	CHECK_ISR()		(~inpw(ISR1_A) | ~inpw(ISR2_A))
+#define	CHECK_ISR_SMP(iop)	(~inpw((iop)+ISRA) | ~inpw((iop)+ISR2))
+#endif
+
+#define	DMA_BUSY()	(inpw(CSF_A) & CSF_BUSY_DMA)
+#define	FIFO_BUSY()	(inpw(CSF_A) & CSF_BUSY_FIFO)
+#define	DMA_FIFO_BUSY()	(inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
+#define	BUS_CHECK() {	int i ; \
+			if ((i = GET_ISR()) & IS_BUSERR) \
+				SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \
+			if (i & IS_CHCK_L) \
+				SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \
+		}
+
+#define	CHECK_DMA() {	u_long k = 10000 ; \
+		 while (k && (DMA_BUSY())) { \
+			k-- ; \
+			BUS_CHECK() ; \
+		 } \
+		 if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+
+#define	CHECK_FIFO() {u_long k = 1000000 ;\
+		 while (k && (FIFO_BUSY())) k-- ;\
+		 if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
+
+#define	CHECK_DMA_FIFO() {u_long k = 1000000 ;\
+		 while (k && (DMA_FIFO_BUSY())) { \
+			k-- ;\
+			BUS_CHECK() ; \
+		 } \
+		 if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
+
+#ifndef UNIX
+#define	CLI_FBI()	outp(ADDR(IRQ_OTH_DIS),0)
+#else
+#define	CLI_FBI(smc)	outp(ADDRS((smc),IRQ_OTH_DIS),0)
+#endif
+
+#ifndef	TCI
+#define	CLI_FBI_SMP(iop)	outp((iop)+IRQ_OTH_DIS,0)
+#else
+#define	CLI_FBI_SMP(iop)	outp((iop)+IRQ_OTH_DIS,0) ;\
+				outp((iop)+IRQ_TC_DIS,0)
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outp(ADDR(IRQ_OTH_EN),0)
+#else
+#define	STI_FBI(smc)	outp(ADDRS((smc),IRQ_OTH_EN),0)
+#endif
+
+/*
+ * Terminal count primitives
+ */
+#define CLI_TCI(smc)	outp(ADDRS((smc),IRQ_TC_DIS),0)
+#define STI_TCI(smc)	outp(ADDRS((smc),IRQ_TC_EN),0)
+#define CHECK_TC(smc,k)	{(k) = 10000 ;\
+	while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\
+	if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; }
+
+#endif	/* MCA */
+
+#ifdef	ISA
+
+/*
+ * address transmision from logic NPADDR6-0 to physical offset address on board
+ */
+#define FMA(a)	(0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7))  /* FORMAC+ (r/w) */
+#define PRA(a)	(0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PROM (read only)*/
+#define P1A(a)	(0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PLC1 (r/w) */
+#define P2A(a)	(0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PLC2 (r/w) */
+#define TIA(a)	(0x6000|(((a)&0x03)<<1))		  /* Timer (r/w) */
+
+#define	ISRA	0x0000		/* int. source register address (read only) */
+#define	ACLA	0x0000		/* address counter low address (write only) */
+#define	ACHA	0x0002		/* address counter high address (write only) */
+#define	TRCA	0x0004		/* transfer counter address (write only) */
+#define	PGRA	0x0006		/* page register address (write only) */
+#define RQAA	0x2000		/* Request reg. (write only) */
+#define	CSRA	0x3000		/* control/status register address (r/w) */
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#define FM_A(a)	(FMA(a)+smc->hw.iop)	/* FORMAC Plus physical addr */
+#define PR_A(a)	(PRA(a)+smc->hw.iop)	/* PROM (read only)*/
+#define P1_A(a)	(P1A(a)+smc->hw.iop)	/* PLC1 (r/w) */
+#define P2_A(a)	(P2A(a)+smc->hw.iop)	/* PLC2 (r/w) */
+#define TI_A(a)	(TIA(a)+smc->hw.iop)	/* Timer (r/w) */
+
+#define	ISR_A	(0x0000+smc->hw.iop) /* int. source register address (read only) */
+#define	ACL_A	(0x0000+smc->hw.iop) /* address counter low address (write only) */
+#define	ACH_A	(0x0002+smc->hw.iop) /* address counter high address (write only)*/
+#define	TRC_A	(0x0004+smc->hw.iop) /* transfer counter address (write only) */
+#define	PGR_A	(0x0006+smc->hw.iop) /* page register address (write only) */
+#define RQA_A	(0x2000+smc->hw.iop) /* Request reg. (write only) */
+#define	CSR_A	(0x3000+smc->hw.iop) /* control/status register address (r/w) */
+#ifdef UNIX
+#define	CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */
+#endif
+#define	PLC1_I	(0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */
+#define	PLC2_I	(0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */
+
+#ifndef	MULT_OEM
+#ifndef	OEM_CONCEPT
+#define	SKLOGO_STR	"SKFDDI"
+#else	/* OEM_CONCEPT */
+#define	SKLOGO_STR	OEM_FDDI_LOGO
+#endif	/* OEM_CONCEPT */
+#endif  /* MULT_OEM */
+#define	SADDRL	(24)		/* start address SKLOGO */
+#define	SA_MAC	(0)		/* start addr. MAC_AD within the PROM */
+#define	PRA_OFF	(0)
+#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type */
+
+#define	CDID	(PRA(SADDRL))	/* Card ID int/O port addr. offset */
+#define	NEXT_CDID	((PRA(SADDRL+1)) - CDID)
+
+#define	SKFDDI_PSZ	32		/* address PROM size */
+
+#define	READ_PROM(a)	((u_char)inpw(a))
+#define	GET_PAGE(i)	outpw(PGR_A,(int)(i))
+
+#define	MAX_PAGES	16		/* 16 pages */
+#define	MAX_FADDR	0x2000		/* 8K per page */
+#define	VPP_OFF()	outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)))
+#define	VPP_ON()	outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \
+				CS_VPPSW)
+
+/*
+ * control/status register CSRA	bits (log. addr: 0x3000)
+ */
+/* write */
+#define CS_CRESET	0x01		/* Card reset (0=reset) */
+#define	CS_IMSK		0x02		/* enable IRQ (1=enable, 0=disable) */
+#define CS_RESINT1	0x04		/* PLINT1 reset */
+#define	CS_VPPSW	0x10		/* 12V power switch (0=off, 1=on) */
+#define CS_BYPASS	0x20		/* bypass switch (0=remove, 1=insert)*/
+#define CS_RESINT2	0x40		/* PLINT2 reset */
+/* read */
+#define	CS_BUSY		0x04		/* master transfer activ (=1) */
+#define	CS_SW_EPROM	0x08		/* 0=Application Soft. 1=BOOT-EPROM */
+#define	CS_BYSTAT	0x40		/* 0=Bypass exist, 1= ..not */
+#define	CS_SAS		0x80		/* single attachement station (=1) */
+
+/*
+ * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ.
+ */
+#define IS_MINTR1	0x01		/* FORMAC ST1U/L && ~IMSK1U/L*/
+#define IS_MINTR2	0x02		/* FORMAC ST2U/L && ~IMSK2U/L*/
+#define IS_PLINT1	0x04		/* PLC1 */
+#define IS_PLINT2	0x08		/* PLC2 */
+#define IS_TIMINT	0x10		/* Timer 82C54-2 */
+
+#define	ALL_IRSR	(IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT)
+
+#define	FPROM_SW()	(inpw(CSR_A)&CS_SW_EPROM)
+#define	DMA_BUSY()	(inpw(CSR_A)&CS_BUSY)
+#define CHECK_FIFO()
+#define	BUS_CHECK()
+
+/*
+ * set Host Request register (wr.)
+ */
+#define SET_HRQ(qup)	outpw(RQA_A+((qup)<<1),0)
+
+#ifndef UNIX
+#ifndef WINNT
+#define	CLI_FBI()	outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#else
+#define	CLI_FBI()	outpw(CSR_A,(l_inpw(CSR_A) & \
+				(CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#endif
+#else
+#define	CLI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \
+						(CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outpw(CSR_A,(inpw(CSR_A) & \
+				(CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
+#else
+#define	STI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \
+				(CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
+#endif
+
+#define CHECK_DMA()	{unsigned k = 10000 ;\
+			while (k && (DMA_BUSY())) k-- ;\
+			if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+
+#define	GET_ISR()	~inpw(ISR_A)
+
+#endif	/* ISA */
+
+/*--------------------------------------------------------------------------*/
+#ifdef	PCI
+
+/*
+ *	(DV)	= only defined for Da Vinci
+ *	(ML)	= only defined for Monalisa
+ */
+
+/*
+ * Configuration Space header
+ */
+#define	PCI_VENDOR_ID	0x00	/* 16 bit	Vendor ID */
+#define	PCI_DEVICE_ID	0x02	/* 16 bit	Device ID */
+#define	PCI_COMMAND	0x04	/* 16 bit	Command */
+#define	PCI_STATUS	0x06	/* 16 bit	Status */
+#define	PCI_REV_ID	0x08	/*  8 bit	Revision ID */
+#define	PCI_CLASS_CODE	0x09	/* 24 bit	Class Code */
+#define	PCI_CACHE_LSZ	0x0c	/*  8 bit	Cache Line Size */
+#define	PCI_LAT_TIM	0x0d	/*  8 bit	Latency Timer */
+#define	PCI_HEADER_T	0x0e	/*  8 bit	Header Type */
+#define	PCI_BIST	0x0f	/*  8 bit	Built-in selftest */
+#define	PCI_BASE_1ST	0x10	/* 32 bit	1st Base address */
+#define	PCI_BASE_2ND	0x14	/* 32 bit	2nd Base address */
+/* Byte 18..2b:	Reserved */
+#define	PCI_SUB_VID	0x2c	/* 16 bit	Subsystem Vendor ID */
+#define	PCI_SUB_ID	0x2e	/* 16 bit	Subsystem ID */
+#define	PCI_BASE_ROM	0x30	/* 32 bit	Expansion ROM Base Address */
+/* Byte 34..33:	Reserved */
+#define PCI_CAP_PTR	0x34	/*  8 bit (ML)	Capabilities Ptr */
+/* Byte 35..3b:	Reserved */
+#define	PCI_IRQ_LINE	0x3c	/*  8 bit	Interrupt Line */
+#define	PCI_IRQ_PIN	0x3d	/*  8 bit	Interrupt Pin */
+#define	PCI_MIN_GNT	0x3e	/*  8 bit	Min_Gnt */
+#define	PCI_MAX_LAT	0x3f	/*  8 bit	Max_Lat */
+/* Device Dependent Region */
+#define	PCI_OUR_REG	0x40	/* 32 bit (DV)	Our Register */
+#define	PCI_OUR_REG_1	0x40	/* 32 bit (ML)	Our Register 1 */
+#define	PCI_OUR_REG_2	0x44	/* 32 bit (ML)	Our Register 2 */
+/* Power Management Region */
+#define PCI_PM_CAP_ID	0x48	/*  8 bit (ML)	Power Management Cap. ID */
+#define PCI_PM_NITEM	0x49	/*  8 bit (ML)	Next Item Ptr */
+#define PCI_PM_CAP_REG	0x4a	/* 16 bit (ML)	Power Management Capabilities */
+#define PCI_PM_CTL_STS	0x4c	/* 16 bit (ML)	Power Manag. Control/Status */
+/* Byte 0x4e:	Reserved */
+#define PCI_PM_DAT_REG	0x4f	/*  8 bit (ML)	Power Manag. Data Register */
+/* VPD Region */
+#define	PCI_VPD_CAP_ID	0x50	/*  8 bit (ML)	VPD Cap. ID */
+#define PCI_VPD_NITEM	0x51	/*  8 bit (ML)	Next Item Ptr */
+#define PCI_VPD_ADR_REG	0x52	/* 16 bit (ML)	VPD Address Register */
+#define PCI_VPD_DAT_REG	0x54	/* 32 bit (ML)	VPD Data Register */
+/* Byte 58..ff:	Reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ *	 I2C bus.
+ */
+#define I2C_ADDR_VPD	0xA0	/* I2C address for the VPD EEPROM */ 
+
+/*
+ * Define Bits and Values of the registers
+ */
+/*	PCI_VENDOR_ID	16 bit	Vendor ID */
+/*	PCI_DEVICE_ID	16 bit	Device ID */
+/* Values for Vendor ID and Device ID shall be patched into the code */
+/*	PCI_COMMAND	16 bit	Command */
+#define	PCI_FBTEN	0x0200	/* Bit 9:	Fast Back-To-Back enable */
+#define	PCI_SERREN	0x0100	/* Bit 8:	SERR enable */
+#define	PCI_ADSTEP	0x0080	/* Bit 7:	Address Stepping */
+#define	PCI_PERREN	0x0040	/* Bit 6:	Parity Report Response enable */
+#define	PCI_VGA_SNOOP	0x0020	/* Bit 5:	VGA palette snoop */
+#define	PCI_MWIEN	0x0010	/* Bit 4:	Memory write an inv cycl ena */
+#define	PCI_SCYCEN	0x0008	/* Bit 3:	Special Cycle enable */
+#define	PCI_BMEN	0x0004	/* Bit 2:	Bus Master enable */
+#define	PCI_MEMEN	0x0002	/* Bit 1:	Memory Space Access enable */
+#define	PCI_IOEN	0x0001	/* Bit 0:	IO Space Access enable */
+
+/*	PCI_STATUS	16 bit	Status */
+#define	PCI_PERR	0x8000	/* Bit 15:	Parity Error */
+#define	PCI_SERR	0x4000	/* Bit 14:	Signaled SERR */
+#define	PCI_RMABORT	0x2000	/* Bit 13:	Received Master Abort */
+#define	PCI_RTABORT	0x1000	/* Bit 12:	Received Target Abort */
+#define	PCI_STABORT	0x0800	/* Bit 11:	Sent Target Abort */
+#define	PCI_DEVSEL	0x0600	/* Bit 10..9:	DEVSEL Timing */
+#define	PCI_DEV_FAST	(0<<9)	/*		fast */
+#define	PCI_DEV_MEDIUM	(1<<9)	/*		medium */
+#define	PCI_DEV_SLOW	(2<<9)	/*		slow */
+#define	PCI_DATAPERR	0x0100	/* Bit 8:	DATA Parity error detected */
+#define	PCI_FB2BCAP	0x0080	/* Bit 7:	Fast Back-to-Back Capability */
+#define	PCI_UDF		0x0040	/* Bit 6:	User Defined Features */
+#define PCI_66MHZCAP	0x0020	/* Bit 5:	66 MHz PCI bus clock capable */
+#define PCI_NEWCAP	0x0010	/* Bit 4:	New cap. list implemented */
+
+#define PCI_ERRBITS	(PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR)
+
+/*	PCI_REV_ID	8 bit	Revision ID */
+/*	PCI_CLASS_CODE	24 bit	Class Code */
+/*	Byte 2:		Base Class		(02) */
+/*	Byte 1:		SubClass		(02) */
+/*	Byte 0:		Programming Interface	(00) */
+
+/*	PCI_CACHE_LSZ	8 bit	Cache Line Size */
+/*	Possible values: 0,2,4,8,16	*/
+
+/*	PCI_LAT_TIM	8 bit	Latency Timer */
+
+/*	PCI_HEADER_T	8 bit	Header Type */
+#define	PCI_HD_MF_DEV	0x80	/* Bit 7:	0= single, 1= multi-func dev */
+#define	PCI_HD_TYPE	0x7f	/* Bit 6..0:	Header Layout 0= normal */
+
+/*	PCI_BIST	8 bit	Built-in selftest */
+#define	PCI_BIST_CAP	0x80	/* Bit 7:	BIST Capable */
+#define	PCI_BIST_ST	0x40	/* Bit 6:	Start BIST */
+#define	PCI_BIST_RET	0x0f	/* Bit 3..0:	Completion Code */
+
+/*	PCI_BASE_1ST	32 bit	1st Base address */
+#define	PCI_MEMSIZE	0x800L       /* use 2 kB Memory Base */
+#define	PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11:	Memory Base Address */
+#define	PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4:	Memory Size Req. */
+#define	PCI_PREFEN	0x00000008L  /* Bit 3:		Prefetchable */
+#define	PCI_MEM_TYP	0x00000006L  /* Bit 2..1:	Memory Type */
+#define	PCI_MEM32BIT	(0<<1)	     /* Base addr anywhere in 32 Bit range */
+#define	PCI_MEM1M	(1<<1)	     /* Base addr below 1 MegaByte */
+#define	PCI_MEM64BIT	(2<<1)	     /* Base addr anywhere in 64 Bit range */
+#define	PCI_MEMSPACE	0x00000001L  /* Bit 0:	Memory Space Indic. */
+
+/*	PCI_BASE_2ND	32 bit	2nd Base address */
+#define	PCI_IOBASE	0xffffff00L  /* Bit 31..8:  I/O Base address */
+#define	PCI_IOSIZE	0x000000fcL  /* Bit 7..2:   I/O Size Requirements */
+#define	PCI_IOSPACE	0x00000001L  /* Bit 0:	    I/O Space Indicator */
+
+/*	PCI_SUB_VID	16 bit	Subsystem Vendor ID */
+/*	PCI_SUB_ID	16 bit	Subsystem ID */
+
+/*	PCI_BASE_ROM	32 bit	Expansion ROM Base Address */
+#define	PCI_ROMBASE	0xfffe0000L  /* Bit 31..17: ROM BASE addres (1st) */
+#define	PCI_ROMBASZ	0x0001c000L  /* Bit 16..14: Treat as BASE or SIZE */
+#define	PCI_ROMSIZE	0x00003800L  /* Bit 13..11: ROM Size Requirements */
+#define	PCI_ROMEN	0x00000001L  /* Bit 0:	    Address Decode enable */
+
+/*	PCI_CAP_PTR	8 bit	New Capabilities Pointers */
+/*	PCI_IRQ_LINE	8 bit	Interrupt Line */
+/*	PCI_IRQ_PIN	8 bit	Interrupt Pin */
+/*	PCI_MIN_GNT	8 bit	Min_Gnt */
+/*	PCI_MAX_LAT	8 bit	Max_Lat */
+/* Device Dependent Region */
+/*	PCI_OUR_REG	(DV)	32 bit	Our Register */
+/*	PCI_OUR_REG_1	(ML)	32 bit	Our Register 1 */
+				  /*	 Bit 31..29:	reserved */
+#define	PCI_PATCH_DIR	(3L<<27)  /*(DV) Bit 28..27:	Ext Patchs direction */
+#define PCI_PATCH_DIR_0	(1L<<27)  /*(DV) Type of the pins EXT_PATCHS<1..0>   */
+#define PCI_PATCH_DIR_1 (1L<<28)  /*	   0 = input			     */
+				  /*	   1 = output			     */
+#define	PCI_EXT_PATCHS	(3L<<25)  /*(DV) Bit 26..25:	Extended Patches     */
+#define PCI_EXT_PATCH_0 (1L<<25)  /*(DV)				     */
+#define PCI_EXT_PATCH_1 (1L<<26)  /*	 CLK for MicroWire (ML)		     */
+#define PCI_VIO		(1L<<25)  /*(ML)				     */
+#define	PCI_EN_BOOT	(1L<<24)  /*	 Bit 24:	Enable BOOT via ROM  */
+				  /*	   1 = Don't boot with ROM	     */
+				  /*	   0 = Boot with ROM		     */
+#define	PCI_EN_IO	(1L<<23)  /*	 Bit 23:	Mapping to IO space  */
+#define	PCI_EN_FPROM	(1L<<22)  /*	 Bit 22:	FLASH mapped to mem? */
+				  /*	   1 = Map Flash to Memory	     */
+			  	  /*	   0 = Disable all addr. decoding    */
+#define	PCI_PAGESIZE	(3L<<20)  /*	 Bit 21..20:	FLASH Page Size	     */
+#define	PCI_PAGE_16	(0L<<20)  /*		16 k pages		     */
+#define	PCI_PAGE_32K	(1L<<20)  /*		32 k pages		     */
+#define	PCI_PAGE_64K	(2L<<20)  /*		64 k pages		     */
+#define	PCI_PAGE_128K	(3L<<20)  /*		128 k pages		     */
+				  /*	 Bit 19: reserved (ML) and (DV)	     */
+#define	PCI_PAGEREG	(7L<<16)  /*	 Bit 18..16:	Page Register	     */
+				  /*	 Bit 15:	reserved	     */
+#define	PCI_FORCE_BE	(1L<<14)  /*	 Bit 14:	Assert all BEs on MR */
+#define	PCI_DIS_MRL	(1L<<13)  /*	 Bit 13:	Disable Mem R Line   */
+#define	PCI_DIS_MRM	(1L<<12)  /*	 Bit 12:	Disable Mem R multip */
+#define	PCI_DIS_MWI	(1L<<11)  /*	 Bit 11:	Disable Mem W & inv  */
+#define	PCI_DISC_CLS	(1L<<10)  /*	 Bit 10:	Disc: cacheLsz bound */
+#define	PCI_BURST_DIS	(1L<<9)	  /*	 Bit  9:	Burst Disable	     */
+#define	PCI_BYTE_SWAP	(1L<<8)	  /*(DV) Bit  8:	Byte Swap in DATA    */
+#define	PCI_SKEW_DAS	(0xfL<<4) /*	 Bit 7..4:	Skew Ctrl, DAS Ext   */
+#define	PCI_SKEW_BASE	(0xfL<<0) /*	 Bit 3..0:	Skew Ctrl, Base	     */
+
+/*	PCI_OUR_REG_2	(ML)	32 bit	Our Register 2 (Monalisa only) */
+#define PCI_VPD_WR_TH	(0xffL<<24)	/* Bit 24..31	VPD Write Threshold  */
+#define	PCI_DEV_SEL	(0x7fL<<17)	/* Bit 17..23	EEPROM Device Select */
+#define	PCI_VPD_ROM_SZ	(7L<<14)	/* Bit 14..16	VPD ROM Size	     */
+					/* Bit 12..13	reserved	     */
+#define	PCI_PATCH_DIR2	(0xfL<<8)	/* Bit  8..11	Ext Patchs dir 2..5  */
+#define	PCI_PATCH_DIR_2	(1L<<8)		/* Bit  8	CS for MicroWire     */
+#define	PCI_PATCH_DIR_3	(1L<<9)
+#define	PCI_PATCH_DIR_4	(1L<<10)
+#define	PCI_PATCH_DIR_5	(1L<<11)
+#define PCI_EXT_PATCHS2 (0xfL<<4)	/* Bit  4..7	Extended Patches     */
+#define	PCI_EXT_PATCH_2	(1L<<4)		/* Bit  4	CS for MicroWire     */
+#define	PCI_EXT_PATCH_3	(1L<<5)
+#define	PCI_EXT_PATCH_4	(1L<<6)
+#define	PCI_EXT_PATCH_5	(1L<<7)
+#define	PCI_EN_DUMMY_RD	(1L<<3)		/* Bit  3	Enable Dummy Read    */
+#define PCI_REV_DESC	(1L<<2)		/* Bit  2	Reverse Desc. Bytes  */
+#define PCI_USEADDR64	(1L<<1)		/* Bit  1	Use 64 Bit Addresse  */
+#define PCI_USEDATA64	(1L<<0)		/* Bit  0	Use 64 Bit Data bus ext*/
+
+/* Power Management Region */
+/*	PCI_PM_CAP_ID		 8 bit (ML)	Power Management Cap. ID */
+/*	PCI_PM_NITEM		 8 bit (ML)	Next Item Ptr */
+/*	PCI_PM_CAP_REG		16 bit (ML)	Power Management Capabilities*/
+#define	PCI_PME_SUP	(0x1f<<11)	/* Bit 11..15	PM Manag. Event Support*/
+#define PCI_PM_D2_SUB	(1<<10)		/* Bit 10	D2 Support Bit	     */
+#define PCI_PM_D1_SUB	(1<<9)		/* Bit 9	D1 Support Bit       */
+					/* Bit 6..8 reserved		     */
+#define PCI_PM_DSI	(1<<5)		/* Bit 5	Device Specific Init.*/
+#define PCI_PM_APS	(1<<4)		/* Bit 4	Auxialiary Power Src */
+#define PCI_PME_CLOCK	(1<<3)		/* Bit 3	PM Event Clock       */
+#define PCI_PM_VER	(7<<0)		/* Bit 0..2	PM PCI Spec. version */
+
+/*	PCI_PM_CTL_STS		16 bit (ML)	Power Manag. Control/Status  */
+#define	PCI_PME_STATUS	(1<<15)		/* Bit 15 	PFA doesn't sup. PME#*/
+#define PCI_PM_DAT_SCL	(3<<13)		/* Bit 13..14	dat reg Scaling factor */
+#define PCI_PM_DAT_SEL	(0xf<<9)	/* Bit  9..12	PM data selector field */
+					/* Bit  7.. 2	reserved	     */
+#define PCI_PM_STATE	(3<<0)		/* Bit  0.. 1	Power Management State */
+#define PCI_PM_STATE_D0	(0<<0)		/* D0:	Operational (default) */
+#define	PCI_PM_STATE_D1	(1<<0)		/* D1:	not supported */
+#define PCI_PM_STATE_D2	(2<<0)		/* D2:	not supported */
+#define PCI_PM_STATE_D3 (3<<0)		/* D3:	HOT, Power Down and Reset */
+
+/*	PCI_PM_DAT_REG		 8 bit (ML)	Power Manag. Data Register */
+/* VPD Region */
+/*	PCI_VPD_CAP_ID		 8 bit (ML)	VPD Cap. ID */
+/*	PCI_VPD_NITEM		 8 bit (ML)	Next Item Ptr */
+/*	PCI_VPD_ADR_REG		16 bit (ML)	VPD Address Register */
+#define	PCI_VPD_FLAG	(1<<15)		/* Bit 15	starts VPD rd/wd cycle*/
+#define PCI_VPD_ADDR	(0x3fff<<0)	/* Bit  0..14	VPD address */
+
+/*	PCI_VPD_DAT_REG		32 bit (ML)	VPD Data Register */
+
+/*
+ *	Control Register File:
+ *	Bank 0
+ */
+#define	B0_RAP		0x0000	/*  8 bit register address port */
+	/* 0x0001 - 0x0003:	reserved */
+#define	B0_CTRL		0x0004	/*  8 bit control register */
+#define	B0_DAS		0x0005	/*  8 Bit control register (DAS) */
+#define	B0_LED		0x0006	/*  8 Bit LED register */
+#define	B0_TST_CTRL	0x0007	/*  8 bit test control register */
+#define	B0_ISRC		0x0008	/* 32 bit Interrupt source register */
+#define	B0_IMSK		0x000c	/* 32 bit Interrupt mask register */
+
+/* 0x0010 - 0x006b:	formac+ (supernet_3) fequently used registers */
+#define B0_CMDREG1	0x0010	/* write command reg 1 instruction */
+#define B0_CMDREG2	0x0014	/* write command reg 2 instruction */
+#define B0_ST1U		0x0010	/* read upper 16-bit of status reg 1 */
+#define B0_ST1L		0x0014	/* read lower 16-bit of status reg 1 */
+#define B0_ST2U		0x0018	/* read upper 16-bit of status reg 2 */
+#define B0_ST2L		0x001c	/* read lower 16-bit of status reg 2 */
+
+#define B0_MARR		0x0020	/* r/w the memory read addr register */
+#define B0_MARW		0x0024	/* r/w the memory write addr register*/
+#define B0_MDRU		0x0028	/* r/w upper 16-bit of mem. data reg */
+#define B0_MDRL		0x002c	/* r/w lower 16-bit of mem. data reg */
+
+#define	B0_MDREG3	0x0030	/* r/w Mode Register 3 */
+#define	B0_ST3U		0x0034	/* read upper 16-bit of status reg 3 */
+#define	B0_ST3L		0x0038	/* read lower 16-bit of status reg 3 */
+#define	B0_IMSK3U	0x003c	/* r/w upper 16-bit of IMSK reg 3 */
+#define	B0_IMSK3L	0x0040	/* r/w lower 16-bit of IMSK reg 3 */
+#define	B0_IVR		0x0044	/* read Interrupt Vector register */
+#define	B0_IMR		0x0048	/* r/w Interrupt mask register */
+/* 0x4c	Hidden */
+
+#define B0_CNTRL_A	0x0050	/* control register A (r/w) */
+#define B0_CNTRL_B	0x0054	/* control register B (r/w) */
+#define B0_INTR_MASK	0x0058	/* interrupt mask (r/w) */
+#define B0_XMIT_VECTOR	0x005c	/* transmit vector register (r/w) */
+
+#define B0_STATUS_A	0x0060	/* status register A (read only) */
+#define B0_STATUS_B	0x0064	/* status register B (read only) */
+#define B0_CNTRL_C	0x0068	/* control register C (r/w) */
+#define	B0_MDREG1	0x006c	/* r/w Mode Register 1 */
+
+#define	B0_R1_CSR	0x0070	/* 32 bit BMU control/status reg (rec q 1) */
+#define	B0_R2_CSR	0x0074	/* 32 bit BMU control/status reg (rec q 2)(DV)*/
+#define	B0_XA_CSR	0x0078	/* 32 bit BMU control/status reg (a xmit q) */
+#define	B0_XS_CSR	0x007c	/* 32 bit BMU control/status reg (s xmit q) */
+
+/*
+ *	Bank 1
+ *	- completely empty (this is the RAP Block window)
+ *	Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ *	Bank 2
+ */
+#define	B2_MAC_0	0x0100	/*  8 bit MAC address Byte 0 */
+#define	B2_MAC_1	0x0101	/*  8 bit MAC address Byte 1 */
+#define	B2_MAC_2	0x0102	/*  8 bit MAC address Byte 2 */
+#define	B2_MAC_3	0x0103	/*  8 bit MAC address Byte 3 */
+#define	B2_MAC_4	0x0104	/*  8 bit MAC address Byte 4 */
+#define	B2_MAC_5	0x0105	/*  8 bit MAC address Byte 5 */
+#define	B2_MAC_6	0x0106	/*  8 bit MAC address Byte 6 (== 0) (DV) */
+#define	B2_MAC_7	0x0107	/*  8 bit MAC address Byte 7 (== 0) (DV) */
+
+#define B2_CONN_TYP	0x0108	/*  8 bit Connector type */
+#define B2_PMD_TYP	0x0109	/*  8 bit PMD type */
+				/* 0x010a - 0x010b:	reserved */
+	/* Eprom registers are currently of no use */
+#define B2_E_0		0x010c	/*  8 bit EPROM Byte 0 */
+#define B2_E_1		0x010d	/*  8 bit EPROM Byte 1 */
+#define B2_E_2		0x010e	/*  8 bit EPROM Byte 2 */
+#define B2_E_3		0x010f	/*  8 bit EPROM Byte 3 */
+#define B2_FAR		0x0110	/* 32 bit Flash-Prom Address Register/Counter */
+#define B2_FDP		0x0114	/*  8 bit Flash-Prom Data Port */
+				/* 0x0115 - 0x0117:	reserved */
+#define B2_LD_CRTL	0x0118	/*  8 bit loader control */
+#define B2_LD_TEST	0x0119	/*  8 bit loader test */
+				/* 0x011a - 0x011f:	reserved */
+#define B2_TI_INI	0x0120	/* 32 bit Timer init value */
+#define B2_TI_VAL	0x0124	/* 32 bit Timer value */
+#define B2_TI_CRTL	0x0128	/*  8 bit Timer control */
+#define B2_TI_TEST	0x0129	/*  8 Bit Timer Test */
+				/* 0x012a - 0x012f:	reserved */
+#define B2_WDOG_INI	0x0130	/* 32 bit Watchdog init value */
+#define B2_WDOG_VAL	0x0134	/* 32 bit Watchdog value */
+#define B2_WDOG_CRTL	0x0138	/*  8 bit Watchdog control */
+#define B2_WDOG_TEST	0x0139	/*  8 Bit Watchdog Test */
+				/* 0x013a - 0x013f:	reserved */
+#define B2_RTM_INI	0x0140	/* 32 bit RTM init value */
+#define B2_RTM_VAL	0x0144	/* 32 bit RTM value */
+#define B2_RTM_CRTL	0x0148	/*  8 bit RTM control */
+#define B2_RTM_TEST	0x0149	/*  8 Bit RTM Test */
+
+#define B2_TOK_COUNT	0x014c	/* (ML)	32 bit	Token Counter */
+#define B2_DESC_ADDR_H	0x0150	/* (ML) 32 bit	Desciptor Base Addr Reg High */
+#define B2_CTRL_2	0x0154	/* (ML)	 8 bit	Control Register 2 */
+#define B2_IFACE_REG	0x0155	/* (ML)	 8 bit	Interface Register */
+				/* 0x0156:		reserved */
+#define B2_TST_CTRL_2	0x0157	/* (ML)  8 bit	Test Control Register 2 */
+#define B2_I2C_CTRL	0x0158	/* (ML)	32 bit	I2C Control Register */
+#define B2_I2C_DATA	0x015c	/* (ML) 32 bit	I2C Data Register */
+
+#define B2_IRQ_MOD_INI	0x0160	/* (ML) 32 bit	IRQ Moderation Timer Init Reg. */
+#define B2_IRQ_MOD_VAL	0x0164	/* (ML)	32 bit	IRQ Moderation Timer Value */
+#define B2_IRQ_MOD_CTRL	0x0168	/* (ML)  8 bit	IRQ Moderation Timer Control */
+#define B2_IRQ_MOD_TEST	0x0169	/* (ML)	 8 bit	IRQ Moderation Timer Test */
+				/* 0x016a - 0x017f:	reserved */
+
+/*
+ *	Bank 3
+ */
+/*
+ * This is a copy of the Configuration register file (lower half)
+ */
+#define B3_CFG_SPC	0x180
+
+/*
+ *	Bank 4
+ */
+#define B4_R1_D		0x0200	/* 	4*32 bit current receive Descriptor  */
+#define B4_R1_DA	0x0210	/* 	32 bit current rec desc address	     */
+#define B4_R1_AC	0x0214	/* 	32 bit current receive Address Count */
+#define B4_R1_BC	0x0218	/*	32 bit current receive Byte Counter  */
+#define B4_R1_CSR	0x021c	/* 	32 bit BMU Control/Status Register   */
+#define B4_R1_F		0x0220	/* 	32 bit flag register		     */
+#define B4_R1_T1	0x0224	/* 	32 bit Test Register 1		     */
+#define B4_R1_T1_TR	0x0224	/* 	8 bit Test Register 1 TR	     */
+#define B4_R1_T1_WR	0x0225	/* 	8 bit Test Register 1 WR	     */
+#define B4_R1_T1_RD	0x0226	/* 	8 bit Test Register 1 RD	     */
+#define B4_R1_T1_SV	0x0227	/* 	8 bit Test Register 1 SV	     */
+#define B4_R1_T2	0x0228	/* 	32 bit Test Register 2		     */
+#define B4_R1_T3	0x022c	/* 	32 bit Test Register 3		     */
+#define B4_R1_DA_H	0x0230	/* (ML)	32 bit Curr Rx Desc Address High     */
+#define B4_R1_AC_H	0x0234	/* (ML)	32 bit Curr Addr Counter High dword  */
+				/* 0x0238 - 0x023f:	reserved	  */
+				/* Receive queue 2 is removed on Monalisa */
+#define B4_R2_D		0x0240	/* 4*32 bit current receive Descriptor	(q2) */
+#define B4_R2_DA	0x0250	/* 32 bit current rec desc address	(q2) */
+#define B4_R2_AC	0x0254	/* 32 bit current receive Address Count	(q2) */
+#define B4_R2_BC	0x0258	/* 32 bit current receive Byte Counter	(q2) */
+#define B4_R2_CSR	0x025c	/* 32 bit BMU Control/Status Register	(q2) */
+#define B4_R2_F		0x0260	/* 32 bit flag register			(q2) */
+#define B4_R2_T1	0x0264	/* 32 bit Test Register 1		(q2) */
+#define B4_R2_T1_TR	0x0264	/* 8 bit Test Register 1 TR		(q2) */
+#define B4_R2_T1_WR	0x0265	/* 8 bit Test Register 1 WR		(q2) */
+#define B4_R2_T1_RD	0x0266	/* 8 bit Test Register 1 RD		(q2) */
+#define B4_R2_T1_SV	0x0267	/* 8 bit Test Register 1 SV		(q2) */
+#define B4_R2_T2	0x0268	/* 32 bit Test Register 2		(q2) */
+#define B4_R2_T3	0x026c	/* 32 bit Test Register 3		(q2) */
+				/* 0x0270 - 0x027c:	reserved */
+
+/*
+ *	Bank 5
+ */
+#define B5_XA_D		0x0280	/* 4*32 bit current transmit Descriptor	(xa) */
+#define B5_XA_DA	0x0290	/* 32 bit current tx desc address	(xa) */
+#define B5_XA_AC	0x0294	/* 32 bit current tx Address Count	(xa) */
+#define B5_XA_BC	0x0298	/* 32 bit current tx Byte Counter	(xa) */
+#define B5_XA_CSR	0x029c	/* 32 bit BMU Control/Status Register	(xa) */
+#define B5_XA_F		0x02a0	/* 32 bit flag register			(xa) */
+#define B5_XA_T1	0x02a4	/* 32 bit Test Register 1		(xa) */
+#define B5_XA_T1_TR	0x02a4	/* 8 bit Test Register 1 TR		(xa) */
+#define B5_XA_T1_WR	0x02a5	/* 8 bit Test Register 1 WR		(xa) */
+#define B5_XA_T1_RD	0x02a6	/* 8 bit Test Register 1 RD		(xa) */
+#define B5_XA_T1_SV	0x02a7	/* 8 bit Test Register 1 SV		(xa) */
+#define B5_XA_T2	0x02a8	/* 32 bit Test Register 2		(xa) */
+#define B5_XA_T3	0x02ac	/* 32 bit Test Register 3		(xa) */
+#define B5_XA_DA_H	0x02b0	/* (ML)	32 bit Curr Tx Desc Address High     */
+#define B5_XA_AC_H	0x02b4	/* (ML)	32 bit Curr Addr Counter High dword  */
+				/* 0x02b8 - 0x02bc:	reserved */
+#define B5_XS_D		0x02c0	/* 4*32 bit current transmit Descriptor	(xs) */
+#define B5_XS_DA	0x02d0	/* 32 bit current tx desc address	(xs) */
+#define B5_XS_AC	0x02d4	/* 32 bit current transmit Address Count(xs) */
+#define B5_XS_BC	0x02d8	/* 32 bit current transmit Byte Counter	(xs) */
+#define B5_XS_CSR	0x02dc	/* 32 bit BMU Control/Status Register	(xs) */
+#define B5_XS_F		0x02e0	/* 32 bit flag register			(xs) */
+#define B5_XS_T1	0x02e4	/* 32 bit Test Register 1		(xs) */
+#define B5_XS_T1_TR	0x02e4	/* 8 bit Test Register 1 TR		(xs) */
+#define B5_XS_T1_WR	0x02e5	/* 8 bit Test Register 1 WR		(xs) */
+#define B5_XS_T1_RD	0x02e6	/* 8 bit Test Register 1 RD		(xs) */
+#define B5_XS_T1_SV	0x02e7	/* 8 bit Test Register 1 SV		(xs) */
+#define B5_XS_T2	0x02e8	/* 32 bit Test Register 2		(xs) */
+#define B5_XS_T3	0x02ec	/* 32 bit Test Register 3		(xs) */
+#define B5_XS_DA_H	0x02f0	/* (ML)	32 bit Curr Tx Desc Address High     */
+#define B5_XS_AC_H	0x02f4	/* (ML)	32 bit Curr Addr Counter High dword  */
+				/* 0x02f8 - 0x02fc:	reserved */
+
+/*
+ *	Bank 6
+ */
+/* External PLC-S registers (SN2 compatibility for DV) */
+/* External registers (ML) */
+#define B6_EXT_REG	0x300
+
+/*
+ *	Bank 7
+ */
+/* DAS PLC-S Registers */
+
+/*
+ *	Bank 8 - 15
+ */
+/* IFCP registers */
+
+/*---------------------------------------------------------------------------*/
+/* Definitions of the Bits in the registers */
+
+/*	B0_RAP		16 bit register address port */
+#define	RAP_RAP		0x0f	/* Bit 3..0:	0 = block0, .., f = block15 */
+
+/*	B0_CTRL		8 bit control register */
+#define CTRL_FDDI_CLR	(1<<7)	/* Bit 7: (ML)	Clear FDDI Reset */
+#define CTRL_FDDI_SET	(1<<6)	/* Bit 6: (ML)	Set FDDI Reset */
+#define	CTRL_HPI_CLR	(1<<5)	/* Bit 5:	Clear HPI SM reset */
+#define	CTRL_HPI_SET	(1<<4)	/* Bit 4:	Set HPI SM reset */
+#define	CTRL_MRST_CLR	(1<<3)	/* Bit 3:	Clear Master reset */
+#define	CTRL_MRST_SET	(1<<2)	/* Bit 2:	Set Master reset */
+#define	CTRL_RST_CLR	(1<<1)	/* Bit 1:	Clear Software reset */
+#define	CTRL_RST_SET	(1<<0)	/* Bit 0:	Set Software reset */
+
+/*	B0_DAS		8 Bit control register (DAS) */
+#define BUS_CLOCK	(1<<7)	/* Bit 7: (ML)	Bus Clock 0/1 = 33/66MHz */
+#define BUS_SLOT_SZ	(1<<6)	/* Bit 6: (ML)	Slot Size 0/1 = 32/64 bit slot*/
+				/* Bit 5..4:	reserved */
+#define	DAS_AVAIL	(1<<3)	/* Bit 3:	1 = DAS, 0 = SAS */
+#define DAS_BYP_ST	(1<<2)	/* Bit 2:	1 = avail,SAS, 0 = not avail */
+#define DAS_BYP_INS	(1<<1)	/* Bit 1:	1 = insert Bypass */
+#define DAS_BYP_RMV	(1<<0)	/* Bit 0:	1 = remove Bypass */
+
+/*	B0_LED		8 Bit LED register */
+				/* Bit 7..6:	reserved */
+#define LED_2_ON	(1<<5)	/* Bit 5:	1 = switch LED_2 on (left,gn)*/
+#define LED_2_OFF	(1<<4)	/* Bit 4:	1 = switch LED_2 off */
+#define LED_1_ON	(1<<3)	/* Bit 3:	1 = switch LED_1 on (mid,yel)*/
+#define LED_1_OFF	(1<<2)	/* Bit 2:	1 = switch LED_1 off */
+#define LED_0_ON	(1<<1)	/* Bit 1:	1 = switch LED_0 on (rght,gn)*/
+#define LED_0_OFF	(1<<0)	/* Bit 0:	1 = switch LED_0 off */
+/* This hardware defines are very ugly therefore we define some others */
+
+#define LED_GA_ON	LED_2_ON	/* S port = A port */
+#define LED_GA_OFF	LED_2_OFF	/* S port = A port */
+#define LED_MY_ON	LED_1_ON
+#define LED_MY_OFF	LED_1_OFF
+#define LED_GB_ON	LED_0_ON
+#define LED_GB_OFF	LED_0_OFF
+
+/*	B0_TST_CTRL	8 bit test control register */
+#define	TST_FRC_DPERR_MR	(1<<7)	/* Bit 7:  force DATAPERR on MST RE. */
+#define	TST_FRC_DPERR_MW	(1<<6)	/* Bit 6:  force DATAPERR on MST WR. */
+#define	TST_FRC_DPERR_TR	(1<<5)	/* Bit 5:  force DATAPERR on TRG RE. */
+#define	TST_FRC_DPERR_TW	(1<<4)	/* Bit 4:  force DATAPERR on TRG WR. */
+#define	TST_FRC_APERR_M		(1<<3)	/* Bit 3:  force ADDRPERR on MST     */
+#define	TST_FRC_APERR_T		(1<<2)	/* Bit 2:  force ADDRPERR on TRG     */
+#define	TST_CFG_WRITE_ON	(1<<1)	/* Bit 1:  ena configuration reg. WR */
+#define	TST_CFG_WRITE_OFF	(1<<0)	/* Bit 0:  dis configuration reg. WR */
+
+/*	B0_ISRC		32 bit Interrupt source register */
+					/* Bit 31..28:	reserved	     */
+#define IS_I2C_READY	(1L<<27)	/* Bit 27: (ML)	IRQ on end of I2C tx */
+#define IS_IRQ_SW	(1L<<26)	/* Bit 26: (ML)	SW forced IRQ	     */
+#define IS_EXT_REG	(1L<<25)	/* Bit 25: (ML) IRQ from external reg*/
+#define	IS_IRQ_STAT	(1L<<24)	/* Bit 24:	IRQ status execption */
+					/*   PERR, RMABORT, RTABORT DATAPERR */
+#define	IS_IRQ_MST_ERR	(1L<<23)	/* Bit 23:	IRQ master error     */
+					/*   RMABORT, RTABORT, DATAPERR	     */
+#define	IS_TIMINT	(1L<<22)	/* Bit 22:	IRQ_TIMER	*/
+#define	IS_TOKEN	(1L<<21)	/* Bit 21:	IRQ_RTM		*/
+/*
+ * Note: The DAS is our First Port (!=PA)
+ */
+#define	IS_PLINT1	(1L<<20)	/* Bit 20:	IRQ_PHY_DAS	*/
+#define	IS_PLINT2	(1L<<19)	/* Bit 19:	IRQ_IFCP_4	*/
+#define	IS_MINTR3	(1L<<18)	/* Bit 18:	IRQ_IFCP_3/IRQ_PHY */
+#define	IS_MINTR2	(1L<<17)	/* Bit 17:	IRQ_IFCP_2/IRQ_MAC_2 */
+#define	IS_MINTR1	(1L<<16)	/* Bit 16:	IRQ_IFCP_1/IRQ_MAC_1 */
+/* Receive Queue 1 */
+#define	IS_R1_P		(1L<<15)	/* Bit 15:	Parity Error (q1) */
+#define	IS_R1_B		(1L<<14)	/* Bit 14:	End of Buffer (q1) */
+#define	IS_R1_F		(1L<<13)	/* Bit 13:	End of Frame (q1) */
+#define	IS_R1_C		(1L<<12)	/* Bit 12:	Encoding Error (q1) */
+/* Receive Queue 2 */
+#define	IS_R2_P		(1L<<11)	/* Bit 11: (DV)	Parity Error (q2) */
+#define	IS_R2_B		(1L<<10)	/* Bit 10: (DV)	End of Buffer (q2) */
+#define	IS_R2_F		(1L<<9)		/* Bit	9: (DV)	End of Frame (q2) */
+#define	IS_R2_C		(1L<<8)		/* Bit	8: (DV)	Encoding Error (q2) */
+/* Asynchronous Transmit queue */
+					/* Bit  7:	reserved */
+#define	IS_XA_B		(1L<<6)		/* Bit	6:	End of Buffer (xa) */
+#define	IS_XA_F		(1L<<5)		/* Bit	5:	End of Frame (xa) */
+#define	IS_XA_C		(1L<<4)		/* Bit	4:	Encoding Error (xa) */
+/* Synchronous Transmit queue */
+					/* Bit  3:	reserved */
+#define	IS_XS_B		(1L<<2)		/* Bit	2:	End of Buffer (xs) */
+#define	IS_XS_F		(1L<<1)		/* Bit	1:	End of Frame (xs) */
+#define	IS_XS_C		(1L<<0)		/* Bit	0:	Encoding Error (xs) */
+
+/*
+ * Define all valid interrupt source Bits from GET_ISR ()
+ */
+#define	ALL_IRSR	0x01ffff77L	/* (DV) */
+#define	ALL_IRSR_ML	0x0ffff077L	/* (ML) */
+
+
+/*	B0_IMSK		32 bit Interrupt mask register */
+/*
+ * The Bit definnition of this register are the same as of the interrupt
+ * source register. These definition are directly derived from the Hardware
+ * spec.
+ */
+					/* Bit 31..28:	reserved	     */
+#define IRQ_I2C_READY	(1L<<27)	/* Bit 27: (ML)	IRQ on end of I2C tx */
+#define IRQ_SW		(1L<<26)	/* Bit 26: (ML)	SW forced IRQ	     */
+#define IRQ_EXT_REG	(1L<<25)	/* Bit 25: (ML) IRQ from external reg*/
+#define	IRQ_STAT	(1L<<24)	/* Bit 24:	IRQ status execption */
+					/*   PERR, RMABORT, RTABORT DATAPERR */
+#define	IRQ_MST_ERR	(1L<<23)	/* Bit 23:	IRQ master error     */
+					/*   RMABORT, RTABORT, DATAPERR	     */
+#define	IRQ_TIMER	(1L<<22)	/* Bit 22:	IRQ_TIMER	*/
+#define	IRQ_RTM		(1L<<21)	/* Bit 21:	IRQ_RTM		*/
+#define	IRQ_DAS		(1L<<20)	/* Bit 20:	IRQ_PHY_DAS	*/
+#define	IRQ_IFCP_4	(1L<<19)	/* Bit 19:	IRQ_IFCP_4	*/
+#define	IRQ_IFCP_3	(1L<<18)	/* Bit 18:	IRQ_IFCP_3/IRQ_PHY */
+#define	IRQ_IFCP_2	(1L<<17)	/* Bit 17:	IRQ_IFCP_2/IRQ_MAC_2 */
+#define	IRQ_IFCP_1	(1L<<16)	/* Bit 16:	IRQ_IFCP_1/IRQ_MAC_1 */
+/* Receive Queue 1 */
+#define	IRQ_R1_P	(1L<<15)	/* Bit 15:	Parity Error (q1) */
+#define	IRQ_R1_B	(1L<<14)	/* Bit 14:	End of Buffer (q1) */
+#define	IRQ_R1_F	(1L<<13)	/* Bit 13:	End of Frame (q1) */
+#define	IRQ_R1_C	(1L<<12)	/* Bit 12:	Encoding Error (q1) */
+/* Receive Queue 2 */
+#define	IRQ_R2_P	(1L<<11)	/* Bit 11: (DV)	Parity Error (q2) */
+#define	IRQ_R2_B	(1L<<10)	/* Bit 10: (DV)	End of Buffer (q2) */
+#define	IRQ_R2_F	(1L<<9)		/* Bit	9: (DV)	End of Frame (q2) */
+#define	IRQ_R2_C	(1L<<8)		/* Bit	8: (DV)	Encoding Error (q2) */
+/* Asynchronous Transmit queue */
+					/* Bit  7:	reserved */
+#define	IRQ_XA_B	(1L<<6)		/* Bit	6:	End of Buffer (xa) */
+#define	IRQ_XA_F	(1L<<5)		/* Bit	5:	End of Frame (xa) */
+#define	IRQ_XA_C	(1L<<4)		/* Bit	4:	Encoding Error (xa) */
+/* Synchronous Transmit queue */
+					/* Bit  3:	reserved */
+#define	IRQ_XS_B	(1L<<2)		/* Bit	2:	End of Buffer (xs) */
+#define	IRQ_XS_F	(1L<<1)		/* Bit	1:	End of Frame (xs) */
+#define	IRQ_XS_C	(1L<<0)		/* Bit	0:	Encoding Error (xs) */
+
+/* 0x0010 - 0x006b:	formac+ (supernet_3) fequently used registers */
+/*	B0_R1_CSR	32 bit BMU control/status reg (rec q 1 ) */
+/*	B0_R2_CSR	32 bit BMU control/status reg (rec q 2 ) */
+/*	B0_XA_CSR	32 bit BMU control/status reg (a xmit q ) */
+/*	B0_XS_CSR	32 bit BMU control/status reg (s xmit q ) */
+/* The registers are the same as B4_R1_CSR, B4_R2_CSR, B5_Xa_CSR, B5_XS_CSR */
+
+/*	B2_MAC_0	8 bit MAC address Byte 0 */
+/*	B2_MAC_1	8 bit MAC address Byte 1 */
+/*	B2_MAC_2	8 bit MAC address Byte 2 */
+/*	B2_MAC_3	8 bit MAC address Byte 3 */
+/*	B2_MAC_4	8 bit MAC address Byte 4 */
+/*	B2_MAC_5	8 bit MAC address Byte 5 */
+/*	B2_MAC_6	8 bit MAC address Byte 6 (== 0) (DV) */
+/*	B2_MAC_7	8 bit MAC address Byte 7 (== 0) (DV) */
+
+/*	B2_CONN_TYP	8 bit Connector type */
+/*	B2_PMD_TYP	8 bit PMD type */
+/*	Values of connector and PMD type comply to SysKonnect internal std */
+
+/*	The EPROM register are currently of no use */
+/*	B2_E_0		8 bit EPROM Byte 0 */
+/*	B2_E_1		8 bit EPROM Byte 1 */
+/*	B2_E_2		8 bit EPROM Byte 2 */
+/*	B2_E_3		8 bit EPROM Byte 3 */
+
+/*	B2_FAR		32 bit Flash-Prom Address Register/Counter */
+#define	FAR_ADDR	0x1ffffL	/* Bit 16..0:	FPROM Address mask */
+
+/*	B2_FDP		8 bit Flash-Prom Data Port */
+
+/*	B2_LD_CRTL	8 bit loader control */
+/*	Bits are currently reserved */
+
+/*	B2_LD_TEST	8 bit loader test */
+#define	LD_T_ON		(1<<3)	/* Bit 3:    Loader Testmode on */
+#define	LD_T_OFF	(1<<2)	/* Bit 2:    Loader Testmode off */
+#define	LD_T_STEP	(1<<1)	/* Bit 1:    Decrement FPROM addr. Counter */
+#define	LD_START	(1<<0)	/* Bit 0:    Start loading FPROM */
+
+/*	B2_TI_INI	32 bit Timer init value */
+/*	B2_TI_VAL	32 bit Timer value */
+/*	B2_TI_CRTL	8 bit Timer control */
+/*	B2_TI_TEST	8 Bit Timer Test */
+/*	B2_WDOG_INI	32 bit Watchdog init value */
+/*	B2_WDOG_VAL	32 bit Watchdog value */
+/*	B2_WDOG_CRTL	8 bit Watchdog control */
+/*	B2_WDOG_TEST	8 Bit Watchdog Test */
+/*	B2_RTM_INI	32 bit RTM init value */
+/*	B2_RTM_VAL	32 bit RTM value */
+/*	B2_RTM_CRTL	8 bit RTM control */
+/*	B2_RTM_TEST	8 Bit RTM Test */
+/*	B2_<TIM>_CRTL	8 bit <TIM> control */
+/*	B2_IRQ_MOD_INI	32 bit IRQ Moderation Timer Init Reg.	(ML) */
+/*	B2_IRQ_MOD_VAL	32 bit IRQ Moderation Timer Value	(ML) */
+/*	B2_IRQ_MOD_CTRL	8 bit IRQ Moderation Timer Control	(ML) */
+/*	B2_IRQ_MOD_TEST	8 bit IRQ Moderation Timer Test		(ML) */
+#define GET_TOK_CT	(1<<4)	/* Bit 4: Get the Token Counter (RTM) */
+#define TIM_RES_TOK	(1<<3)	/* Bit 3: RTM Status: 1 == restricted */
+#define TIM_ALARM	(1<<3)	/* Bit 3: Timer Alarm (WDOG) */
+#define TIM_START	(1<<2)	/* Bit 2: Start Timer (TI,WDOG,RTM,IRQ_MOD)*/
+#define TIM_STOP	(1<<1)	/* Bit 1: Stop Timer (TI,WDOG,RTM,IRQ_MOD) */
+#define TIM_CL_IRQ	(1<<0)	/* Bit 0: Clear Timer IRQ (TI,WDOG,RTM) */
+/*	B2_<TIM>_TEST	8 Bit <TIM> Test */
+#define	TIM_T_ON	(1<<2)	/* Bit 2: Test mode on (TI,WDOG,RTM,IRQ_MOD) */
+#define	TIM_T_OFF	(1<<1)	/* Bit 1: Test mode off (TI,WDOG,RTM,IRQ_MOD) */
+#define	TIM_T_STEP	(1<<0)	/* Bit 0: Test step (TI,WDOG,RTM,IRQ_MOD) */
+
+/*	B2_TOK_COUNT	0x014c	(ML)	32 bit	Token Counter */
+/*	B2_DESC_ADDR_H	0x0150	(ML)	32 bit	Desciptor Base Addr Reg High */
+/*	B2_CTRL_2	0x0154	(ML)	 8 bit	Control Register 2 */
+				/* Bit 7..5:	reserved		*/
+#define CTRL_CL_I2C_IRQ (1<<4)	/* Bit 4:	Clear I2C IRQ		*/
+#define CTRL_ST_SW_IRQ	(1<<3)	/* Bit 3:	Set IRQ SW Request	*/
+#define CTRL_CL_SW_IRQ	(1<<2)	/* Bit 2:	Clear IRQ SW Request	*/
+#define CTRL_STOP_DONE	(1<<1)	/* Bit 1:	Stop Master is finished */
+#define	CTRL_STOP_MAST	(1<<0)	/* Bit 0:	Command Bit to stop the master*/
+
+/*	B2_IFACE_REG	0x0155	(ML)	 8 bit	Interface Register */
+				/* Bit 7..3:	reserved		*/
+#define	IF_I2C_DATA_DIR	(1<<2)	/* Bit 2:	direction of IF_I2C_DATA*/
+#define IF_I2C_DATA	(1<<1)	/* Bit 1:	I2C Data Port		*/
+#define	IF_I2C_CLK	(1<<0)	/* Bit 0:	I2C Clock Port		*/
+
+				/* 0x0156:		reserved */
+/*	B2_TST_CTRL_2	0x0157	(ML)	 8 bit	Test Control Register 2 */
+					/* Bit 7..4:	reserved */
+					/* force the following error on */
+					/* the next master read/write	*/
+#define TST_FRC_DPERR_MR64	(1<<3)	/* Bit 3:	DataPERR RD 64	*/
+#define TST_FRC_DPERR_MW64	(1<<2)	/* Bit 2:	DataPERR WR 64	*/
+#define TST_FRC_APERR_1M64	(1<<1)	/* Bit 1:	AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64	(1<<0)	/* Bit 0:	AddrPERR on 2. phase */
+
+/*	B2_I2C_CTRL	0x0158	(ML)	32 bit	I2C Control Register	       */
+#define	I2C_FLAG	(1L<<31)	/* Bit 31:	Start read/write if WR */
+#define I2C_ADDR	(0x7fffL<<16)	/* Bit 30..16:	Addr to be read/written*/
+#define	I2C_DEV_SEL	(0x7fL<<9)	/* Bit  9..15:	I2C Device Select      */
+					/* Bit  5.. 8:	reserved	       */
+#define I2C_BURST_LEN	(1L<<4)		/* Bit  4	Burst Len, 1/4 bytes   */
+#define I2C_DEV_SIZE	(7L<<1)		/* Bit	1.. 3:	I2C Device Size	       */
+#define I2C_025K_DEV	(0L<<1)		/*		0: 256 Bytes or smaller*/
+#define I2C_05K_DEV	(1L<<1)		/* 		1: 512	Bytes	       */
+#define	I2C_1K_DEV	(2L<<1)		/*		2: 1024 Bytes	       */
+#define I2C_2K_DEV	(3L<<1)		/*		3: 2048	Bytes	       */
+#define	I2C_4K_DEV	(4L<<1)		/*		4: 4096 Bytes	       */
+#define	I2C_8K_DEV	(5L<<1)		/*		5: 8192 Bytes	       */
+#define	I2C_16K_DEV	(6L<<1)		/*		6: 16384 Bytes	       */
+#define	I2C_32K_DEV	(7L<<1)		/*		7: 32768 Bytes	       */
+#define I2C_STOP_BIT	(1<<0)		/* Bit  0:	Interrupt I2C transfer */
+
+/*
+ * I2C Addresses
+ *
+ * The temperature sensor and the voltage sensor are on the same I2C bus.
+ * Note: The voltage sensor (Micorwire) will be selected by PCI_EXT_PATCH_1
+ *	 in PCI_OUR_REG 1.
+ */
+#define	I2C_ADDR_TEMP	0x90	/* I2C Address Temperature Sensor */
+
+/*	B2_I2C_DATA	0x015c	(ML)	32 bit	I2C Data Register */
+
+/*	B4_R1_D		4*32 bit current receive Descriptor	(q1) */
+/*	B4_R1_DA	32 bit current rec desc address		(q1) */
+/*	B4_R1_AC	32 bit current receive Address Count	(q1) */
+/*	B4_R1_BC	32 bit current receive Byte Counter	(q1) */
+/*	B4_R1_CSR	32 bit BMU Control/Status Register	(q1) */
+/*	B4_R1_F		32 bit flag register			(q1) */
+/*	B4_R1_T1	32 bit Test Register 1		 	(q1) */
+/*	B4_R1_T2	32 bit Test Register 2		 	(q1) */
+/*	B4_R1_T3	32 bit Test Register 3		 	(q1) */
+/*	B4_R2_D		4*32 bit current receive Descriptor	(q2) */
+/*	B4_R2_DA	32 bit current rec desc address		(q2) */
+/*	B4_R2_AC	32 bit current receive Address Count	(q2) */
+/*	B4_R2_BC	32 bit current receive Byte Counter	(q2) */
+/*	B4_R2_CSR	32 bit BMU Control/Status Register	(q2) */
+/*	B4_R2_F		32 bit flag register			(q2) */
+/*	B4_R2_T1	32 bit Test Register 1			(q2) */
+/*	B4_R2_T2	32 bit Test Register 2			(q2) */
+/*	B4_R2_T3	32 bit Test Register 3			(q2) */
+/*	B5_XA_D		4*32 bit current receive Descriptor	(xa) */
+/*	B5_XA_DA	32 bit current rec desc address		(xa) */
+/*	B5_XA_AC	32 bit current receive Address Count	(xa) */
+/*	B5_XA_BC	32 bit current receive Byte Counter	(xa) */
+/*	B5_XA_CSR	32 bit BMU Control/Status Register	(xa) */
+/*	B5_XA_F		32 bit flag register			(xa) */
+/*	B5_XA_T1	32 bit Test Register 1			(xa) */
+/*	B5_XA_T2	32 bit Test Register 2			(xa) */
+/*	B5_XA_T3	32 bit Test Register 3			(xa) */
+/*	B5_XS_D		4*32 bit current receive Descriptor	(xs) */
+/*	B5_XS_DA	32 bit current rec desc address		(xs) */
+/*	B5_XS_AC	32 bit current receive Address Count	(xs) */
+/*	B5_XS_BC	32 bit current receive Byte Counter	(xs) */
+/*	B5_XS_CSR	32 bit BMU Control/Status Register	(xs) */
+/*	B5_XS_F		32 bit flag register			(xs) */
+/*	B5_XS_T1	32 bit Test Register 1			(xs) */
+/*	B5_XS_T2	32 bit Test Register 2			(xs) */
+/*	B5_XS_T3	32 bit Test Register 3			(xs) */
+/*	B5_<xx>_CSR	32 bit BMU Control/Status Register	(xx) */
+#define	CSR_DESC_CLEAR	(1L<<21)    /* Bit 21:	Clear Reset for Descr */
+#define	CSR_DESC_SET	(1L<<20)    /* Bit 20:	Set Reset for Descr */
+#define	CSR_FIFO_CLEAR	(1L<<19)    /* Bit 19:	Clear Reset for FIFO */
+#define	CSR_FIFO_SET	(1L<<18)    /* Bit 18:	Set Reset for FIFO */
+#define	CSR_HPI_RUN	(1L<<17)    /* Bit 17:	Release HPI SM */
+#define	CSR_HPI_RST	(1L<<16)    /* Bit 16:	Reset HPI SM to Idle */
+#define	CSR_SV_RUN	(1L<<15)    /* Bit 15:	Release Supervisor SM */
+#define	CSR_SV_RST	(1L<<14)    /* Bit 14:	Reset Supervisor SM */
+#define	CSR_DREAD_RUN	(1L<<13)    /* Bit 13:	Release Descr Read SM */
+#define	CSR_DREAD_RST	(1L<<12)    /* Bit 12:	Reset Descr Read SM */
+#define	CSR_DWRITE_RUN	(1L<<11)    /* Bit 11:	Rel. Descr Write SM */
+#define	CSR_DWRITE_RST	(1L<<10)    /* Bit 10:	Reset Descr Write SM */
+#define	CSR_TRANS_RUN	(1L<<9)     /* Bit 9:	Release Transfer SM */
+#define	CSR_TRANS_RST	(1L<<8)     /* Bit 8:	Reset Transfer SM */
+				    /* Bit 7..5: reserved */
+#define	CSR_START	(1L<<4)     /* Bit 4:	Start Rec/Xmit Queue */
+#define	CSR_IRQ_CL_P	(1L<<3)     /* Bit 3:	Clear Parity IRQ, Rcv */
+#define	CSR_IRQ_CL_B	(1L<<2)     /* Bit 2:	Clear EOB IRQ */
+#define	CSR_IRQ_CL_F	(1L<<1)     /* Bit 1:	Clear EOF IRQ */
+#define	CSR_IRQ_CL_C	(1L<<0)     /* Bit 0:	Clear ERR IRQ */
+
+#define CSR_SET_RESET	(CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\
+			CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLEAR|CSR_FIFO_CLEAR|CSR_HPI_RUN|CSR_SV_RUN|\
+			CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN)
+
+
+/*	B5_<xx>_F	32 bit flag register		 (xx) */
+					/* Bit 28..31:	reserved	      */
+#define F_ALM_FULL	(1L<<27)	/* Bit 27: (ML)	FIFO almost full      */
+#define F_FIFO_EOF	(1L<<26)	/* Bit 26: (ML)	Fag bit in FIFO       */
+#define F_WM_REACHED	(1L<<25)	/* Bit 25: (ML)	Watermark reached     */
+#define F_UP_DW_USED	(1L<<24)	/* Bit 24: (ML) Upper Dword used (bug)*/
+					/* Bit 23: 	reserved	      */
+#define F_FIFO_LEVEL	(0x1fL<<16)	/* Bit 16..22:(ML) # of Qwords in FIFO*/
+					/* Bit  8..15: 	reserved	      */
+#define F_ML_WATER_M	0x0000ffL	/* Bit  0.. 7:(ML) Watermark	      */
+#define	FLAG_WATER	0x00001fL	/* Bit 4..0:(DV) Level of req data tr.*/
+
+/*	B5_<xx>_T1	32 bit Test Register 1		 (xx) */
+/*		Holds four State Machine control Bytes */
+#define	SM_CRTL_SV	(0xffL<<24) /* Bit 31..24:  Control Supervisor SM */
+#define	SM_CRTL_RD	(0xffL<<16) /* Bit 23..16:  Control Read Desc SM */
+#define	SM_CRTL_WR	(0xffL<<8)  /* Bit 15..8:   Control Write Desc SM */
+#define	SM_CRTL_TR	(0xffL<<0)  /* Bit 7..0:    Control Transfer SM */
+
+/*	B4_<xx>_T1_TR	8 bit Test Register 1 TR		(xx) */
+/*	B4_<xx>_T1_WR	8 bit Test Register 1 WR		(xx) */
+/*	B4_<xx>_T1_RD	8 bit Test Register 1 RD		(xx) */
+/*	B4_<xx>_T1_SV	8 bit Test Register 1 SV		(xx) */
+/* The control status byte of each machine looks like ... */
+#define	SM_STATE	0xf0	/* Bit 7..4:	State which shall be loaded */
+#define	SM_LOAD		0x08	/* Bit 3:	Load the SM with SM_STATE */
+#define	SM_TEST_ON	0x04	/* Bit 2:	Switch on SM Test Mode */
+#define	SM_TEST_OFF	0x02	/* Bit 1:	Go off the Test Mode */
+#define	SM_STEP		0x01	/* Bit 0:	Step the State Machine */
+
+/* The coding of the states */
+#define	SM_SV_IDLE	0x0	/* Supervisor	Idle		Tr/Re	     */
+#define	SM_SV_RES_START	0x1	/* Supervisor	Res_Start	Tr/Re	     */
+#define	SM_SV_GET_DESC	0x3	/* Supervisor	Get_Desc	Tr/Re	     */
+#define	SM_SV_CHECK	0x2	/* Supervisor	Check		Tr/Re	     */
+#define	SM_SV_MOV_DATA	0x6	/* Supervisor	Move_Data	Tr/Re	     */
+#define	SM_SV_PUT_DESC	0x7	/* Supervisor	Put_Desc	Tr/Re	     */
+#define	SM_SV_SET_IRQ	0x5	/* Supervisor	Set_Irq		Tr/Re	     */
+
+#define	SM_RD_IDLE	0x0	/* Read Desc.	Idle		Tr/Re	     */
+#define	SM_RD_LOAD	0x1	/* Read Desc.	Load		Tr/Re	     */
+#define	SM_RD_WAIT_TC	0x3	/* Read Desc.	Wait_TC		Tr/Re	     */
+#define	SM_RD_RST_EOF	0x6	/* Read Desc.	Reset_EOF	   Re	     */
+#define	SM_RD_WDONE_R	0x2	/* Read Desc.	Wait_Done	   Re	     */
+#define	SM_RD_WDONE_T	0x4	/* Read Desc.	Wait_Done	Tr   	     */
+
+#define	SM_TR_IDLE	0x0	/* Trans. Data	Idle		Tr/Re	     */
+#define	SM_TR_LOAD	0x3	/* Trans. Data	Load		Tr/Re	     */
+#define	SM_TR_LOAD_R_ML	0x1	/* Trans. Data	Load		  /Re	(ML) */
+#define	SM_TR_WAIT_TC	0x2	/* Trans. Data	Wait_TC		Tr/Re	     */
+#define	SM_TR_WDONE	0x4	/* Trans. Data	Wait_Done	Tr/Re	     */
+
+#define	SM_WR_IDLE	0x0	/* Write Desc.	Idle		Tr/Re	     */
+#define	SM_WR_ABLEN	0x1	/* Write Desc.	Act_Buf_Length	Tr/Re	     */
+#define	SM_WR_LD_A4	0x2	/* Write Desc.	Load_A4		   Re	     */
+#define	SM_WR_RES_OWN	0x2	/* Write Desc.	Res_OWN		Tr   	     */
+#define	SM_WR_WAIT_EOF	0x3	/* Write Desc.	Wait_EOF	   Re	     */
+#define	SM_WR_LD_N2C_R	0x4	/* Write Desc.	Load_N2C	   Re	     */
+#define	SM_WR_WAIT_TC_R	0x5	/* Write Desc.	Wait_TC		   Re	     */
+#define	SM_WR_WAIT_TC4	0x6	/* Write Desc.	Wait_TC4	   Re	     */
+#define	SM_WR_LD_A_T	0x6	/* Write Desc.	Load_A		Tr   	     */
+#define	SM_WR_LD_A_R	0x7	/* Write Desc.	Load_A		   Re	     */
+#define	SM_WR_WAIT_TC_T	0x7	/* Write Desc.	Wait_TC		Tr   	     */
+#define	SM_WR_LD_N2C_T	0xc	/* Write Desc.	Load_N2C	Tr   	     */
+#define	SM_WR_WDONE_T	0x9	/* Write Desc.	Wait_Done	Tr   	     */
+#define	SM_WR_WDONE_R	0xc	/* Write Desc.	Wait_Done	   Re	     */
+#define SM_WR_LD_D_AD	0xe	/* Write Desc.  Load_Dumr_A	   Re	(ML) */
+#define SM_WR_WAIT_D_TC	0xf	/* Write Desc.	Wait_Dumr_TC	   Re	(ML) */
+
+/*	B5_<xx>_T2	32 bit Test Register 2		 (xx) */
+/* Note: This register is only defined for the transmit queues */
+				/* Bit 31..8:	reserved */
+#define	AC_TEST_ON	(1<<7)	/* Bit 7:	Address Counter Test Mode on */
+#define	AC_TEST_OFF	(1<<6)	/* Bit 6:	Address Counter Test Mode off*/
+#define	BC_TEST_ON	(1<<5)	/* Bit 5:	Byte Counter Test Mode on */
+#define	BC_TEST_OFF	(1<<4)	/* Bit 4:	Byte Counter Test Mode off */
+#define	TEST_STEP04	(1<<3)	/* Bit 3:	Inc AC/Dec BC by 4 */
+#define	TEST_STEP03	(1<<2)	/* Bit 2:	Inc AC/Dec BC by 3 */
+#define	TEST_STEP02	(1<<1)	/* Bit 1:	Inc AC/Dec BC by 2 */
+#define	TEST_STEP01	(1<<0)	/* Bit 0:	Inc AC/Dec BC by 1 */
+
+/*	B5_<xx>_T3	32 bit Test Register 3		 (xx) */
+/* Note: This register is only defined for the transmit queues */
+				/* Bit 31..8:	reserved */
+#define T3_MUX_2	(1<<7)	/* Bit 7: (ML)	Mux position MSB */
+#define T3_VRAM_2	(1<<6)	/* Bit 6: (ML)	Virtual RAM buffer addr MSB */
+#define	T3_LOOP		(1<<5)	/* Bit 5: 	Set Loopback (Xmit) */
+#define	T3_UNLOOP	(1<<4)	/* Bit 4: 	Unset Loopback (Xmit) */
+#define	T3_MUX		(3<<2)	/* Bit 3..2:	Mux position */
+#define	T3_VRAM		(3<<0)	/* Bit 1..0:	Virtual RAM buffer Address */
+
+/* PCI card IDs */
+/*
+ * Note: The following 4 byte definitions shall not be used! Use OEM Concept!
+ */
+#define	PCI_VEND_ID0	0x48		/* PCI vendor ID (SysKonnect) */
+#define	PCI_VEND_ID1	0x11		/* PCI vendor ID (SysKonnect) */
+					/*		 (High byte) */
+#define	PCI_DEV_ID0	0x00		/* PCI device ID */
+#define	PCI_DEV_ID1	0x40		/* PCI device ID (High byte) */
+
+/*#define PCI_CLASS	0x02*/		/* PCI class code: network device */
+#define PCI_NW_CLASS	0x02		/* PCI class code: network device */
+#define PCI_SUB_CLASS	0x02		/* PCI subclass ID: FDDI device */
+#define PCI_PROG_INTFC	0x00		/* PCI programming Interface (=0) */
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define	FMA(a)	(0x0400|((a)<<2))	/* FORMAC+ (r/w) (SN3) */
+#define	P1(a)	(0x0380|((a)<<2))	/* PLC1 (r/w) (DAS) */
+#define	P2(a)	(0x0600|((a)<<2))	/* PLC2 (r/w) (covered by the SN3) */
+#define PRA(a)	(B2_MAC_0 + (a))	/* configuration PROM (MAC address) */
+
+/*
+ * FlashProm specification
+ */
+#define	MAX_PAGES	0x20000L	/* Every byte has a single page */
+#define	MAX_FADDR	1		/* 1 byte per page */
+
+/*
+ * Receive / Transmit Buffer Control word
+ */
+#define	BMU_OWN		(1UL<<31)	/* OWN bit: 0 == host, 1 == adapter */
+#define	BMU_STF		(1L<<30)	/* Start of Frame ?		*/
+#define	BMU_EOF		(1L<<29)	/* End of Frame ?		*/
+#define	BMU_EN_IRQ_EOB	(1L<<28)	/* Enable "End of Buffer" IRQ	*/
+#define	BMU_EN_IRQ_EOF	(1L<<27)	/* Enable "End of Frame" IRQ	*/
+#define	BMU_DEV_0	(1L<<26)	/* RX: don't transfer to system mem */
+#define BMU_SMT_TX	(1L<<25)	/* TX: if set, buffer type SMT_MBuf */
+#define BMU_ST_BUF	(1L<<25)	/* RX: copy of start of frame */
+#define BMU_UNUSED	(1L<<24)	/* Set if the Descr is curr unused */
+#define BMU_SW		(3L<<24)	/* 2 Bits reserved for SW usage */
+#define	BMU_CHECK	0x00550000L	/* To identify the control word */
+#define	BMU_BBC		0x0000FFFFL	/* R/T Buffer Byte Count        */
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#ifdef MEM_MAPPED_IO
+#define	ADDR(a)		(char far *) smc->hw.iop+(a)
+#define	ADDRS(smc,a)	(char far *) (smc)->hw.iop+(a)
+#else
+#define	ADDR(a)	(((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), \
+	(smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \
+	(smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#define	ADDRS(smc,a) (((a)>>7) ? (outp((smc)->hw.iop+B0_RAP,(a)>>7), \
+	((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \
+	((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#endif
+
+/*
+ * Define a macro to access the configuration space
+ */
+#define PCI_C(a)	ADDR(B3_CFG_SPC + (a))	/* PCI Config Space */
+
+#define EXT_R(a)	ADDR(B6_EXT_REG + (a))	/* External Registers */
+
+/*
+ * Define some values needed for the MAC address (PROM)
+ */
+#define	SA_MAC		(0)	/* start addr. MAC_AD within the PROM */
+#define	PRA_OFF		(0)	/* offset correction when 4th byte reading */
+
+#define	SKFDDI_PSZ	8	/* address PROM size */
+
+#define	FM_A(a)	ADDR(FMA(a))	/* FORMAC Plus physical addr */
+#define	P1_A(a)	ADDR(P1(a))	/* PLC1 (r/w) */
+#define	P2_A(a)	ADDR(P2(a))	/* PLC2 (r/w) (DAS) */
+#define PR_A(a)	ADDR(PRA(a))	/* config. PROM (MAC address) */
+
+/*
+ * Macro to read the PROM
+ */
+#define	READ_PROM(a)	((u_char)inp(a))
+
+#define	GET_PAGE(bank)	outpd(ADDR(B2_FAR),bank)
+#define	VPP_ON()
+#define	VPP_OFF()
+
+/*
+ * Note: Values of the Interrupt Source Register are defined above
+ */
+#define ISR_A		ADDR(B0_ISRC)
+#define	GET_ISR()		inpd(ISR_A)
+#define GET_ISR_SMP(iop)	inpd((iop)+B0_ISRC)
+#define	CHECK_ISR()		(inpd(ISR_A) & inpd(ADDR(B0_IMSK)))
+#define CHECK_ISR_SMP(iop)	(inpd((iop)+B0_ISRC) & inpd((iop)+B0_IMSK))
+
+#define	BUS_CHECK()
+
+/*
+ * CLI_FBI:	Disable Board Interrupts
+ * STI_FBI:	Enable Board Interrupts
+ */
+#ifndef UNIX
+#define	CLI_FBI()	outpd(ADDR(B0_IMSK),0)
+#else
+#define	CLI_FBI(smc)	outpd(ADDRS((smc),B0_IMSK),0)
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outpd(ADDR(B0_IMSK),smc->hw.is_imask)
+#else
+#define	STI_FBI(smc)	outpd(ADDRS((smc),B0_IMSK),(smc)->hw.is_imask)
+#endif
+
+#define CLI_FBI_SMP(iop)	outpd((iop)+B0_IMSK,0)
+#define	STI_FBI_SMP(smc,iop)	outpd((iop)+B0_IMSK,(smc)->hw.is_imask)
+
+#endif	/* PCI */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * 12 bit transfer (dword) counter:
+ *	(ISA:	2*trc = number of byte)
+ *	(EISA:	4*trc = number of byte)
+ *	(MCA:	4*trc = number of byte)
+ */
+#define	MAX_TRANS	(0x0fff)
+
+/*
+ * PC PIC
+ */
+#define	MST_8259 (0x20)
+#define	SLV_8259 (0xA0)
+
+#define TPS		(18)		/* ticks per second */
+
+/*
+ * error timer defs
+ */
+#define	TN		(4)	/* number of supported timer = TN+1 */
+#define	SNPPND_TIME	(5)	/* buffer memory access over mem. data reg. */
+
+#define	MAC_AD	0x405a0000
+
+#define MODR1	FM_A(FM_MDREG1)	/* mode register 1 */
+#define MODR2	FM_A(FM_MDREG2)	/* mode register 2 */
+
+#define CMDR1	FM_A(FM_CMDREG1)	/* command register 1 */
+#define CMDR2	FM_A(FM_CMDREG2)	/* command register 2 */
+
+
+/*
+ * function defines
+ */
+#define	CLEAR(io,mask)		outpw((io),inpw(io)&(~(mask)))
+#define	SET(io,mask)		outpw((io),inpw(io)|(mask))
+#define	GET(io,mask)		(inpw(io)&(mask))
+#define	SETMASK(io,val,mask)	outpw((io),(inpw(io) & ~(mask)) | (val))
+
+/*
+ * PHY Port A (PA) = PLC 1
+ * With SuperNet 3 PHY-A and PHY S are identical.
+ */
+#define	PLC(np,reg)	(((np) == PA) ? P2_A(reg) : P1_A(reg))
+
+/*
+ * set memory address register for write and read
+ */
+#define	MARW(ma)	outpw(FM_A(FM_MARW),(unsigned int)(ma))
+#define	MARR(ma)	outpw(FM_A(FM_MARR),(unsigned int)(ma))
+
+/*
+ * read/write from/to memory data register
+ */
+/* write double word */
+#define	MDRW(dd)	outpw(FM_A(FM_MDRU),(unsigned int)((dd)>>16)) ;\
+			outpw(FM_A(FM_MDRL),(unsigned int)(dd))
+
+#ifndef WINNT
+/* read double word */
+#define	MDRR()		(((long)inpw(FM_A(FM_MDRU))<<16) + inpw(FM_A(FM_MDRL)))
+
+/* read FORMAC+ 32-bit status register */
+#define	GET_ST1()	(((long)inpw(FM_A(FM_ST1U))<<16) + inpw(FM_A(FM_ST1L)))
+#define	GET_ST2()	(((long)inpw(FM_A(FM_ST2U))<<16) + inpw(FM_A(FM_ST2L)))
+#ifdef	SUPERNET_3
+#define	GET_ST3()	(((long)inpw(FM_A(FM_ST3U))<<16) + inpw(FM_A(FM_ST3L)))
+#endif
+#else
+/* read double word */
+#define MDRR()		inp2w((FM_A(FM_MDRU)),(FM_A(FM_MDRL)))
+
+/* read FORMAC+ 32-bit status register */
+#define GET_ST1()	inp2w((FM_A(FM_ST1U)),(FM_A(FM_ST1L)))
+#define GET_ST2()	inp2w((FM_A(FM_ST2U)),(FM_A(FM_ST2L)))
+#ifdef	SUPERNET_3
+#define GET_ST3()	inp2w((FM_A(FM_ST3U)),(FM_A(FM_ST3L)))
+#endif
+#endif
+
+/* Special timer macro for 82c54 */
+				/* timer access over data bus bit 8..15 */
+#define	OUT_82c54_TIMER(port,val)	outpw(TI_A(port),(val)<<8)
+#define	IN_82c54_TIMER(port)		((inpw(TI_A(port))>>8) & 0xff)
+
+
+#ifdef	DEBUG
+#define	DB_MAC(mac,st) {if (debug_mac & 0x1)\
+				printf("M") ;\
+			if (debug_mac & 0x2)\
+				printf("\tMAC %d status 0x%08lx\n",mac,st) ;\
+			if (debug_mac & 0x4)\
+				dp_mac(mac,st) ;\
+}
+
+#define	DB_PLC(p,iev) {	if (debug_plc & 0x1)\
+				printf("P") ;\
+			if (debug_plc & 0x2)\
+				printf("\tPLC %s Int 0x%04x\n", \
+					(p == PA) ? "A" : "B", iev) ;\
+			if (debug_plc & 0x4)\
+				dp_plc(p,iev) ;\
+}
+
+#define	DB_TIMER() {	if (debug_timer & 0x1)\
+				printf("T") ;\
+			if (debug_timer & 0x2)\
+				printf("\tTimer ISR\n") ;\
+}
+
+#else	/* no DEBUG */
+
+#define	DB_MAC(mac,st)
+#define	DB_PLC(p,iev)
+#define	DB_TIMER()
+
+#endif	/* no DEBUG */
+
+#define	INC_PTR(sp,cp,ep)	if (++cp == ep) cp = sp
+/*
+ * timer defs
+ */
+#define	COUNT(t)	((t)<<6)	/* counter */
+#define	RW_OP(o)	((o)<<4)	/* read/write operation */
+#define	TMODE(m)	((m)<<1)	/* timer mode */
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/skfbiinc.h linux/drivers/net/skfp/h/skfbiinc.h
--- v2.3.46/linux/drivers/net/skfp/h/skfbiinc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/skfbiinc.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_SKFBIINC_
+#define _SKFBIINC_
+
+#include "h/supern_2.h"
+
+/*
+ * special defines for use into .asm files
+ */
+#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1)
+
+#ifdef	ISA
+#define DMA_BUSY_CHECK	CSRA
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT)
+#define	HRQR		(RQAA+(RQ_RRQ<<1))
+#define	HRQW		(RQAA+(RQ_WA2<<1))
+#define	HRQA0		(RQAA+(RQ_WA0<<1))
+#define HRQSQ		(RQAA+(RQ_WSQ<<1))
+#endif
+
+#ifdef	EISA
+#define	DMA_BUSY_CHECK	CSRA
+#define DMA_HIGH_WORD	0x0400
+#define DMA_MASK_M	0x0a
+#define DMA_MODE_M	0x0b
+#define DMA_BYTE_PTR_M	0x0c
+#define DMA_MASK_S	0x0d4
+#define DMA_MODE_S	0x0d6
+#define DMA_BYTE_PTR_S	0x0d8
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC)
+#endif	/* EISA */
+
+#ifdef	MCA
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+			 IS_CHCK_L | IS_BUSERR)
+#endif
+
+#ifdef PCI
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+			 IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
+			 IS_R1_C | IS_XA_C | IS_XS_C)
+#endif
+
+#ifdef	PCI
+#define	ISR_MASK	(IS_MINTR1 | IS_R1_F | IS_XS_F| IS_XA_F | IMASK_FAST)
+#else
+#define	ISR_MASK	(IS_MINTR1 | IS_MINTR2 | IMASK_FAST)
+#endif
+
+#define	FMA_FM_CMDREG1	FMA(FM_CMDREG1)
+#define	FMA_FM_CMDREG2	FMA(FM_CMDREG2)
+#define	FMA_FM_STMCHN	FMA(FM_STMCHN)
+#define	FMA_FM_RPR	FMA(FM_RPR)
+#define	FMA_FM_WPXA0	FMA(FM_WPXA0)
+#define	FMA_FM_WPXA2	FMA(FM_WPXA2)
+#define	FMA_FM_MARR	FMA(FM_MARR)
+#define	FMA_FM_MARW	FMA(FM_MARW)
+#define	FMA_FM_MDRU	FMA(FM_MDRU)
+#define	FMA_FM_MDRL	FMA(FM_MDRL)
+#define	FMA_ST1L	FMA(FM_ST1L)
+#define	FMA_ST1U	FMA(FM_ST1U)
+#define	FMA_ST2L	FMA(FM_ST2L)
+#define	FMA_ST2U	FMA(FM_ST2U)
+#ifdef	SUPERNET_3
+#define FMA_ST3L	FMA(FM_ST3L)
+#define FMA_ST3U	FMA(FM_ST3U)
+#endif
+
+#define TMODE_RRQ	RQ_RRQ
+#define TMODE_WAQ2	RQ_WA2
+#define	HSRA		HSR(0)
+
+
+#define FMA_FM_ST1L	FMA_ST1L
+#define FMA_FM_ST1U	FMA_ST1U
+#define FMA_FM_ST2L	FMA_ST2L
+#define FMA_FM_ST2U	FMA_ST2U
+#ifdef	SUPERNET_3
+#define FMA_FM_ST3L	FMA_ST3L
+#define FMA_FM_ST3U	FMA_ST3U
+#endif
+
+#define FMA_FM_SWPR	FMA(FM_SWPR)
+
+#define FMA_FM_RPXA0	FMA(FM_RPXA0)
+
+#define	FMA_FM_RPXS	FMA(FM_RPXS)
+#define	FMA_FM_WPXS	FMA(FM_WPXS)
+
+#define	FMA_FM_IMSK1U	FMA(FM_IMSK1U)
+#define	FMA_FM_IMSK1L	FMA(FM_IMSK1L)
+
+#define	FMA_FM_EAS	FMA(FM_EAS)
+#define	FMA_FM_EAA0	FMA(FM_EAA0)
+
+#define	TMODE_WAQ0	RQ_WA0
+#define TMODE_WSQ	RQ_WSQ
+
+/* Define default for DRV_PCM_STATE_CHANGE */
+#ifndef	DRV_PCM_STATE_CHANGE
+#define	DRV_PCM_STATE_CHANGE(smc,plc,p_state)	/* nothing */
+#endif
+
+/* Define default for DRV_RMT_INDICATION */
+#ifndef	DRV_RMT_INDICATION
+#define	DRV_RMT_INDICATION(smc,i)	/* nothing */
+#endif
+
+#endif	/* n_SKFBIINC_ */
+
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smc.h linux/drivers/net/skfp/h/smc.h
--- v2.3.46/linux/drivers/net/skfp/h/smc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/smc.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_SCMECM_
+#define _SCMECM_
+
+#if	defined(PCI) && !defined(OSDEF)
+/*
+ * In the case of the PCI bus the file osdef1st.h must be present
+ */
+#define	OSDEF
+#endif
+
+#ifdef	PCI
+#ifndef	SUPERNET_3
+#define	SUPERNET_3
+#endif
+#ifndef	TAG_MODE
+#define	TAG_MODE
+#endif
+#endif
+
+/*
+ * include all other files in required order
+ * the following files must have been included before:
+ *	types.h
+ *	fddi.h
+ */
+#ifdef	OSDEF
+#include "h/osdef1st.h"
+#endif	/* OSDEF */
+#ifdef	OEM_CONCEPT
+#include "oemdef.h"
+#endif	/* OEM_CONCEPT */
+#include "h/smt.h"
+#include "h/cmtdef.h"
+#include "h/fddimib.h"
+#include "h/targethw.h"		/* all target hw dependencies */
+#include "h/targetos.h"		/* all target os dependencies */
+#ifdef	ESS
+#include "h/sba.h"
+#endif
+
+/*
+ * Event Queue
+ *	queue.c
+ * events are class/value pairs
+ *	class	is addressee, e.g. RMT, PCM etc.
+ *	value	is command, e.g. line state change, ring op change etc.
+ */
+struct event_queue {
+	u_short	class ;			/* event class */
+	u_short	event ;			/* event value */
+} ;
+
+/*
+ * define event queue as circular buffer
+ */
+#ifdef	CONCENTRATOR
+#define MAX_EVENT	128
+#else	/* nCONCENTRATOR */
+#define MAX_EVENT	64
+#endif	/* nCONCENTRATOR */
+
+struct s_queue {
+
+	struct event_queue ev_queue[MAX_EVENT];
+	struct event_queue *ev_put ;
+	struct event_queue *ev_get ;
+} ;
+
+/*
+ * ECM - Entity Coordination Management
+ * ecm.c
+ */
+struct s_ecm {
+	u_char path_test ;		/* ECM path test variable */
+	u_char sb_flag ;		/* ECM stuck bypass */
+	u_char DisconnectFlag ;		/* jd 05-Aug-1999 Bug #10419 
+					 * ECM disconnected */
+	u_char ecm_line_state ;		/* flag to dispatcher : line states */
+	u_long trace_prop ;		/* ECM Trace_Prop flag >= 16 bits !! */
+	/* NUMPHYS note:
+	 * this variable must have enough bits to hold all entiies in
+	 * the station. So NUMPHYS may not be greater than 31.
+	 */
+	char	ec_pad[2] ;
+	struct smt_timer ecm_timer ;	/* timer */
+} ;
+
+
+/*
+ * RMT - Ring Management
+ * rmt.c
+ */
+struct s_rmt {
+	u_char dup_addr_test ;		/* state of dupl. addr. test */
+	u_char da_flag ;		/* flag : duplicate address det. */
+	u_char loop_avail ;		/* flag : MAC available for loopback */
+	u_char sm_ma_avail ;		/* flag : MAC available for SMT */
+	u_char no_flag ;		/* flag : ring not operational */
+	u_char bn_flag ;		/* flag : MAC reached beacon state */
+	u_char jm_flag ;		/* flag : jamming in NON_OP_DUP */
+	u_char rm_join ;		/* CFM flag RM_Join */
+	u_char rm_loop ;		/* CFM flag RM_Loop */
+
+	long fast_rm_join ;		/* bit mask of active ports */
+	/*
+	 * timer and flags
+	 */
+	struct smt_timer rmt_timer0 ;	/* timer 0 */
+	struct smt_timer rmt_timer1 ;	/* timer 1 */
+	struct smt_timer rmt_timer2 ;	/* timer 2 */
+	u_char timer0_exp ;		/* flag : timer 0 expired */
+	u_char timer1_exp ;		/* flag : timer 1 expired */
+	u_char timer2_exp ;		/* flag : timer 2 expired */
+
+	u_char rm_pad1[1] ;
+} ;
+
+/*
+ * CFM - Configuration Management
+ * cfm.c
+ * used for SAS and DAS
+ */
+struct s_cfm {
+	u_char cf_state;		/* CFM state machine current state */
+	u_char cf_pad[3] ;
+} ;
+
+/*
+ * CEM - Configuration Element Management
+ * cem.c
+ * used for Concentrator
+ */
+#ifdef	CONCENTRATOR
+struct s_cem {
+	int	ce_state ;	/* CEM state */
+	int	ce_port ;	/* PA PB PM PM+1 .. */
+	int	ce_type ;	/* TA TB TS TM */
+} ;
+
+/*
+ * linked list of CCEs in current token path
+ */
+struct s_c_ring {
+	struct s_c_ring	*c_next ;
+	char		c_entity ;
+} ;
+
+struct mib_path_config {
+	u_long	fddimibPATHConfigSMTIndex;
+	u_long	fddimibPATHConfigPATHIndex;
+	u_long	fddimibPATHConfigTokenOrder;
+	u_long	fddimibPATHConfigResourceType;
+#define SNMP_RES_TYPE_MAC	2	/* Resource is a MAC */
+#define SNMP_RES_TYPE_PORT	4	/* Resource is a PORT */
+	u_long	fddimibPATHConfigResourceIndex;
+	u_long	fddimibPATHConfigCurrentPath;
+#define SNMP_PATH_ISOLATED	1	/* Current path is isolated */
+#define SNMP_PATH_LOCAL		2	/* Current path is local */
+#define SNMP_PATH_SECONDARY	3	/* Current path is secondary */
+#define SNMP_PATH_PRIMARY	4	/* Current path is primary */
+#define SNMP_PATH_CONCATENATED	5	/* Current path is concatenated */
+#define SNMP_PATH_THRU		6	/* Current path is thru */
+};
+
+
+#endif
+
+/*
+ * PCM connect states
+ */
+#define PCM_DISABLED	0
+#define PCM_CONNECTING	1
+#define PCM_STANDBY	2
+#define PCM_ACTIVE	3
+
+struct s_pcm {
+	u_char	pcm_pad[3] ;
+} ;
+
+/*
+ * PHY struct
+ * one per physical port
+ */
+struct s_phy {
+	/* Inter Module Globals */
+	struct fddi_mib_p	*mib ;
+
+	u_char np ;		/* index 0 .. NUMPHYS */
+	u_char cf_join ;
+	u_char cf_loop ;
+	u_char wc_flag ;	/* withhold connection flag */
+	u_char pc_mode ;	/* Holds the negotiated mode of the PCM */
+	u_char pc_lem_fail ;	/* flag : LCT failed */
+	u_char lc_test ;
+	u_char scrub ;		/* CFM flag Scrub -> PCM */
+	char phy_name ;
+	u_char pmd_type[2] ;	/* SK connector/transceiver type codes */
+#define PMD_SK_CONN	0	/* pmd_type[PMD_SK_CONN] = Connector */
+#define PMD_SK_PMD	1	/* pmd_type[PMD_SK_PMD] = Xver */
+	u_char pmd_scramble ;	/* scrambler on/off */
+
+	/* inner Module Globals */
+	u_char curr_ls ;	/* current line state */
+	u_char ls_flag ;
+	u_char rc_flag ;
+	u_char tc_flag ;
+	u_char td_flag ;
+	u_char bitn ;
+	u_char tr_flag ;	/* trace recvd while in active */
+	u_char twisted ;	/* flag to indicate an A-A or B-B connection */
+	u_char t_val[NUMBITS] ;	/* transmit bits for signaling */
+	u_char r_val[NUMBITS] ;	/* receive bits for signaling */
+	u_long t_next[NUMBITS] ;
+	struct smt_timer pcm_timer0 ;
+	struct smt_timer pcm_timer1 ;
+	struct smt_timer pcm_timer2 ;
+	u_char timer0_exp ;
+	u_char timer1_exp ;
+	u_char timer2_exp ;
+	u_char pcm_pad1[1] ;
+	int	cem_pst ;	/* CEM privae state; used for dual homing */
+	struct lem_counter lem ;
+#ifdef	AMDPLC
+	struct s_plc	plc ;
+#endif
+} ;
+
+/*
+ * timer package
+ * smttimer.c
+ */
+struct s_timer {
+	struct smt_timer	*st_queue ;
+	struct smt_timer	st_fast ;
+} ;
+
+/*
+ * SRF types and data
+ */
+#define SMT_EVENT_BASE			1
+#define SMT_EVENT_MAC_PATH_CHANGE	(SMT_EVENT_BASE+0)
+#define SMT_EVENT_MAC_NEIGHBOR_CHANGE	(SMT_EVENT_BASE+1)
+#define SMT_EVENT_PORT_PATH_CHANGE	(SMT_EVENT_BASE+2)
+#define SMT_EVENT_PORT_CONNECTION	(SMT_EVENT_BASE+3)
+
+#define SMT_IS_CONDITION(x)			((x)>=SMT_COND_BASE)
+
+#define SMT_COND_BASE		(SMT_EVENT_PORT_CONNECTION+1)
+#define SMT_COND_SMT_PEER_WRAP		(SMT_COND_BASE+0)
+#define SMT_COND_SMT_HOLD		(SMT_COND_BASE+1)
+#define SMT_COND_MAC_FRAME_ERROR	(SMT_COND_BASE+2)
+#define SMT_COND_MAC_DUP_ADDR		(SMT_COND_BASE+3)
+#define SMT_COND_MAC_NOT_COPIED		(SMT_COND_BASE+4)
+#define SMT_COND_PORT_EB_ERROR		(SMT_COND_BASE+5)
+#define SMT_COND_PORT_LER		(SMT_COND_BASE+6)
+
+#define SR0_WAIT	0
+#define SR1_HOLDOFF	1
+#define SR2_DISABLED	2
+
+struct s_srf {
+	u_long	SRThreshold ;			/* threshold value */
+	u_char	RT_Flag ;			/* report transmitted flag */
+	u_char	sr_state ;			/* state-machine */
+	u_char	any_report ;			/* any report required */
+	u_long	TSR ;				/* timer */
+	u_short	ring_status ;			/* IBM ring status */
+} ;
+
+/*
+ * IBM token ring status
+ */
+#define RS_RES15	(1<<15)			/* reserved */
+#define RS_HARDERROR	(1<<14)			/* ring down */
+#define RS_SOFTERROR	(1<<13)			/* sent SRF */
+#define RS_BEACON	(1<<12)			/* transmitted beacon */
+#define RS_PATHTEST	(1<<11)			/* path test failed */
+#define RS_SELFTEST	(1<<10)			/* selftest required */
+#define RS_RES9		(1<< 9)			/* reserved */
+#define RS_DISCONNECT	(1<< 8)			/* remote disconnect */
+#define RS_RES7		(1<< 7)			/* reserved */
+#define RS_DUPADDR	(1<< 6)			/* duplicate address */
+#define RS_NORINGOP	(1<< 5)			/* no ring op */
+#define RS_VERSION	(1<< 4)			/* SMT version mismatch */
+#define RS_STUCKBYPASSS	(1<< 3)			/* stuck bypass */
+#define RS_EVENT	(1<< 2)			/* FDDI event occured */
+#define RS_RINGOPCHANGE	(1<< 1)			/* ring op changed */
+#define RS_RES0		(1<< 0)			/* reserved */
+
+#define RS_SET(smc,bit) \
+	ring_status_indication(smc,smc->srf.ring_status |= bit)
+#define RS_CLEAR(smc,bit)	\
+	ring_status_indication(smc,smc->srf.ring_status &= ~bit)
+
+#define RS_CLEAR_EVENT	(0xffff & ~(RS_NORINGOP))
+
+/* Define the AIX-event-Notification as null function if it isn't defined */
+/* in the targetos.h file */
+#ifndef AIX_EVENT
+#define AIX_EVENT(smc,opt0,opt1,opt2,opt3)	/* nothing */
+#endif
+
+struct s_srf_evc {
+	u_char	evc_code ;			/* event code type */
+	u_char	evc_index ;			/* index for mult. instances */
+	u_char	evc_rep_required ;		/* report required */
+	u_short	evc_para ;			/* SMT Para Number */
+	u_char	*evc_cond_state ;		/* condition state */
+	u_char	*evc_multiple ;			/* multiple occurence */
+} ;
+
+/*
+ * Values used by frame based services
+ * smt.c
+ */
+#define SMT_MAX_TEST		5
+#define SMT_TID_NIF		0		/* pending NIF request */
+#define SMT_TID_NIF_TEST	1		/* pending NIF test */
+#define SMT_TID_ECF_UNA		2		/* pending ECF UNA test */
+#define SMT_TID_ECF_DNA		3		/* pending ECF DNA test */
+#define SMT_TID_ECF		4		/* pending ECF test */
+
+struct smt_values {
+	u_long		smt_tvu ;		/* timer valid una */
+	u_long		smt_tvd ;		/* timer valid dna */
+	u_long		smt_tid ;		/* transaction id */
+	u_long		pend[SMT_MAX_TEST] ;	/* TID of requests */
+	u_long		uniq_time ;		/* unique time stamp */
+	u_short		uniq_ticks  ;		/* unique time stamp */
+	u_short		please_reconnect ;	/* flag : reconnect */
+	u_long		smt_last_lem ;
+	u_long		smt_last_notify ;
+	struct smt_timer	smt_timer ;	/* SMT NIF timer */
+	u_long		last_tok_time[NUMMACS];	/* token cnt emulation */
+} ;
+
+/*
+ * SMT/CMT configurable parameters
+ */
+#define SMT_DAS	0			/* dual attach */
+#define SMT_SAS	1			/* single attach */
+#define SMT_NAC	2			/* null attach concentrator */
+
+struct smt_config {
+	u_char	attach_s ;		/* CFM attach to secondary path */
+	u_char	sas ;			/* SMT_DAS/SAS/NAC */
+	u_char	build_ring_map ;	/* build ringmap if TRUE */
+	u_char	numphys ;		/* number of active phys */
+	u_char	sc_pad[1] ;
+
+	u_long	pcm_tb_min ;		/* PCM : TB_Min timer value */
+	u_long	pcm_tb_max ;		/* PCM : TB_Max timer value */
+	u_long	pcm_c_min ;		/* PCM : C_Min timer value */
+	u_long	pcm_t_out ;		/* PCM : T_Out timer value */
+	u_long	pcm_tl_min ;		/* PCM : TL_min timer value */
+	u_long	pcm_lc_short ;		/* PCM : LC_Short timer value */
+	u_long	pcm_lc_medium ;		/* PCM : LC_Medium timer value */
+	u_long	pcm_lc_long ;		/* PCM : LC_Long timer value */
+	u_long	pcm_lc_extended ;	/* PCM : LC_Extended timer value */
+	u_long	pcm_t_next_9 ;		/* PCM : T_Next[9] timer value */
+	u_long	pcm_ns_max ;		/* PCM : NS_Max timer value */
+
+	u_long	ecm_i_max ;		/* ECM : I_Max timer value */
+	u_long	ecm_in_max ;		/* ECM : IN_Max timer value */
+	u_long	ecm_td_min ;		/* ECM : TD_Min timer */
+	u_long	ecm_test_done ;		/* ECM : path test done timer */
+	u_long	ecm_check_poll ;	/* ECM : check bypass poller */
+
+	u_long	rmt_t_non_op ;		/* RMT : T_Non_OP timer value */
+	u_long	rmt_t_stuck ;		/* RMT : T_Stuck timer value */
+	u_long	rmt_t_direct ;		/* RMT : T_Direct timer value */
+	u_long	rmt_t_jam ;		/* RMT : T_Jam timer value */
+	u_long	rmt_t_announce ;	/* RMT : T_Announce timer value */
+	u_long	rmt_t_poll ;		/* RMT : claim/beacon poller */
+	u_long  rmt_dup_mac_behavior ;  /* Flag for the beavior of SMT if
+					 * a Duplicate MAC Address was detected.
+					 * FALSE: SMT will leave finaly the ring
+					 * TRUE:  SMT will reinstert into the ring
+					 */
+	u_long	mac_d_max ;		/* MAC : D_Max timer value */
+
+	u_long lct_short ;		/* LCT : error threshhold */
+	u_long lct_medium ;		/* LCT : error threshhold */
+	u_long lct_long ;		/* LCT : error threshhold */
+	u_long lct_extended ;		/* LCT : error threshhold */
+} ;
+
+#ifdef	DEBUG
+/*
+ * Debugging struct sometimes used in smc
+ */
+struct	smt_debug {
+	int	d_smtf ;
+	int	d_smt ;
+	int	d_ecm ;
+	int	d_rmt ;
+	int	d_cfm ;
+	int	d_pcm ;
+	int	d_plc ;
+#ifdef	ESS
+	int	d_ess ;
+#endif
+#ifdef	SBA
+	int	d_sba ;
+#endif
+	struct	os_debug	d_os;	/* Include specific OS DEBUG struct */
+} ;
+
+#ifndef	DEBUG_BRD
+/* all boards shall be debugged with one debug struct */
+extern	struct	smt_debug	debug;	/* Declaration of debug struct */
+#endif	/* DEBUG_BRD */
+
+#endif	/* DEBUG */
+
+/*
+ * the SMT Context Struct SMC
+ * this struct contains ALL global variables of SMT
+ */
+struct s_smc {
+	struct s_smt_os	os ;		/* os specific */
+	struct s_smt_hw	hw ;		/* hardware */
+
+/*
+ * NOTE: os and hw MUST BE the first two structs
+ * anything beyond hw WILL BE SET TO ZERO in smt_set_defaults()
+ */
+	struct smt_config s ;		/* smt constants */
+	struct smt_values sm ;		/* smt variables */
+	struct s_ecm	e ;		/* ecm */
+	struct s_rmt	r ;		/* rmt */
+	struct s_cfm	cf ;		/* cfm/cem */
+#ifdef	CONCENTRATOR
+	struct s_cem	ce[NUMPHYS] ;	/* cem */
+	struct s_c_ring	cr[NUMPHYS+NUMMACS] ;
+#endif
+	struct s_pcm	p ;		/* pcm */
+	struct s_phy	y[NUMPHYS] ;	/* phy */
+	struct s_queue	q ;		/* queue */
+	struct s_timer	t ;		/* timer */
+	struct s_srf srf ;		/* SRF */
+	struct s_srf_evc evcs[6+NUMPHYS*4] ;
+	struct fddi_mib	mib ;		/* __THE_MIB__ */
+#ifdef	SBA
+	struct s_sba	sba ;		/* SBA variables */
+#endif
+#ifdef	ESS
+	struct s_ess	ess ;		/* Ess variables */
+#endif
+#if	defined(DEBUG) && defined(DEBUG_BRD)
+	/* If you want all single board to be debugged separately */
+	struct smt_debug	debug;	/* Declaration of debug struct */
+#endif	/* DEBUG_BRD && DEBUG */
+} ;
+
+#endif	/* _SCMECM_ */
+
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smt.h linux/drivers/net/skfp/h/smt.h
--- v2.3.46/linux/drivers/net/skfp/h/smt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/smt.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,882 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	SMT 7.2 frame definitions
+ */
+
+#ifndef	_SMT_
+#define _SMT_
+
+/* #define SMT5_10 */
+#define SMT6_10
+#define SMT7_20
+
+#define	OPT_PMF		/* if parameter management is supported */
+#define	OPT_SRF		/* if status report is supported */
+
+/*
+ * SMT frame version 5.1
+ */
+
+#define SMT_VID	0x0001			/* V 5.1 .. 6.1 */
+#define SMT_VID_2 0x0002		/* V 7.2 */
+
+struct smt_sid {
+	u_char	sid_oem[2] ;			/* implementation spec. */
+	struct fddi_addr sid_node ;		/* node address */
+} ;
+
+typedef u_char	t_station_id[8] ;
+
+/*
+ * note on alignment :
+ * sizeof(struct smt_header) = 32
+ * all parameters are long aligned
+ * if struct smt_header starts at offset 0, all longs are aligned correctly
+ * (FC starts at offset 3)
+ */
+_packed struct smt_header {
+	struct fddi_addr    	smt_dest ;	/* destination address */
+	struct fddi_addr	smt_source ;	/* source address */
+	u_char			smt_class ;	/* NIF, SIF ... */
+	u_char			smt_type ;	/* req., response .. */
+	u_short			smt_version ;	/* version id */
+	u_long			smt_tid ;	/* transaction ID */
+	struct smt_sid		smt_sid ;	/* station ID */
+	u_short			smt_pad ;	/* pad with 0 */
+	u_short			smt_len ;	/* length of info field */
+} ;
+#define SWAP_SMTHEADER	"662sl8ss"
+
+#if	0
+/*
+ * MAC FC values
+ */
+#define FC_SMT_INFO	0x41		/* SMT info */
+#define FC_SMT_NSA	0x4f		/* SMT Next Station Addressing */
+#endif
+
+
+/*
+ * type codes
+ */
+#define SMT_ANNOUNCE	0x01		/* announcement */
+#define SMT_REQUEST	0x02		/* request */
+#define SMT_REPLY	0x03		/* reply */
+
+/*
+ * class codes
+ */
+#define SMT_NIF		0x01		/* neighbor information frames */
+#define SMT_SIF_CONFIG	0x02		/* station information configuration */
+#define SMT_SIF_OPER	0x03		/* station information operation */
+#define SMT_ECF		0x04		/* echo frames */
+#define SMT_RAF		0x05		/* resource allocation */
+#define SMT_RDF		0x06		/* request denied */
+#define SMT_SRF		0x07		/* status report */
+#define SMT_PMF_GET	0x08		/* parameter management get */
+#define SMT_PMF_SET	0x09		/* parameter management set */
+#define SMT_ESF		0xff		/* extended service */
+
+#define SMT_MAX_ECHO_LEN	4458	/* max length of SMT Echo */
+#if	defined(CONC) || defined(CONC_II)
+#define SMT_TEST_ECHO_LEN	50	/* test length of SMT Echo */
+#else
+#define SMT_TEST_ECHO_LEN	SMT_MAX_ECHO_LEN	/* test length */
+#endif
+
+#define SMT_MAX_INFO_LEN	(4352-20)	/* max length for SMT info */
+
+
+/*
+ * parameter types
+ */
+
+struct smt_para {
+	u_short	p_type ;		/* type */
+	u_short	p_len ;			/* length of parameter */
+} ;
+
+#define PARA_LEN	(sizeof(struct smt_para))
+
+#define SMTSETPARA(p,t)		(p)->para.p_type = (t),\
+				(p)->para.p_len = sizeof(*(p)) - PARA_LEN
+
+/*
+ * P01 : Upstream Neighbor Address, UNA
+ */
+#define SMT_P_UNA	0x0001		/* upstream neighbor address */
+#define SWAP_SMT_P_UNA	"s6"
+
+struct smt_p_una {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	una_pad ;
+	struct fddi_addr una_node ;	/* node address, zero if unknown */
+} ;
+
+/*
+ * P02 : Station Descriptor
+ */
+#define SMT_P_SDE	0x0002		/* station descriptor */
+#define SWAP_SMT_P_SDE	"1111"
+
+#define SMT_SDE_STATION		0	/* end node */
+#define SMT_SDE_CONCENTRATOR	1	/* concentrator */
+
+struct smt_p_sde {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char	sde_type ;		/* station type */
+	u_char	sde_mac_count ;		/* number of MACs */
+	u_char	sde_non_master ;	/* number of A,B or S ports */
+	u_char	sde_master ;		/* number of S ports on conc. */
+} ;
+
+/*
+ * P03 : Station State
+ */
+#define SMT_P_STATE	0x0003		/* station state */
+#define SWAP_SMT_P_STATE	"scc"
+
+struct smt_p_state {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	st_pad ;
+	u_char	st_topology ;		/* topology */
+	u_char	st_dupl_addr ;		/* duplicate address detected */
+} ;
+#define SMT_ST_WRAPPED		(1<<0)	/* station wrapped */
+#define SMT_ST_UNATTACHED	(1<<1)	/* unattached concentrator */
+#define SMT_ST_TWISTED_A	(1<<2)	/* A-A connection, twisted ring */
+#define SMT_ST_TWISTED_B	(1<<3)	/* B-B connection, twisted ring */
+#define SMT_ST_ROOTED_S		(1<<4)	/* rooted station */
+#define SMT_ST_SRF		(1<<5)	/* SRF protocol supported */
+#define SMT_ST_SYNC_SERVICE	(1<<6)	/* use synchronous bandwidth */
+
+#define SMT_ST_MY_DUPA		(1<<0)	/* my station detected dupl. */
+#define SMT_ST_UNA_DUPA		(1<<1)	/* my UNA detected duplicate */
+
+/*
+ * P04 : timestamp
+ */
+#define SMT_P_TIMESTAMP	0x0004		/* time stamp */
+#define SWAP_SMT_P_TIMESTAMP	"8"
+struct smt_p_timestamp {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char	ts_time[8] ;		/* time, resolution 80nS, unique */
+} ;
+
+/*
+ * P05 : station policies
+ */
+#define SMT_P_POLICY	0x0005		/* station policies */
+#define SWAP_SMT_P_POLICY	"ss"
+
+struct smt_p_policy {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	pl_config ;
+	u_short pl_connect ;		/* bit string POLICY_AA ... */
+} ;
+#define SMT_PL_HOLD		1	/* hold policy supported (Dual MAC) */
+
+/*
+ * P06 : latency equivalent
+ */
+#define SMT_P_LATENCY	0x0006		/* latency */
+#define SWAP_SMT_P_LATENCY	"ssss"
+
+/*
+ * note: latency has two phy entries by definition
+ * for a SAS, the 2nd one is null
+ */
+struct smt_p_latency {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	lt_phyout_idx1 ;	/* index */
+	u_short	lt_latency1 ;		/* latency , unit : byte clock */
+	u_short	lt_phyout_idx2 ;	/* 0 if SAS */
+	u_short	lt_latency2 ;		/* 0 if SAS */
+} ;
+
+/*
+ * P07 : MAC neighbors
+ */
+#define SMT_P_NEIGHBORS	0x0007		/* MAC neighbor description */
+#define SWAP_SMT_P_NEIGHBORS	"ss66"
+
+struct smt_p_neighbor {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	nb_mib_index ;		/* MIB index */
+	u_short	nb_mac_index ;		/* n+1 .. n+m, m = #MACs, n = #PHYs */
+	struct fddi_addr nb_una ;	/* UNA , 0 for unknown */
+	struct fddi_addr nb_dna ;	/* DNA , 0 for unknown */
+} ;
+
+/*
+ * PHY record
+ */
+#define SMT_PHY_A	0		/* A port */
+#define SMT_PHY_B	1		/* B port */
+#define SMT_PHY_S	2		/* slave port */
+#define SMT_PHY_M	3		/* master port */
+
+#define SMT_CS_DISABLED	0		/* connect state : disabled */
+#define SMT_CS_CONNECTING	1	/* connect state : connecting */
+#define SMT_CS_STANDBY	2		/* connect state : stand by */
+#define SMT_CS_ACTIVE	3		/* connect state : active */
+
+#define SMT_RM_NONE	0
+#define SMT_RM_MAC	1
+
+struct smt_phy_rec {
+	u_short	phy_mib_index ;		/* MIB index */
+	u_char	phy_type ;		/* A/B/S/M */
+	u_char	phy_connect_state ;	/* disabled/connecting/active */
+	u_char	phy_remote_type ;	/* A/B/S/M */
+	u_char	phy_remote_mac ;	/* none/remote */
+	u_short	phy_resource_idx ;	/* 1 .. n */
+} ;
+
+/*
+ * MAC record
+ */
+struct smt_mac_rec {
+	struct fddi_addr mac_addr ;		/* MAC address */
+	u_short		mac_resource_idx ;	/* n+1 .. n+m */
+} ;
+
+/*
+ * P08 : path descriptors
+ * should be really an array ; however our environment has a fixed number of
+ * PHYs and MACs
+ */
+#define SMT_P_PATH	0x0008			/* path descriptor */
+#define SWAP_SMT_P_PATH	"[6s]"
+
+struct smt_p_path {
+	struct smt_para	para ;		/* generic parameter header */
+	struct smt_phy_rec	pd_phy[2] ;	/* PHY A */
+	struct smt_mac_rec	pd_mac ;	/* MAC record */
+} ;
+
+/*
+ * P09 : MAC status
+ */
+#define SMT_P_MAC_STATUS	0x0009		/* MAC status */
+#define SWAP_SMT_P_MAC_STATUS	"sslllllllll"
+
+struct smt_p_mac_status {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short st_mib_index ;		/* MIB index */
+	u_short	st_mac_index ;		/* n+1 .. n+m */
+	u_long	st_t_req ;		/* T_Req */
+	u_long	st_t_neg ;		/* T_Neg */
+	u_long	st_t_max ;		/* T_Max */
+	u_long	st_tvx_value ;		/* TVX_Value */
+	u_long	st_t_min ;		/* T_Min */
+	u_long	st_sba ;		/* synchr. bandwidth alloc */
+	u_long	st_frame_ct ;		/* frame counter */
+	u_long	st_error_ct ;		/* error counter */
+	u_long	st_lost_ct ;		/* lost frames counter */
+} ;
+
+/*
+ * P0A : PHY link error rate monitoring
+ */
+#define SMT_P_LEM	0x000a		/* link error monitor */
+#define SWAP_SMT_P_LEM	"ssccccll"
+/*
+ * units of lem_cutoff,lem_alarm,lem_estimate : 10**-x
+ */
+struct smt_p_lem {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	lem_mib_index ;		/* MIB index */
+	u_short	lem_phy_index ;		/* 1 .. n */
+	u_char	lem_pad2 ;		/* be nice and make it even . */
+	u_char	lem_cutoff ;		/* 0x4 .. 0xf, default 0x7 */
+	u_char	lem_alarm ;		/* 0x4 .. 0xf, default 0x8 */
+	u_char	lem_estimate ;		/* 0x0 .. 0xff */
+	u_long	lem_reject_ct ;		/* 0x00000000 .. 0xffffffff */
+	u_long	lem_ct ;		/* 0x00000000 .. 0xffffffff */
+} ;
+
+/*
+ * P0B : MAC frame counters
+ */
+#define SMT_P_MAC_COUNTER 0x000b	/* MAC frame counters */
+#define SWAP_SMT_P_MAC_COUNTER	"ssll"
+
+struct smt_p_mac_counter {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	mc_mib_index ;		/* MIB index */
+	u_short	mc_index ;		/* mac index */
+	u_long	mc_receive_ct ;		/* receive counter */
+	u_long	mc_transmit_ct ;	/* transmit counter */
+} ;
+
+/*
+ * P0C : MAC frame not copied counter
+ */
+#define SMT_P_MAC_FNC	0x000c		/* MAC frame not copied counter */
+#define SWAP_SMT_P_MAC_FNC	"ssl"
+
+struct smt_p_mac_fnc {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	nc_mib_index ;		/* MIB index */
+	u_short	nc_index ;		/* mac index */
+	u_long	nc_counter ;		/* not copied counter */
+} ;
+
+
+/*
+ * P0D : MAC priority values
+ */
+#define SMT_P_PRIORITY	0x000d		/* MAC priority values */
+#define SWAP_SMT_P_PRIORITY	"ssl"
+
+struct smt_p_priority {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	pr_mib_index ;		/* MIB index */
+	u_short	pr_index ;		/* mac index */
+	u_long	pr_priority[7] ;	/* priority values */
+} ;
+
+/*
+ * P0E : PHY elasticity buffer status
+ */
+#define SMT_P_EB	0x000e		/* PHY EB status */
+#define SWAP_SMT_P_EB	"ssl"
+
+struct smt_p_eb {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	eb_mib_index ;		/* MIB index */
+	u_short	eb_index ;		/* phy index */
+	u_long	eb_error_ct ;		/* # of eb overflows */
+} ;
+
+/*
+ * P0F : manufacturer field
+ */
+#define SMT_P_MANUFACTURER	0x000f	/* manufacturer field */
+#define SWAP_SMT_P_MANUFACTURER	""
+
+struct smp_p_manufacturer {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char mf_data[32] ;		/* OUI + arbitrary data */
+} ;
+
+/*
+ * P10 : user field
+ */
+#define SMT_P_USER		0x0010	/* manufacturer field */
+#define SWAP_SMT_P_USER	""
+
+struct smp_p_user {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char us_data[32] ;		/* arbitrary data */
+} ;
+
+
+
+/*
+ * P11 : echo data
+ */
+#define SMT_P_ECHODATA	0x0011		/* echo data */
+#define SWAP_SMT_P_ECHODATA	""
+
+struct smt_p_echo {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char	ec_data[SMT_MAX_ECHO_LEN-4] ;	/* echo data */
+} ;
+
+/*
+ * P12 : reason code
+ */
+#define SMT_P_REASON	0x0012		/* reason code */
+#define SWAP_SMT_P_REASON	"l"
+
+struct smt_p_reason {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long	rdf_reason ;		/* CLASS/VERSION */
+} ;
+#define SMT_RDF_CLASS	0x00000001	/* class not supported */
+#define SMT_RDF_VERSION	0x00000002	/* version not supported */
+#define SMT_RDF_SUCCESS	0x00000003	/* success (PMF) */
+#define SMT_RDF_BADSET	0x00000004	/* bad set count (PMF) */
+#define SMT_RDF_ILLEGAL 0x00000005	/* read only (PMF) */
+#define SMT_RDF_NOPARAM	0x6		/* paramter not supported (PMF) */
+#define SMT_RDF_RANGE	0x8		/* out of range */
+#define SMT_RDF_AUTHOR	0x9		/* not autohorized */
+#define SMT_RDF_LENGTH	0x0a		/* length error */
+#define SMT_RDF_TOOLONG	0x0b		/* length error */
+#define SMT_RDF_SBA	0x0d		/* SBA denied */
+
+/*
+ * P13 : refused frame beginning
+ */
+#define SMT_P_REFUSED	0x0013		/* refused frame beginning */
+#define SWAP_SMT_P_REFUSED	"l"
+
+struct smt_p_refused {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long	ref_fc ;		/* 3 bytes 0 + FC */
+	struct smt_header	ref_header ;	/* refused header */
+} ;
+
+/*
+ * P14 : supported SMT versions
+ */
+#define SMT_P_VERSION	0x0014		/* SMT supported versions */
+#define SWAP_SMT_P_VERSION	"sccss"
+
+struct smt_p_version {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	v_pad ;
+	u_char	v_n ;			/* 1 .. 0xff, #versions */
+	u_char	v_index ;		/* 1 .. 0xff, index of op. v. */
+	u_short	v_version[1] ;		/* list of min. 1 version */
+	u_short	v_pad2 ;		/* pad if necessary */
+} ;
+
+/*
+ * P15 : Resource Type
+ */
+#define	SWAP_SMT_P0015		"l"
+
+struct smt_p_0015 {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long		res_type ;	/* recsource type */
+} ;
+
+#define	SYNC_BW		0x00000001L	/* Synchronous Bandwidth */
+
+/*
+ * P16 : SBA Command
+ */
+#define	SWAP_SMT_P0016		"l"
+
+struct smt_p_0016 {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long		sba_cmd ;	/* command for the SBA */
+} ;
+
+#define	REQUEST_ALLOCATION	0x1	/* req allocation of sync bandwidth */
+#define	REPORT_ALLOCATION	0x2	/* rep of sync bandwidth allocation */
+#define	CHANGE_ALLOCATION	0x3	/* forces a station using sync band-*/
+					/* width to change its current allo-*/
+					/* cation */
+
+/*
+ * P17 : SBA Payload Request
+ */
+#define	SWAP_SMT_P0017		"l"
+
+struct smt_p_0017 {
+	struct smt_para	para ;		/* generic parameter header */
+	long		sba_pl_req ;	/* total sync bandwidth measured in */
+} ;					/* bytes per 125 us */
+
+/*
+ * P18 : SBA Overhead Request
+ */
+#define	SWAP_SMT_P0018		"l"
+
+struct smt_p_0018 {
+	struct smt_para	para ;		/* generic parameter header */
+	long		sba_ov_req ;	/* total sync bandwidth req for overhead*/
+} ;					/* measuered in bytes per T_Neg */
+
+/*
+ * P19 : SBA Allocation Address
+ */
+#define	SWAP_SMT_P0019		"s6"
+
+struct smt_p_0019 {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short		sba_pad ;
+	struct fddi_addr alloc_addr ;	/* Allocation Address */
+} ;
+
+/*
+ * P1A : SBA Category
+ */
+#define	SWAP_SMT_P001A		"l"
+
+struct smt_p_001a {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long		category ;	/* Allocator defined classification */
+} ;
+
+/*
+ * P1B : Maximum T_Neg
+ */
+#define	SWAP_SMT_P001B		"l"
+
+struct smt_p_001b {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long		max_t_neg ;	/* longest T_NEG for the sync service*/
+} ;
+
+/*
+ * P1C : Minimum SBA Segment Size
+ */
+#define	SWAP_SMT_P001C		"l"
+
+struct smt_p_001c {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long		min_seg_siz ;	/* smallest number of bytes per frame*/
+} ;
+
+/*
+ * P1D : SBA Allocatable
+ */
+#define	SWAP_SMT_P001D		"l"
+
+struct smt_p_001d {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long		allocatable ;	/* total sync bw availabel for alloc */
+} ;
+
+/*
+ * P20 0B : frame status capabilities
+ * NOTE: not in swap table, is used by smt.c AND PMF table
+ */
+#define SMT_P_FSC	0x200b
+/* #define SWAP_SMT_P_FSC	"ssss" */
+
+struct smt_p_fsc {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	fsc_pad0 ;
+	u_short	fsc_mac_index ;		/* mac index 1 .. ff */
+	u_short	fsc_pad1 ;
+	u_short	fsc_value ;		/* FSC_TYPE[0-2] */
+} ;
+
+#define FSC_TYPE0	0		/* "normal" node (A/C handling) */
+#define FSC_TYPE1	1		/* Special A/C indicator forwarding */
+#define FSC_TYPE2	2		/* Special A/C indicator forwarding */
+
+/*
+ * P00 21 : user defined authoriziation (see pmf.c)
+ */
+#define SMT_P_AUTHOR	0x0021
+
+/*
+ * notification parameters
+ */
+#define SWAP_SMT_P1048	"ll"
+struct smt_p_1048 {
+	u_long p1048_flag ;
+	u_long p1048_cf_state ;
+} ;
+
+/*
+ * NOTE: all 2xxx 3xxx and 4xxx must include the INDEX in the swap string,
+ *	even so the INDEX is NOT part of the struct.
+ *	INDEX is already swapped in pmf.c, format in string is '4'
+ */
+#define SWAP_SMT_P208C	"4lss66"
+struct smt_p_208c {
+	u_long			p208c_flag ;
+	u_short			p208c_pad ;
+	u_short			p208c_dupcondition ;
+	struct	fddi_addr	p208c_fddilong ;
+	struct	fddi_addr	p208c_fddiunalong ;
+} ;
+
+#define SWAP_SMT_P208D	"4lllll"
+struct smt_p_208d {
+	u_long			p208d_flag ;
+	u_long			p208d_frame_ct ;
+	u_long			p208d_error_ct ;
+	u_long			p208d_lost_ct ;
+	u_long			p208d_ratio ;
+} ;
+
+#define SWAP_SMT_P208E	"4llll"
+struct smt_p_208e {
+	u_long			p208e_flag ;
+	u_long			p208e_not_copied ;
+	u_long			p208e_copied ;
+	u_long			p208e_not_copied_ratio ;
+} ;
+
+#define SWAP_SMT_P208F	"4ll6666s6"
+
+struct smt_p_208f {
+	u_long			p208f_multiple ;
+	u_long			p208f_nacondition ;
+	struct fddi_addr	p208f_old_una ;
+	struct fddi_addr	p208f_new_una ;
+	struct fddi_addr	p208f_old_dna ;
+	struct fddi_addr	p208f_new_dna ;
+	u_short			p208f_curren_path ;
+	struct fddi_addr	p208f_smt_address ;
+} ;
+
+#define SWAP_SMT_P2090	"4lssl"
+
+struct smt_p_2090 {
+	u_long			p2090_multiple ;
+	u_short			p2090_availablepaths ;
+	u_short			p2090_currentpath ;
+	u_long			p2090_requestedpaths ;
+} ;
+
+/*
+ * NOTE:
+ * special kludge for parameters 320b,320f,3210
+ * these parameters are part of RAF frames
+ * RAF frames are parsed in SBA.C and must be swapped
+ * PMF.C has special code to avoid double swapping
+ */
+#ifdef	LITTLE_ENDIAN
+#define SBAPATHINDEX	(0x01000000L)
+#else
+#define SBAPATHINDEX	(0x01L)
+#endif
+
+#define	SWAP_SMT_P320B	"42s"
+
+struct	smt_p_320b {
+	struct smt_para para ;	/* generic parameter header */
+	u_long	mib_index ;
+	u_short path_pad ;
+	u_short	path_index ;
+} ;
+
+#define	SWAP_SMT_P320F	"4l"
+
+struct	smt_p_320f {
+	struct smt_para para ;	/* generic parameter header */
+	u_long	mib_index ;
+	u_long	mib_payload ;
+} ;
+
+#define	SWAP_SMT_P3210	"4l"
+
+struct	smt_p_3210 {
+	struct smt_para para ;	/* generic parameter header */
+	u_long	mib_index ;
+	u_long	mib_overhead ;
+} ;
+
+#define SWAP_SMT_P4050	"4l1111ll"
+
+struct smt_p_4050 {
+	u_long			p4050_flag ;
+	u_char			p4050_pad ;
+	u_char			p4050_cutoff ;
+	u_char			p4050_alarm ;
+	u_char			p4050_estimate ;
+	u_long			p4050_reject_ct ;
+	u_long			p4050_ct ;
+} ;
+
+#define SWAP_SMT_P4051	"4lssss"
+struct smt_p_4051 {
+	u_long			p4051_multiple ;
+	u_short			p4051_porttype ;
+	u_short			p4051_connectstate ;
+	u_short			p4051_pc_neighbor ;
+	u_short			p4051_pc_withhold ;
+} ;
+
+#define SWAP_SMT_P4052	"4ll"
+struct smt_p_4052 {
+	u_long			p4052_flag ;
+	u_long			p4052_eberrorcount ;
+} ;
+
+#define SWAP_SMT_P4053	"4lsslss"
+
+struct smt_p_4053 {
+	u_long			p4053_multiple ;
+	u_short			p4053_availablepaths ;
+	u_short			p4053_currentpath ;
+	u_long			p4053_requestedpaths ;
+	u_short			p4053_mytype ;
+	u_short			p4053_neighbortype ;
+} ;
+
+
+#define SMT_P_SETCOUNT	0x1035
+#define SWAP_SMT_P_SETCOUNT	"l8"
+
+struct smt_p_setcount {
+	struct smt_para	para ;		/* generic parameter header */
+	u_long		count ;
+	u_char		timestamp[8] ;
+} ;
+
+/*
+ * SMT FRAMES
+ */
+
+/*
+ * NIF : neighbor information frames
+ */
+struct smt_nif {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_una	una ;		/* UNA */
+	struct smt_p_sde	sde ;		/* station descriptor */
+	struct smt_p_state	state ;		/* station state */
+#ifdef	SMT6_10
+	struct smt_p_fsc	fsc ;		/* frame status cap. */
+#endif
+} ;
+
+/*
+ * SIF : station information frames
+ */
+struct smt_sif_config {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_timestamp	ts ;		/* time stamp */
+	struct smt_p_sde	sde ;		/* station descriptor */
+	struct smt_p_version	version ;	/* supported versions */
+	struct smt_p_state	state ;		/* station state */
+	struct smt_p_policy	policy ;	/* station policy */
+	struct smt_p_latency	latency ;	/* path latency */
+	struct smt_p_neighbor	neighbor ;	/* neighbors, we have only one*/
+#ifdef	OPT_PMF
+	struct smt_p_setcount	setcount ;	 /* Set Count mandatory */
+#endif
+	/* WARNING : path MUST BE LAST FIELD !!! (see smt.c:smt_fill_path) */
+	struct smt_p_path	path ;		/* path descriptor */
+} ;
+#define SIZEOF_SMT_SIF_CONFIG	(sizeof(struct smt_sif_config)- \
+				 sizeof(struct smt_p_path))
+
+struct smt_sif_operation {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_timestamp	ts ;		/* time stamp */
+	struct smt_p_mac_status	status ;	/* mac status */
+	struct smt_p_mac_counter mc ;		/* MAC counter */
+	struct smt_p_mac_fnc 	fnc ;		/* MAC frame not copied */
+	struct smp_p_manufacturer man ;		/* manufacturer field */
+	struct smp_p_user	user ;		/* user field */
+#ifdef	OPT_PMF
+	struct smt_p_setcount	setcount ;	 /* Set Count mandatory */
+#endif
+	/* must be last */
+	struct smt_p_lem	lem[1] ;	/* phy lem status */
+} ;
+#define SIZEOF_SMT_SIF_OPERATION	(sizeof(struct smt_sif_operation)- \
+					 sizeof(struct smt_p_lem))
+
+/*
+ * ECF : echo frame
+ */
+struct smt_ecf {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_echo	ec_echo ;	/* echo parameter */
+} ;
+#define SMT_ECF_LEN	(sizeof(struct smt_header)+sizeof(struct smt_para))
+
+/*
+ * RDF : request denied frame
+ */
+struct smt_rdf {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_reason	reason ;	/* reason code */
+	struct smt_p_version	version ;	/* supported versions */
+	struct smt_p_refused	refused ;	/* refused frame fragment */
+} ;
+
+/*
+ * SBA Request Allocation Responce Frame
+ */
+struct smt_sba_alc_res {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_reason	reason ;	/* reason code */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+	struct smt_p_0019	a_addr ;	/* Allocation Address */
+	struct smt_p_001a	cat ;		/* Category - from the request */
+	struct smt_p_001d	alloc ;		/* SBA Allocatable */
+} ;
+
+/*
+ * SBA Request Allocation Request Frame
+ */
+struct smt_sba_alc_req {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_0017	pl_req ;	/* requested payload */
+	struct smt_p_0018	ov_req ;	/* requested SBA overhead */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+	struct smt_p_0019	a_addr ;	/* Allocation Address */
+	struct smt_p_001a	cat ;		/* Category - from the request */
+	struct smt_p_001b	tneg ;		/* max T-NEG */
+	struct smt_p_001c	segm ;		/* minimum segment size */
+} ;
+
+/*
+ * SBA Change Allocation Request Frame
+ */
+struct smt_sba_chg {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+	struct smt_p_001a	cat ;		/* Category - from the request */
+} ;
+
+/*
+ * SBA Report Allocation Request Frame
+ */
+struct smt_sba_rep_req {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+} ;
+
+/*
+ * SBA Report Allocation Response Frame
+ */
+struct smt_sba_rep_res {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+} ;
+
+/*
+ * actions
+ */
+#define SMT_STATION_ACTION	1
+#define SMT_STATION_ACTION_CONNECT	0
+#define SMT_STATION_ACTION_DISCONNECT	1
+#define SMT_STATION_ACTION_PATHTEST	2
+#define SMT_STATION_ACTION_SELFTEST	3
+#define SMT_STATION_ACTION_DISABLE_A	4
+#define SMT_STATION_ACTION_DISABLE_B	5
+#define SMT_STATION_ACTION_DISABLE_M	6
+
+#define SMT_PORT_ACTION		2
+#define SMT_PORT_ACTION_MAINT	0
+#define SMT_PORT_ACTION_ENABLE	1
+#define SMT_PORT_ACTION_DISABLE	2
+#define SMT_PORT_ACTION_START	3
+#define SMT_PORT_ACTION_STOP	4
+
+#endif	/* _SMT_ */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smt_p.h linux/drivers/net/skfp/h/smt_p.h
--- v2.3.46/linux/drivers/net/skfp/h/smt_p.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/smt_p.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,326 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * defines for all SMT attributes
+ */
+
+/*
+ * this boring file was produced by perl
+ * thanks Larry !
+ */
+#define	SMT_P0012	0x0012
+
+#define	SMT_P0015	0x0015
+#define	SMT_P0016	0x0016
+#define	SMT_P0017	0x0017
+#define	SMT_P0018	0x0018
+#define	SMT_P0019	0x0019
+
+#define	SMT_P001A	0x001a
+#define	SMT_P001B	0x001b
+#define	SMT_P001C	0x001c
+#define	SMT_P001D	0x001d
+
+#define	SMT_P100A	0x100a
+#define	SMT_P100B	0x100b
+#define	SMT_P100C	0x100c
+#define	SMT_P100D	0x100d
+#define	SMT_P100E	0x100e
+#define	SMT_P100F	0x100f
+#define	SMT_P1010	0x1010
+#define	SMT_P1011	0x1011
+#define	SMT_P1012	0x1012
+#define	SMT_P1013	0x1013
+#define	SMT_P1014	0x1014
+#define	SMT_P1015	0x1015
+#define	SMT_P1016	0x1016
+#define	SMT_P1017	0x1017
+#define	SMT_P1018	0x1018
+#define	SMT_P1019	0x1019
+#define	SMT_P101A	0x101a
+#define	SMT_P101B	0x101b
+#define	SMT_P101C	0x101c
+#define	SMT_P101D	0x101d
+#define	SMT_P101E	0x101e
+#define	SMT_P101F	0x101f
+#define	SMT_P1020	0x1020
+#define	SMT_P1021	0x1021
+#define	SMT_P1022	0x1022
+#define	SMT_P1023	0x1023
+#define	SMT_P1024	0x1024
+#define	SMT_P1025	0x1025
+#define	SMT_P1026	0x1026
+#define	SMT_P1027	0x1027
+#define	SMT_P1028	0x1028
+#define	SMT_P1029	0x1029
+#define	SMT_P102A	0x102a
+#define	SMT_P102B	0x102b
+#define	SMT_P102C	0x102c
+#define	SMT_P102D	0x102d
+#define	SMT_P102E	0x102e
+#define	SMT_P102F	0x102f
+#define	SMT_P1030	0x1030
+#define	SMT_P1031	0x1031
+#define	SMT_P1032	0x1032
+#define	SMT_P1033	0x1033
+#define	SMT_P1034	0x1034
+#define	SMT_P1035	0x1035
+#define	SMT_P1036	0x1036
+#define	SMT_P1037	0x1037
+#define	SMT_P1038	0x1038
+#define	SMT_P1039	0x1039
+#define	SMT_P103A	0x103a
+#define	SMT_P103B	0x103b
+#define	SMT_P103C	0x103c
+#define	SMT_P103D	0x103d
+#define	SMT_P103E	0x103e
+#define	SMT_P103F	0x103f
+#define	SMT_P1040	0x1040
+#define	SMT_P1041	0x1041
+#define	SMT_P1042	0x1042
+#define	SMT_P1043	0x1043
+#define	SMT_P1044	0x1044
+#define	SMT_P1045	0x1045
+#define	SMT_P1046	0x1046
+#define	SMT_P1047	0x1047
+#define	SMT_P1048	0x1048
+#define	SMT_P1049	0x1049
+#define	SMT_P104A	0x104a
+#define	SMT_P104B	0x104b
+#define	SMT_P104C	0x104c
+#define	SMT_P104D	0x104d
+#define	SMT_P104E	0x104e
+#define	SMT_P104F	0x104f
+#define	SMT_P1050	0x1050
+#define	SMT_P1051	0x1051
+#define	SMT_P1052	0x1052
+#define	SMT_P1053	0x1053
+#define	SMT_P1054	0x1054
+
+#define	SMT_P10F0	0x10f0
+#define	SMT_P10F1	0x10f1
+#ifdef	ESS
+#define	SMT_P10F2	0x10f2
+#define	SMT_P10F3	0x10f3
+#define	SMT_P10F4	0x10f4
+#define	SMT_P10F5	0x10f5
+#define	SMT_P10F6	0x10f6
+#define	SMT_P10F7	0x10f7
+#endif
+#ifdef	SBA
+#define	SMT_P10F8	0x10f8
+#define	SMT_P10F9	0x10f9
+#endif
+
+#define	SMT_P200A	0x200a
+#define	SMT_P200B	0x200b
+#define	SMT_P200C	0x200c
+#define	SMT_P200D	0x200d
+#define	SMT_P200E	0x200e
+#define	SMT_P200F	0x200f
+#define	SMT_P2010	0x2010
+#define	SMT_P2011	0x2011
+#define	SMT_P2012	0x2012
+#define	SMT_P2013	0x2013
+#define	SMT_P2014	0x2014
+#define	SMT_P2015	0x2015
+#define	SMT_P2016	0x2016
+#define	SMT_P2017	0x2017
+#define	SMT_P2018	0x2018
+#define	SMT_P2019	0x2019
+#define	SMT_P201A	0x201a
+#define	SMT_P201B	0x201b
+#define	SMT_P201C	0x201c
+#define	SMT_P201D	0x201d
+#define	SMT_P201E	0x201e
+#define	SMT_P201F	0x201f
+#define	SMT_P2020	0x2020
+#define	SMT_P2021	0x2021
+#define	SMT_P2022	0x2022
+#define	SMT_P2023	0x2023
+#define	SMT_P2024	0x2024
+#define	SMT_P2025	0x2025
+#define	SMT_P2026	0x2026
+#define	SMT_P2027	0x2027
+#define	SMT_P2028	0x2028
+#define	SMT_P2029	0x2029
+#define	SMT_P202A	0x202a
+#define	SMT_P202B	0x202b
+#define	SMT_P202C	0x202c
+#define	SMT_P202D	0x202d
+#define	SMT_P202E	0x202e
+#define	SMT_P202F	0x202f
+#define	SMT_P2030	0x2030
+#define	SMT_P2031	0x2031
+#define	SMT_P2032	0x2032
+#define	SMT_P2033	0x2033
+#define	SMT_P2034	0x2034
+#define	SMT_P2035	0x2035
+#define	SMT_P2036	0x2036
+#define	SMT_P2037	0x2037
+#define	SMT_P2038	0x2038
+#define	SMT_P2039	0x2039
+#define	SMT_P203A	0x203a
+#define	SMT_P203B	0x203b
+#define	SMT_P203C	0x203c
+#define	SMT_P203D	0x203d
+#define	SMT_P203E	0x203e
+#define	SMT_P203F	0x203f
+#define	SMT_P2040	0x2040
+#define	SMT_P2041	0x2041
+#define	SMT_P2042	0x2042
+#define	SMT_P2043	0x2043
+#define	SMT_P2044	0x2044
+#define	SMT_P2045	0x2045
+#define	SMT_P2046	0x2046
+#define	SMT_P2047	0x2047
+#define	SMT_P2048	0x2048
+#define	SMT_P2049	0x2049
+#define	SMT_P204A	0x204a
+#define	SMT_P204B	0x204b
+#define	SMT_P204C	0x204c
+#define	SMT_P204D	0x204d
+#define	SMT_P204E	0x204e
+#define	SMT_P204F	0x204f
+#define	SMT_P2050	0x2050
+#define	SMT_P2051	0x2051
+#define	SMT_P2052	0x2052
+#define	SMT_P2053	0x2053
+#define	SMT_P2054	0x2054
+#define	SMT_P2055	0x2055
+#define	SMT_P2056	0x2056
+#define	SMT_P2057	0x2057
+#define	SMT_P2058	0x2058
+#define	SMT_P2059	0x2059
+#define	SMT_P205A	0x205a
+#define	SMT_P205B	0x205b
+#define	SMT_P205C	0x205c
+#define	SMT_P205D	0x205d
+#define	SMT_P205E	0x205e
+#define	SMT_P205F	0x205f
+#define	SMT_P2060	0x2060
+#define	SMT_P2061	0x2061
+#define	SMT_P2062	0x2062
+#define	SMT_P2063	0x2063
+#define	SMT_P2064	0x2064
+#define	SMT_P2065	0x2065
+#define	SMT_P2066	0x2066
+#define	SMT_P2067	0x2067
+#define	SMT_P2068	0x2068
+#define	SMT_P2069	0x2069
+#define	SMT_P206A	0x206a
+#define	SMT_P206B	0x206b
+#define	SMT_P206C	0x206c
+#define	SMT_P206D	0x206d
+#define	SMT_P206E	0x206e
+#define	SMT_P206F	0x206f
+#define	SMT_P2070	0x2070
+#define	SMT_P2071	0x2071
+#define	SMT_P2072	0x2072
+#define	SMT_P2073	0x2073
+#define	SMT_P2074	0x2074
+#define	SMT_P2075	0x2075
+#define	SMT_P2076	0x2076
+
+#define	SMT_P208C	0x208c
+#define	SMT_P208D	0x208d
+#define	SMT_P208E	0x208e
+#define	SMT_P208F	0x208f
+#define	SMT_P2090	0x2090
+
+#define	SMT_P20F0	0x20F0
+#define	SMT_P20F1	0x20F1
+
+#define	SMT_P320A	0x320a
+#define	SMT_P320B	0x320b
+#define	SMT_P320C	0x320c
+#define	SMT_P320D	0x320d
+#define	SMT_P320E	0x320e
+#define	SMT_P320F	0x320f
+#define	SMT_P3210	0x3210
+#define	SMT_P3211	0x3211
+#define	SMT_P3212	0x3212
+#define	SMT_P3213	0x3213
+#define	SMT_P3214	0x3214
+#define	SMT_P3215	0x3215
+#define	SMT_P3216	0x3216
+#define	SMT_P3217	0x3217
+
+#define	SMT_P400A	0x400a
+#define	SMT_P400B	0x400b
+#define	SMT_P400C	0x400c
+#define	SMT_P400D	0x400d
+#define	SMT_P400E	0x400e
+#define	SMT_P400F	0x400f
+#define	SMT_P4010	0x4010
+#define	SMT_P4011	0x4011
+#define	SMT_P4012	0x4012
+#define	SMT_P4013	0x4013
+#define	SMT_P4014	0x4014
+#define	SMT_P4015	0x4015
+#define	SMT_P4016	0x4016
+#define	SMT_P4017	0x4017
+#define	SMT_P4018	0x4018
+#define	SMT_P4019	0x4019
+#define	SMT_P401A	0x401a
+#define	SMT_P401B	0x401b
+#define	SMT_P401C	0x401c
+#define	SMT_P401D	0x401d
+#define	SMT_P401E	0x401e
+#define	SMT_P401F	0x401f
+#define	SMT_P4020	0x4020
+#define	SMT_P4021	0x4021
+#define	SMT_P4022	0x4022
+#define	SMT_P4023	0x4023
+#define	SMT_P4024	0x4024
+#define	SMT_P4025	0x4025
+#define	SMT_P4026	0x4026
+#define	SMT_P4027	0x4027
+#define	SMT_P4028	0x4028
+#define	SMT_P4029	0x4029
+#define	SMT_P402A	0x402a
+#define	SMT_P402B	0x402b
+#define	SMT_P402C	0x402c
+#define	SMT_P402D	0x402d
+#define	SMT_P402E	0x402e
+#define	SMT_P402F	0x402f
+#define	SMT_P4030	0x4030
+#define	SMT_P4031	0x4031
+#define	SMT_P4032	0x4032
+#define	SMT_P4033	0x4033
+#define	SMT_P4034	0x4034
+#define	SMT_P4035	0x4035
+#define	SMT_P4036	0x4036
+#define	SMT_P4037	0x4037
+#define	SMT_P4038	0x4038
+#define	SMT_P4039	0x4039
+#define	SMT_P403A	0x403a
+#define	SMT_P403B	0x403b
+#define	SMT_P403C	0x403c
+#define	SMT_P403D	0x403d
+#define	SMT_P403E	0x403e
+#define	SMT_P403F	0x403f
+#define	SMT_P4040	0x4040
+#define	SMT_P4041	0x4041
+#define	SMT_P4042	0x4042
+#define	SMT_P4043	0x4043
+#define	SMT_P4044	0x4044
+#define	SMT_P4045	0x4045
+#define	SMT_P4046	0x4046
+
+#define	SMT_P4050	0x4050
+#define	SMT_P4051	0x4051
+#define	SMT_P4052	0x4052
+#define	SMT_P4053	0x4053
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smtstate.h linux/drivers/net/skfp/h/smtstate.h
--- v2.3.46/linux/drivers/net/skfp/h/smtstate.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/smtstate.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	SMT state definitions
+ */
+
+#ifndef	KERNEL
+/*
+ * PCM states
+ */
+#define PC0_OFF			0
+#define PC1_BREAK		1
+#define PC2_TRACE		2
+#define PC3_CONNECT		3
+#define PC4_NEXT		4
+#define PC5_SIGNAL		5
+#define PC6_JOIN		6
+#define PC7_VERIFY		7
+#define PC8_ACTIVE		8
+#define PC9_MAINT		9
+
+/*
+ * PCM modes
+ */
+#define PM_NONE			0
+#define PM_PEER			1
+#define PM_TREE			2
+
+/*
+ * PCM type
+ */
+#define TA			0
+#define TB			1
+#define TS			2
+#define TM			3
+#define TNONE			4
+
+/*
+ * CFM states
+ */
+#define SC0_ISOLATED	0		/* isolated */
+#define SC1_WRAP_A	5		/* wrap A */
+#define SC2_WRAP_B	6		/* wrap B */
+#define SC4_THRU_A	12		/* through A */
+#define SC5_THRU_B	7		/* through B (SMt 6.2) */
+#define SC7_WRAP_S	8		/* SAS */
+
+/*
+ * ECM states
+ */
+#define EC0_OUT		0
+#define EC1_IN		1
+#define EC2_TRACE	2
+#define EC3_LEAVE	3
+#define EC4_PATH_TEST	4
+#define EC5_INSERT	5
+#define EC6_CHECK	6
+#define EC7_DEINSERT	7
+
+/*
+ * RMT states
+ */
+#define RM0_ISOLATED	0
+#define RM1_NON_OP	1		/* not operational */
+#define RM2_RING_OP	2		/* ring operational */
+#define RM3_DETECT	3		/* detect dupl addresses */
+#define RM4_NON_OP_DUP	4		/* dupl. addr detected */
+#define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */
+#define RM6_DIRECTED	6		/* sending directed beacons */
+#define RM7_TRACE	7		/* trace initiated */
+#endif
+
+struct pcm_state {
+	unsigned char	pcm_type ;		/* TA TB TS TM */
+	unsigned char	pcm_state ;		/* state PC[0-9]_* */
+	unsigned char	pcm_mode ;		/* PM_{NONE,PEER,TREE} */
+	unsigned char	pcm_neighbor ;		/* TA TB TS TM */
+	unsigned char	pcm_bsf ;		/* flag bs : TRUE/FALSE */
+	unsigned char	pcm_lsf ;		/* flag ls : TRUE/FALSE */
+	unsigned char	pcm_lct_fail ;		/* counter lct_fail */
+	unsigned char	pcm_ls_rx ;		/* rx line state */
+	short		pcm_r_val ;		/* signaling bits */
+	short		pcm_t_val ;		/* signaling bits */
+} ;
+
+struct smt_state {
+	struct pcm_state pcm_state[NUMPHYS] ;	/* port A & port B */
+} ;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/supern_2.h linux/drivers/net/skfp/h/supern_2.h
--- v2.3.46/linux/drivers/net/skfp/h/supern_2.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/supern_2.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,1059 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	defines for AMD Supernet II chip set
+	the chips are refered to as
+		FPLUS	Formac Plus
+		PLC	Physical Layer
+
+	added defines for AMD Supernet III chip set
+	added comments on differences between Supernet II and Supernet III
+	added defines for the Motorola ELM (MOT_ELM)
+*/
+
+#ifndef	_SUPERNET_
+#define _SUPERNET_
+
+/*
+ * Define Supernet 3 when used
+ */
+#ifdef	PCI
+#ifndef	SUPERNET_3
+#define	SUPERNET_3
+#endif
+#define TAG
+#endif
+
+#define	MB	0xff
+#define	MW	0xffff
+#define	MD	0xffffffff
+
+/*
+ * FORMAC frame status (rx_msext)
+ */
+#define	FS_EI		(1<<2)
+#define	FS_AI		(1<<1)
+#define	FS_CI		(1<<0)
+
+#define FS_MSVALID	(1<<15)		/* end of queue */
+#define FS_MSRABT	(1<<14)		/* frame was aborted during reception*/
+#define FS_SSRCRTG	(1<<12)		/* if SA has set MSB (source-routing)*/
+#define FS_SEAC2	(FS_EI<<9)	/* error indicator */
+#define FS_SEAC1	(FS_AI<<9)	/* address indicator */
+#define FS_SEAC0	(FS_CI<<9)	/* copy indicator */
+#define FS_SFRMERR	(1<<8)		/* error detected (CRC or length) */
+#define FS_SADRRG	(1<<7)		/* address recognized */
+#define FS_SFRMTY2	(1<<6)		/* frame-class bit */
+#define FS_SFRMTY1	(1<<5)		/* frame-type bit (impementor) */
+#define FS_SFRMTY0	(1<<4)		/* frame-type bit (LLC) */
+#define FS_ERFBB1	(1<<1)		/* byte offset (depends on LSB bit) */
+#define FS_ERFBB0	(1<<0)		/*  - " - */
+
+/*
+ * status frame type
+ */
+#define	FRM_SMT		(0)	/* asynchr. frames */
+#define	FRM_LLCA	(1)
+#define	FRM_IMPA	(2)	
+#define	FRM_MAC		(4)	/* synchr. frames */
+#define	FRM_LLCS	(5)
+#define	FRM_IMPS	(6)
+
+/*
+ * bits in rx_descr.i	(receive frame status word)
+ */
+#define RX_MSVALID	((long)1<<31)	/* memory status valid */
+#define RX_MSRABT	((long)1<<30)	/* memory status receive abort */
+#define RX_FS_E		((long)FS_SEAC2<<16)	/* error indicator */
+#define RX_FS_A		((long)FS_SEAC1<<16)	/* address indicator */
+#define RX_FS_C		((long)FS_SEAC0<<16)	/* copy indicator */
+#define RX_FS_CRC	((long)FS_SFRMERR<<16)/* error detected */
+#define RX_FS_ADDRESS	((long)FS_SADRRG<<16)	/* address recognized */
+#define RX_FS_MAC	((long)FS_SFRMTY2<<16)/* MAC frame */
+#define RX_FS_SMT	((long)0<<16)		/* SMT frame */
+#define RX_FS_IMPL	((long)FS_SFRMTY1<<16)/* implementer frame */
+#define RX_FS_LLC	((long)FS_SFRMTY0<<16)/* LLC frame */
+
+/*
+ * receive frame descriptor
+ */
+union rx_descr {
+	struct {
+#ifdef	LITTLE_ENDIAN
+	unsigned	rx_length :16 ;	/* frame length lower/upper byte */
+	unsigned	rx_erfbb  :2 ;	/* received frame byte boundary */
+	unsigned	rx_reserv2:2 ;	/* reserved */	
+	unsigned	rx_sfrmty :3 ;	/* frame type bits */
+	unsigned	rx_sadrrg :1 ;	/* DA == MA or broad-/multicast */
+	unsigned	rx_sfrmerr:1 ;	/* received frame not valid */
+	unsigned	rx_seac0  :1 ;	/* frame-copied  C-indicator */
+	unsigned	rx_seac1  :1 ;	/* address-match A-indicator */
+	unsigned	rx_seac2  :1 ;	/* frame-error   E-indicator */
+	unsigned	rx_ssrcrtg:1 ;	/* == 1 SA has MSB set */
+	unsigned	rx_reserv1:1 ;	/* reserved */	
+	unsigned	rx_msrabt :1 ;	/* memory status receive abort */
+	unsigned	rx_msvalid:1 ;	/* memory status valid */
+#else
+	unsigned	rx_msvalid:1 ;	/* memory status valid */
+	unsigned	rx_msrabt :1 ;	/* memory status receive abort */
+	unsigned	rx_reserv1:1 ;	/* reserved */	
+	unsigned	rx_ssrcrtg:1 ;	/* == 1 SA has MSB set */
+	unsigned	rx_seac2  :1 ;	/* frame-error   E-indicator */
+	unsigned	rx_seac1  :1 ;	/* address-match A-indicator */
+	unsigned	rx_seac0  :1 ;	/* frame-copied  C-indicator */
+	unsigned	rx_sfrmerr:1 ;	/* received frame not valid */
+	unsigned	rx_sadrrg :1 ;	/* DA == MA or broad-/multicast */
+	unsigned	rx_sfrmty :3 ;	/* frame type bits */
+	unsigned	rx_erfbb  :2 ;	/* received frame byte boundary */
+	unsigned	rx_reserv2:2 ;	/* reserved */	
+	unsigned	rx_length :16 ;	/* frame length lower/upper byte */
+#endif
+	} r ;
+	long	i ;
+} ;
+
+/* defines for Receive Frame Descriptor access */
+#define RD_S_ERFBB	0x00030000L	/* received frame byte boundary */
+#define RD_S_RES2	0x000c0000L	/* reserved */
+#define RD_S_SFRMTY	0x00700000L	/* frame type bits */
+#define RD_S_SADRRG	0x00800000L	/* DA == MA or broad-/multicast */
+#define RD_S_SFRMERR	0x01000000L	/* received frame not valid */
+#define	RD_S_SEAC	0x0e000000L	/* frame status indicators */
+#define RD_S_SEAC0	0x02000000L	/* frame-copied  case-indicator */
+#define RD_S_SEAC1	0x04000000L	/* address-match A-indicator */
+#define RD_S_SEAC2	0x08000000L	/* frame-error   E-indicator */
+#define RD_S_SSRCRTG	0x10000000L	/* == 1 SA has MSB set */
+#define RD_S_RES1	0x20000000L	/* reserved */
+#define RD_S_MSRABT	0x40000000L	/* memory status receive abort */
+#define RD_S_MSVALID	0x80000000L	/* memory status valid */
+
+#define	RD_STATUS	0xffff0000L
+#define	RD_LENGTH	0x0000ffffL
+
+/* defines for Receive Frames Status Word values */
+/*RD_S_SFRMTY*/
+#define RD_FRM_SMT	(unsigned long)(0<<20)     /* asynchr. frames */
+#define RD_FRM_LLCA	(unsigned long)(1<<20)
+#define RD_FRM_IMPA	(unsigned long)(2<<20)
+#define RD_FRM_MAC	(unsigned long)(4<<20)     /* synchr. frames */
+#define RD_FRM_LLCS	(unsigned long)(5<<20)
+#define RD_FRM_IMPS	(unsigned long)(6<<20)
+
+#define TX_DESCRIPTOR	0x40000000L
+#define TX_OFFSET_3	0x18000000L
+
+#define TXP1	2
+
+/*
+ * transmit frame descriptor
+ */
+union tx_descr {
+	struct {
+#ifdef	LITTLE_ENDIAN
+	unsigned	tx_length:16 ;	/* frame length lower/upper byte */
+	unsigned	tx_res	 :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tx_xmtabt:1 ;	/* transmit abort */
+	unsigned	tx_nfcs  :1 ;	/* no frame check sequence */
+	unsigned	tx_xdone :1 ;	/* give up token */
+	unsigned	tx_rpxm  :2 ;	/* byte offset */
+	unsigned	tx_pat1  :2 ;	/* must be TXP1 */
+	unsigned	tx_more	 :1 ;	/* more frame in chain */
+#else
+	unsigned	tx_more	 :1 ;	/* more frame in chain */
+	unsigned	tx_pat1  :2 ;	/* must be TXP1 */
+	unsigned	tx_rpxm  :2 ;	/* byte offset */
+	unsigned	tx_xdone :1 ;	/* give up token */
+	unsigned	tx_nfcs  :1 ;	/* no frame check sequence */
+	unsigned	tx_xmtabt:1 ;	/* transmit abort */
+	unsigned	tx_res	 :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tx_length:16 ;	/* frame length lower/upper byte */
+#endif
+	} t ;
+	long	i ;
+} ;
+
+/* defines for Transmit Descriptor access */
+#define	TD_C_MORE	0x80000000L	/* more frame in chain */
+#define	TD_C_DESCR	0x60000000L	/* must be TXP1 */
+#define	TD_C_TXFBB	0x18000000L	/* byte offset */
+#define	TD_C_XDONE	0x04000000L	/* give up token */
+#define TD_C_NFCS	0x02000000L	/* no frame check sequence */
+#define TD_C_XMTABT	0x01000000L	/* transmit abort */
+
+#define	TD_C_LNCNU	0x0000ff00L	
+#define TD_C_LNCNL	0x000000ffL
+#define TD_C_LNCN	0x0000ffffL	/* frame length lower/upper byte */
+ 
+/*
+ * transmit pointer
+ */
+union tx_pointer {
+	struct t {
+#ifdef	LITTLE_ENDIAN
+	unsigned	tp_pointer:16 ;	/* pointer to tx_descr (low/high) */
+	unsigned	tp_res	  :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tp_pattern:8 ;	/* fixed pattern (bit 24..31) */
+#else
+	unsigned	tp_pattern:8 ;	/* fixed pattern (bit 24..31) */
+	unsigned	tp_res	  :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tp_pointer:16 ;	/* pointer to tx_descr (low/high) */
+#endif
+	} t ;
+	long	i ;
+} ;
+
+/* defines for Nontag Mode Pointer access */
+#define	TD_P_CNTRL	0xff000000L
+#define TD_P_RPXU	0x0000ff00L
+#define TD_P_RPXL	0x000000ffL
+#define TD_P_RPX	0x0000ffffL
+
+
+#define TX_PATTERN	0xa0
+#define TX_POINTER_END	0xa0000000L
+#define TX_INT_PATTERN	0xa0000000L
+
+struct tx_queue {
+	struct tx_queue *tq_next ;
+	u_short tq_pack_offset ;	/* offset buffer memory */
+	u_char  tq_pad[2] ;
+} ;
+
+/*
+	defines for FORMAC Plus (Am79C830)
+*/
+
+/*
+ *  FORMAC+ read/write (r/w) registers
+ */
+#define FM_CMDREG1	0x00		/* write command reg 1 instruction */
+#define FM_CMDREG2	0x01		/* write command reg 2 instruction */
+#define FM_ST1U		0x00		/* read upper 16-bit of status reg 1 */
+#define FM_ST1L		0x01		/* read lower 16-bit of status reg 1 */
+#define FM_ST2U		0x02		/* read upper 16-bit of status reg 2 */
+#define FM_ST2L		0x03		/* read lower 16-bit of status reg 2 */
+#define FM_IMSK1U	0x04		/* r/w upper 16-bit of IMSK 1 */
+#define FM_IMSK1L	0x05		/* r/w lower 16-bit of IMSK 1 */
+#define FM_IMSK2U	0x06		/* r/w upper 16-bit of IMSK 2 */
+#define FM_IMSK2L	0x07		/* r/w lower 16-bit of IMSK 2 */
+#define FM_SAID		0x08		/* r/w short addr.-individual */
+#define FM_LAIM		0x09		/* r/w long addr.-ind. (MSW of LAID) */
+#define FM_LAIC		0x0a		/* r/w long addr.-ind. (middle)*/
+#define FM_LAIL		0x0b		/* r/w long addr.-ind. (LSW) */
+#define FM_SAGP		0x0c		/* r/w short address-group */
+#define FM_LAGM		0x0d		/* r/w long addr.-gr. (MSW of LAGP) */
+#define FM_LAGC		0x0e		/* r/w long addr.-gr. (middle) */
+#define FM_LAGL		0x0f		/* r/w long addr.-gr. (LSW) */
+#define FM_MDREG1	0x10		/* r/w 16-bit mode reg 1 */
+#define FM_STMCHN	0x11		/* read state-machine reg */
+#define FM_MIR1		0x12		/* read upper 16-bit of MAC Info Reg */
+#define FM_MIR0		0x13		/* read lower 16-bit of MAC Info Reg */
+#define FM_TMAX		0x14		/* r/w 16-bit TMAX reg */
+#define FM_TVX		0x15		/* write 8-bit TVX reg with NP7-0
+					   read TVX on NP7-0, timer on NP15-8*/
+#define FM_TRT		0x16		/* r/w upper 16-bit of TRT timer */
+#define FM_THT		0x17		/* r/w upper 16-bit of THT timer */
+#define FM_TNEG		0x18		/* read upper 16-bit of TNEG (TTRT) */
+#define FM_TMRS		0x19		/* read lower 5-bit of TNEG,TRT,THT */
+			/* F E D C  B A 9 8  7 6 5 4  3 2 1 0
+			   x |-TNEG4-0| |-TRT4-0-| |-THT4-0-| (x-late count) */
+#define FM_TREQ0	0x1a		/* r/w 16-bit TREQ0 reg (LSW of TRT) */
+#define FM_TREQ1	0x1b		/* r/w 16-bit TREQ1 reg (MSW of TRT) */
+#define FM_PRI0		0x1c		/* r/w priority r. for asyn.-queue 0 */
+#define FM_PRI1		0x1d		/* r/w priority r. for asyn.-queue 1 */
+#define FM_PRI2		0x1e		/* r/w priority r. for asyn.-queue 2 */
+#define FM_TSYNC	0x1f		/* r/w 16-bit of the TSYNC register */
+#define FM_MDREG2	0x20		/* r/w 16-bit mode reg 2 */
+#define FM_FRMTHR	0x21		/* r/w the frame threshold register */
+#define FM_EACB		0x22		/* r/w end addr of claim/beacon area */
+#define FM_EARV		0x23		/* r/w end addr of receive queue */
+/* Supernet 3 */
+#define	FM_EARV1	FM_EARV
+
+#define FM_EAS		0x24		/* r/w end addr of synchr. queue */
+#define FM_EAA0		0x25		/* r/w end addr of asyn. queue 0 */
+#define FM_EAA1		0x26		/* r/w end addr of asyn. queue 1 */
+#define FM_EAA2		0x27		/* r/w end addr of asyn. queue 2 */
+#define FM_SACL		0x28		/* r/w start addr of claim frame */
+#define FM_SABC		0x29		/* r/w start addr of beacon frame */
+#define FM_WPXSF	0x2a		/* r/w the write ptr. for special fr.*/
+#define FM_RPXSF	0x2b		/* r/w the read ptr. for special fr. */
+#define FM_RPR		0x2d		/* r/w the read ptr. for receive qu. */
+#define FM_WPR		0x2e		/* r/w the write ptr. for receive qu.*/
+#define FM_SWPR		0x2f		/* r/w the shadow wr.-ptr. for rec.q.*/
+/* Supernet 3 */ 
+#define FM_RPR1         FM_RPR   
+#define FM_WPR1         FM_WPR 
+#define FM_SWPR1        FM_SWPR
+
+#define FM_WPXS		0x30		/* r/w the write ptr. for synchr. qu.*/
+#define FM_WPXA0	0x31		/* r/w the write ptr. for asyn. qu.0 */
+#define FM_WPXA1	0x32		/* r/w the write ptr. for asyn. qu.1 */
+#define FM_WPXA2	0x33		/* r/w the write ptr. for asyn. qu.2 */
+#define FM_SWPXS	0x34		/* r/w the shadow wr.-ptr. for syn.q.*/
+#define FM_SWPXA0	0x35		/* r/w the shad. wr.-ptr. for asyn.q0*/
+#define FM_SWPXA1	0x36		/* r/w the shad. wr.-ptr. for asyn.q1*/
+#define FM_SWPXA2	0x37		/* r/w the shad. wr.-ptr. for asyn.q2*/
+#define FM_RPXS		0x38		/* r/w the read ptr. for synchr. qu. */
+#define FM_RPXA0	0x39		/* r/w the read ptr. for asyn. qu. 0 */
+#define FM_RPXA1	0x3a		/* r/w the read ptr. for asyn. qu. 1 */
+#define FM_RPXA2	0x3b		/* r/w the read ptr. for asyn. qu. 2 */
+#define FM_MARR		0x3c		/* r/w the memory read addr register */
+#define FM_MARW		0x3d		/* r/w the memory write addr register*/
+#define FM_MDRU		0x3e		/* r/w upper 16-bit of mem. data reg */
+#define FM_MDRL		0x3f		/* r/w lower 16-bit of mem. data reg */
+
+/* following instructions relate to MAC counters and timer */
+#define FM_TMSYNC	0x40		/* r/w upper 16 bits of TMSYNC timer */
+#define FM_FCNTR	0x41		/* r/w the 16-bit frame counter */
+#define FM_LCNTR	0x42		/* r/w the 16-bit lost counter */
+#define FM_ECNTR	0x43		/* r/w the 16-bit error counter */
+
+/* Supernet 3:	extensions to old register block */
+#define	FM_FSCNTR	0x44		/* r/? Frame Strip Counter */
+#define	FM_FRSELREG	0x45		/* r/w Frame Selection Register */
+
+/* Supernet 3:	extensions for 2. receive queue etc. */
+#define	FM_MDREG3	0x60		/* r/w Mode Register 3 */
+#define	FM_ST3U		0x61		/* read upper 16-bit of status reg 3 */
+#define	FM_ST3L		0x62		/* read lower 16-bit of status reg 3 */
+#define	FM_IMSK3U	0x63		/* r/w upper 16-bit of IMSK reg 3 */
+#define	FM_IMSK3L	0x64		/* r/w lower 16-bit of IMSK reg 3 */
+#define	FM_IVR		0x65		/* read Interrupt Vector register */
+#define	FM_IMR		0x66		/* r/w Interrupt mask register */
+/* 0x67	Hidden */
+#define	FM_RPR2		0x68		/* r/w the read ptr. for rec. qu. 2 */
+#define	FM_WPR2		0x69		/* r/w the write ptr. for rec. qu. 2 */
+#define	FM_SWPR2	0x6a		/* r/w the shadow wptr. for rec. q. 2 */
+#define	FM_EARV2	0x6b		/* r/w end addr of rec. qu. 2 */
+#define	FM_UNLCKDLY	0x6c		/* r/w Auto Unlock Delay register */
+					/* Bit 15-8: RECV2 unlock threshold */
+					/* Bit  7-0: RECV1 unlock threshold */
+/* 0x6f-0x73	Hidden */
+#define	FM_LTDPA1	0x79		/* r/w Last Trans desc ptr for A1 qu. */
+/* 0x80-0x9a	PLCS registers of built-in PLCS  (Supernet 3 only) */
+
+/* Supernet 3: Adderss Filter Registers */
+#define	FM_AFCMD	0xb0		/* r/w Address Filter Command Reg */
+#define	FM_AFSTAT	0xb2		/* r/w Address Filter Status Reg */
+#define	FM_AFBIST	0xb4		/* r/w Address Filter BIST signature */
+#define	FM_AFCOMP2	0xb6		/* r/w Address Filter Comparand 2 */
+#define	FM_AFCOMP1	0xb8		/* r/w Address Filter Comparand 1 */
+#define	FM_AFCOMP0	0xba		/* r/w Address Filter Comparand 0 */
+#define	FM_AFMASK2	0xbc		/* r/w Address Filter Mask 2 */
+#define	FM_AFMASK1	0xbe		/* r/w Address Filter Mask 1 */
+#define	FM_AFMASK0	0xc0		/* r/w Address Filter Mask 0 */
+#define	FM_AFPERS	0xc2		/* r/w Address Filter Personality Reg */
+
+/* Supernet 3: Orion (PDX?) Registers */
+#define	FM_ORBIST	0xd0		/* r/w Orion BIST signature */
+#define	FM_ORSTAT	0xd2		/* r/w Orion Status Register */
+
+
+/*
+ * Mode Register 1 (MDREG1)
+ */
+#define FM_RES0		0x0001		/* reserved */
+					/* SN3: other definition */
+#define	FM_XMTINH_HOLD	0x0002		/* transmit-inhibit/hold bit */
+					/* SN3: other definition */
+#define	FM_HOFLXI	0x0003		/* SN3: Hold / Flush / Inhibit */
+#define	FM_FULL_HALF	0x0004		/* full-duplex/half-duplex bit */
+#define	FM_LOCKTX	0x0008		/* lock-transmit-asynchr.-queues bit */
+#define FM_EXGPA0	0x0010		/* extended-group-addressing bit 0 */
+#define FM_EXGPA1	0x0020		/* extended-group-addressing bit 1 */
+#define FM_DISCRY	0x0040		/* disable-carry bit */
+					/* SN3: reserved */
+#define FM_SELRA	0x0080		/* select input from PHY (1=RA,0=RB) */
+
+#define FM_ADDET	0x0700		/* address detection */
+#define FM_MDAMA	(0<<8)		/* address detection : DA = MA */
+#define FM_MDASAMA	(1<<8)		/* address detection : DA=MA||SA=MA */
+#define	FM_MRNNSAFNMA	(2<<8)		/* rec. non-NSA frames DA=MA&&SA!=MA */
+#define	FM_MRNNSAF	(3<<8)		/* rec. non-NSA frames DA = MA */
+#define	FM_MDISRCV	(4<<8)		/* disable receive function */
+#define	FM_MRES0	(5<<8)		/* reserve */
+#define	FM_MLIMPROM	(6<<8)		/* limited-promiscuous mode */
+#define FM_MPROMISCOUS	(7<<8)		/* address detection : promiscous */
+
+#define FM_SELSA	0x0800		/* select-short-address bit */
+
+#define FM_MMODE	0x7000		/* mode select */
+#define FM_MINIT	(0<<12)		/* initialize */
+#define FM_MMEMACT	(1<<12)		/* memory activate */
+#define FM_MONLINESP	(2<<12)		/* on-line special */
+#define FM_MONLINE	(3<<12)		/* on-line (FDDI operational mode) */
+#define FM_MILOOP	(4<<12)		/* internal loopback */
+#define FM_MRES1	(5<<12)		/* reserved */
+#define FM_MRES2	(6<<12)		/* reserved */
+#define FM_MELOOP	(7<<12)		/* external loopback */
+
+#define	FM_SNGLFRM	0x8000		/* single-frame-receive mode */
+					/* SN3: reserved */
+
+#define	MDR1INIT	(FM_MINIT | FM_MDAMA)
+
+/*
+ * Mode Register 2 (MDREG2)
+ */
+#define	FM_AFULL	0x000f		/* 4-bit value (empty loc.in txqueue)*/
+#define	FM_RCVERR	0x0010		/* rec.-errored-frames bit */
+#define	FM_SYMCTL	0x0020		/* sysmbol-control bit */
+					/* SN3: reserved */
+#define	FM_SYNPRQ	0x0040		/* synchron.-NP-DMA-request bit */
+#define	FM_ENNPRQ	0x0080		/* enable-NP-DMA-request bit */
+#define	FM_ENHSRQ	0x0100		/* enable-host-request bit */
+#define	FM_RXFBB01	0x0600		/* rec. frame byte boundary bit0 & 1 */
+#define	FM_LSB		0x0800		/* determ. ordering of bytes in buffer*/
+#define	FM_PARITY	0x1000		/* 1 = even, 0 = odd */
+#define	FM_CHKPAR	0x2000		/* 1 = parity of 32-bit buffer BD-bus*/
+#define	FM_STRPFCS	0x4000		/* 1 = strips FCS field of rec.frame */
+#define	FM_BMMODE	0x8000		/* Buffer-Memory-Mode (1 = tag mode) */
+					/* SN3: 1 = tag, 0 = modified tag */
+
+/*
+ * Status Register 1, Upper 16 Bits (ST1U)
+ */
+#define FM_STEFRMS	0x0001		/* transmit end of frame: synchr. qu.*/
+#define FM_STEFRMA0	0x0002		/* transmit end of frame: asyn. qu.0 */
+#define FM_STEFRMA1	0x0004		/* transmit end of frame: asyn. qu.1 */
+#define FM_STEFRMA2	0x0008		/* transmit end of frame: asyn. qu.2 */
+					/* SN3: reserved */
+#define FM_STECFRMS	0x0010		/* transmit end of chain of syn. qu. */
+					/* SN3: reserved */
+#define FM_STECFRMA0	0x0020		/* transmit end of chain of asyn. q0 */
+					/* SN3: reserved */
+#define FM_STECFRMA1	0x0040		/* transmit end of chain of asyn. q1 */
+					/* SN3: STECMDA1 */
+#define FM_STECMDA1	0x0040		/* SN3: 'no description' */
+#define FM_STECFRMA2	0x0080		/* transmit end of chain of asyn. q2 */
+					/* SN3: reserved */
+#define	FM_STEXDONS	0x0100		/* transmit until XDONE in syn. qu. */
+#define	FM_STBFLA	0x0200		/* asynchr.-queue trans. buffer full */
+#define	FM_STBFLS	0x0400		/* synchr.-queue transm. buffer full */
+#define	FM_STXABRS	0x0800		/* synchr. queue transmit-abort */
+#define	FM_STXABRA0	0x1000		/* asynchr. queue 0 transmit-abort */
+#define	FM_STXABRA1	0x2000		/* asynchr. queue 1 transmit-abort */
+#define	FM_STXABRA2	0x4000		/* asynchr. queue 2 transmit-abort */
+					/* SN3: reserved */
+#define	FM_SXMTABT	0x8000		/* transmit abort */
+
+/*
+ * Status Register 1, Lower 16 Bits (ST1L)
+ */
+#define FM_SQLCKS	0x0001		/* queue lock for synchr. queue */
+#define FM_SQLCKA0	0x0002		/* queue lock for asynchr. queue 0 */
+#define FM_SQLCKA1	0x0004		/* queue lock for asynchr. queue 1 */
+#define FM_SQLCKA2	0x0008		/* queue lock for asynchr. queue 2 */
+					/* SN3: reserved */
+#define FM_STXINFLS	0x0010		/* transmit instruction full: syn. */
+					/* SN3: reserved */
+#define FM_STXINFLA0	0x0020		/* transmit instruction full: asyn.0 */
+					/* SN3: reserved */
+#define FM_STXINFLA1	0x0040		/* transmit instruction full: asyn.1 */
+					/* SN3: reserved */
+#define FM_STXINFLA2	0x0080		/* transmit instruction full: asyn.2 */
+					/* SN3: reserved */
+#define FM_SPCEPDS	0x0100		/* parity/coding error: syn. queue */
+#define FM_SPCEPDA0	0x0200		/* parity/coding error: asyn. queue0 */
+#define FM_SPCEPDA1	0x0400		/* parity/coding error: asyn. queue1 */
+#define FM_SPCEPDA2	0x0800		/* parity/coding error: asyn. queue2 */
+					/* SN3: reserved */
+#define FM_STBURS	0x1000		/* transmit buffer underrun: syn. q. */
+#define FM_STBURA0	0x2000		/* transmit buffer underrun: asyn.0 */
+#define FM_STBURA1	0x4000		/* transmit buffer underrun: asyn.1 */
+#define FM_STBURA2	0x8000		/* transmit buffer underrun: asyn.2 */
+					/* SN3: reserved */
+
+/*
+ * Status Register 2, Upper 16 Bits (ST2U)
+ */
+#define FM_SOTRBEC	0x0001		/* other beacon received */
+#define FM_SMYBEC	0x0002		/* my beacon received */
+#define FM_SBEC		0x0004		/* beacon state entered */
+#define FM_SLOCLM	0x0008		/* low claim received */
+#define FM_SHICLM	0x0010		/* high claim received */
+#define FM_SMYCLM	0x0020		/* my claim received */
+#define FM_SCLM		0x0040		/* claim state entered */
+#define FM_SERRSF	0x0080		/* error in special frame */
+#define FM_SNFSLD	0x0100		/* NP and FORMAC+ simultaneous load */
+#define FM_SRFRCTOV	0x0200		/* receive frame counter overflow */
+					/* SN3: reserved */
+#define FM_SRCVFRM	0x0400		/* receive frame */
+					/* SN3: reserved */
+#define FM_SRCVOVR	0x0800		/* receive FIFO overflow */
+#define FM_SRBFL	0x1000		/* receive buffer full */
+#define FM_SRABT	0x2000		/* receive abort */
+#define FM_SRBMT	0x4000		/* receive buffer empty */
+#define FM_SRCOMP	0x8000		/* receive complete. Nontag mode */
+
+/*
+ * Status Register 2, Lower 16 Bits (ST2L)
+ * Attention: SN3 docu shows these bits the other way around
+ */
+#define FM_SRES0	0x0001		/* reserved */
+#define FM_SESTRIPTK	0x0001		/* SN3: 'no description' */
+#define FM_STRTEXR	0x0002		/* TRT expired in claim | beacon st. */
+#define FM_SDUPCLM	0x0004		/* duplicate claim received */
+#define FM_SSIFG	0x0008		/* short interframe gap */
+#define FM_SFRMCTR	0x0010		/* frame counter overflow */
+#define FM_SERRCTR	0x0020		/* error counter overflow */
+#define FM_SLSTCTR	0x0040		/* lost counter overflow */
+#define FM_SPHINV	0x0080		/* PHY invalid */
+#define FM_SADET	0x0100		/* address detect */
+#define FM_SMISFRM	0x0200		/* missed frame */
+#define FM_STRTEXP	0x0400		/* TRT expired and late count > 0 */
+#define FM_STVXEXP	0x0800		/* TVX expired */
+#define FM_STKISS	0x1000		/* token issued */
+#define FM_STKERR	0x2000		/* token error */
+#define FM_SMULTDA	0x4000		/* multiple destination address */
+#define FM_SRNGOP	0x8000		/* ring operational */
+
+/*
+ * Supernet 3:
+ * Status Register 3, Upper 16 Bits (ST3U)
+ */
+#define	FM_SRQUNLCK1	0x0001		/* receive queue unlocked queue 1 */
+#define	FM_SRQUNLCK2	0x0002		/* receive queue unlocked queue 2 */
+#define	FM_SRPERRQ1	0x0004		/* receive parity error rx queue 1 */
+#define	FM_SRPERRQ2	0x0008		/* receive parity error rx queue 2 */
+					/* Bit 4-10: reserved */
+#define	FM_SRCVOVR2	0x0800		/* receive FIFO overfull rx queue 2 */
+#define	FM_SRBFL2	0x1000		/* receive buffer full rx queue 2 */
+#define	FM_SRABT2	0x2000		/* receive abort rx queue 2 */
+#define	FM_SRBMT2	0x4000		/* receive buf empty rx queue 2 */
+#define	FM_SRCOMP2	0x8000		/* receive comp rx queue 2 */
+
+/*
+ * Supernet 3:
+ * Status Register 3, Lower 16 Bits (ST3L)
+ */
+#define	FM_AF_BIST_DONE		0x0001	/* Address Filter BIST is done */
+#define	FM_PLC_BIST_DONE	0x0002	/* internal PLC Bist is done */
+#define	FM_PDX_BIST_DONE	0x0004	/* PDX BIST is done */
+					/* Bit  3: reserved */
+#define	FM_SICAMDAMAT		0x0010	/* Status internal CAM DA match */
+#define	FM_SICAMDAXACT		0x0020	/* Status internal CAM DA exact match */
+#define	FM_SICAMSAMAT		0x0040	/* Status internal CAM SA match */
+#define	FM_SICAMSAXACT		0x0080	/* Status internal CAM SA exact match */
+
+/*
+ * MAC State-Machine Register FM_STMCHN
+ */
+#define	FM_MDRTAG	0x0004		/* tag bit of long word read */
+#define	FM_SNPPND	0x0008		/* r/w from buffer mem. is pending */
+#define	FM_TXSTAT	0x0070		/* transmitter state machine state */
+#define	FM_RCSTAT	0x0380		/* receiver state machine state */
+#define	FM_TM01		0x0c00		/* indicate token mode */
+#define	FM_SIM		0x1000		/* indicate send immediate-mode */
+#define	FM_REV		0xe000		/* FORMAC Plus revision number */
+
+/*
+ * Supernet 3
+ * Mode Register 3
+ */
+#define	FM_MENRS	0x0001		/* Ena enhanced rec status encoding */
+#define	FM_MENXS	0x0002		/* Ena enhanced xmit status encoding */
+#define	FM_MENXCT	0x0004		/* Ena EXACT/INEXACT matching */
+#define	FM_MENAFULL	0x0008		/* Ena enh QCTRL encoding for AFULL */
+#define	FM_MEIND	0x0030		/* Ena enh A,C indicator settings */
+#define	FM_MENQCTRL	0x0040		/* Ena enh QCTRL encoding */
+#define	FM_MENRQAUNLCK	0x0080		/* Ena rec q auto unlock */
+#define	FM_MENDAS	0x0100		/* Ena DAS connections by cntr MUX */
+#define	FM_MENPLCCST	0x0200		/* Ena Counter Segm test in PLC blck */
+#define	FM_MENSGLINT	0x0400		/* Ena Vectored Interrupt reading */
+#define	FM_MENDRCV	0x0800		/* Ena dual receive queue operation */
+#define	FM_MENFCLOC	0x3000		/* Ena FC location within frm data */
+#define	FM_MENTRCMD	0x4000		/* Ena ASYNC1 xmit only after command */
+#define	FM_MENTDLPBK	0x8000		/* Ena TDAT to RDAT lkoopback */
+
+/*
+ * Supernet 3
+ * Frame Selection Register
+ */
+#define	FM_RECV1	0x000f		/* options for receive queue 1 */
+#define	FM_RCV1_ALL	(0<<0)		/* receive all frames */
+#define	FM_RCV1_LLC	(1<<0)		/* rec all LLC frames */
+#define	FM_RCV1_SMT	(2<<0)		/* rec all SMT frames */
+#define	FM_RCV1_NSMT	(3<<0)		/* rec non-SMT frames */
+#define	FM_RCV1_IMP	(4<<0)		/* rec Implementor frames */
+#define	FM_RCV1_MAC	(5<<0)		/* rec all MAC frames */
+#define	FM_RCV1_SLLC	(6<<0)		/* rec all sync LLC frames */
+#define	FM_RCV1_ALLC	(7<<0)		/* rec all async LLC frames */
+#define	FM_RCV1_VOID	(8<<0)		/* rec all void frames */
+#define	FM_RCV1_ALSMT	(9<<0)		/* rec all async LLC & SMT frames */
+#define	FM_RECV2	0x00f0		/* options for receive queue 2 */
+#define	FM_RCV2_ALL	(0<<4)		/* receive all other frames */
+#define	FM_RCV2_LLC	(1<<4)		/* rec all LLC frames */
+#define	FM_RCV2_SMT	(2<<4)		/* rec all SMT frames */
+#define	FM_RCV2_NSMT	(3<<4)		/* rec non-SMT frames */
+#define	FM_RCV2_IMP	(4<<4)		/* rec Implementor frames */
+#define	FM_RCV2_MAC	(5<<4)		/* rec all MAC frames */
+#define	FM_RCV2_SLLC	(6<<4)		/* rec all sync LLC frames */
+#define	FM_RCV2_ALLC	(7<<4)		/* rec all async LLC frames */
+#define	FM_RCV2_VOID	(8<<4)		/* rec all void frames */
+#define	FM_RCV2_ALSMT	(9<<4)		/* rec all async LLC & SMT frames */
+#define	FM_ENXMTADSWAP	0x4000		/* enh rec addr swap (phys -> can) */
+#define	FM_ENRCVADSWAP	0x8000		/* enh tx addr swap (can -> phys) */
+
+/*
+ * Supernet 3:
+ * Address Filter Command Register (AFCMD)
+ */
+#define	FM_INST		0x0007		/* Address Filter Operation */
+#define FM_IINV_CAM	(0<<0)		/* Invalidate CAM */
+#define FM_IWRITE_CAM	(1<<0)		/* Write CAM */
+#define FM_IREAD_CAM	(2<<0)		/* Read CAM */
+#define FM_IRUN_BIST	(3<<0)		/* Run BIST */
+#define FM_IFIND	(4<<0)		/* Find */
+#define FM_IINV		(5<<0)		/* Invalidate */
+#define FM_ISKIP	(6<<0)		/* Skip */
+#define FM_ICL_SKIP	(7<<0)		/* Clear all SKIP bits */
+
+/*
+ * Supernet 3:
+ * Address Filter Status Register (AFSTAT)
+ */
+					/* Bit  0-4: reserved */
+#define	FM_REV_NO	0x00e0		/* Revision Number of Address Filter */
+#define	FM_BIST_DONE	0x0100		/* BIST complete */
+#define	FM_EMPTY	0x0200		/* CAM empty */
+#define	FM_ERROR	0x0400		/* Error (improper operation) */
+#define	FM_MULT		0x0800		/* Multiple Match */
+#define	FM_EXACT	0x1000		/* Exact Match */
+#define	FM_FOUND	0x2000		/* Comparand found in CAM */
+#define	FM_FULL		0x4000		/* CAM full */
+#define	FM_DONE		0x8000		/* DONE indicator */
+
+/*
+ * Supernet 3:
+ * BIST Signature Register (AFBIST)
+ */
+#define	AF_BIST_SIGNAT	0x0553		/* Address Filter BIST Signature */
+
+/*
+ * Supernet 3:
+ * Personality Register (AFPERS)
+ */
+#define	FM_VALID	0x0001		/* CAM Entry Valid */
+#define	FM_DA		0x0002		/* Destination Address */
+#define	FM_DAX		0x0004		/* Destination Address Exact */
+#define	FM_SA		0x0008		/* Source Address */
+#define	FM_SAX		0x0010		/* Source Address Exact */
+#define	FM_SKIP		0x0020		/* Skip this entry */
+
+/*
+ * instruction set for command register 1 (NPADDR6-0 = 0x00)
+ */
+#define FM_IRESET	0x01		/* software reset */
+#define FM_IRMEMWI	0x02		/* load Memory Data Reg., inc MARR */
+#define FM_IRMEMWO	0x03		/* load MDR from buffer memory, n.i. */
+#define FM_IIL		0x04		/* idle/listen */
+#define FM_ICL		0x05		/* claim/listen */
+#define FM_IBL		0x06		/* beacon/listen */
+#define FM_ILTVX	0x07		/* load TVX timer from TVX reg */
+#define FM_INRTM	0x08		/* nonrestricted token mode */
+#define FM_IENTM	0x09		/* enter nonrestricted token mode */
+#define FM_IERTM	0x0a		/* enter restricted token mode */
+#define FM_IRTM		0x0b		/* restricted token mode */
+#define FM_ISURT	0x0c		/* send unrestricted token */
+#define FM_ISRT		0x0d		/* send restricted token */
+#define FM_ISIM		0x0e		/* enter send-immediate mode */
+#define FM_IESIM	0x0f		/* exit send-immediate mode */
+#define FM_ICLLS	0x11		/* clear synchronous queue lock */
+#define FM_ICLLA0	0x12		/* clear asynchronous queue 0 lock */
+#define FM_ICLLA1	0x14		/* clear asynchronous queue 1 lock */
+#define FM_ICLLA2	0x18		/* clear asynchronous queue 2 lock */
+					/* SN3: reserved */
+#define FM_ICLLR	0x20		/* clear receive queue (SN3:1) lock */
+#define FM_ICLLR2	0x21		/* SN3: clear receive queue 2 lock */
+#define FM_ITRXBUS	0x22		/* SN3: Tristate X-Bus (SAS only) */
+#define FM_IDRXBUS	0x23		/* SN3: drive X-Bus */
+#define FM_ICLLAL	0x3f		/* clear all queue locks */
+
+/*
+ * instruction set for command register 2 (NPADDR6-0 = 0x01)
+ */
+#define FM_ITRS		0x01		/* transmit synchronous queue */
+					/* SN3: reserved */
+#define FM_ITRA0	0x02		/* transmit asynchronous queue 0 */
+					/* SN3: reserved */
+#define FM_ITRA1	0x04		/* transmit asynchronous queue 1 */
+					/* SN3: reserved */
+#define FM_ITRA2	0x08		/* transmit asynchronous queue 2 */
+					/* SN3: reserved */
+#define FM_IACTR	0x10		/* abort current transmit activity */
+#define FM_IRSTQ	0x20		/* reset transmit queues */
+#define FM_ISTTB	0x30		/* set tag bit */
+#define FM_IERSF	0x40		/* enable receive single frame */
+					/* SN3: reserved */
+#define	FM_ITR		0x50		/* SN3: Transmit Command */
+
+
+/*
+ *	defines for PLC (Am79C864)
+ */
+
+/*
+ *  PLC read/write (r/w) registers
+ */
+#define PL_CNTRL_A	0x00		/* control register A (r/w) */
+#define PL_CNTRL_B	0x01		/* control register B (r/w) */
+#define PL_INTR_MASK	0x02		/* interrupt mask (r/w) */
+#define PL_XMIT_VECTOR	0x03		/* transmit vector register (r/w) */
+#define PL_VECTOR_LEN	0x04		/* transmit vector length (r/w) */
+#define PL_LE_THRESHOLD	0x05		/* link error event threshold (r/w) */
+#define PL_C_MIN	0x06		/* minimum connect state time (r/w) */
+#define PL_TL_MIN	0x07		/* min. line state transmit t. (r/w) */
+#define PL_TB_MIN	0x08		/* minimum break time (r/w) */
+#define PL_T_OUT	0x09		/* signal timeout (r/w) */
+#define PL_CNTRL_C	0x0a		/* control register C (r/w) */
+#define PL_LC_LENGTH	0x0b		/* link confidence test time (r/w) */
+#define PL_T_SCRUB	0x0c		/* scrub time = MAC TVX (r/w) */
+#define PL_NS_MAX	0x0d		/* max. noise time before break (r/w)*/
+#define PL_TPC_LOAD_V	0x0e		/* TPC timer load value (write only) */
+#define PL_TNE_LOAD_V	0x0f		/* TNE timer load value (write only) */
+#define PL_STATUS_A	0x10		/* status register A (read only) */
+#define PL_STATUS_B	0x11		/* status register B (read only) */
+#define PL_TPC		0x12		/* timer for PCM (ro) [20.48 us] */
+#define PL_TNE		0x13		/* time of noise event [0.32 us] */
+#define PL_CLK_DIV	0x14		/* TNE clock divider (read only) */
+#define PL_BIST_SIGNAT	0x15		/* built in self test signature (ro)*/
+#define PL_RCV_VECTOR	0x16		/* receive vector reg. (read only) */
+#define PL_INTR_EVENT	0x17		/* interrupt event reg. (read only) */
+#define PL_VIOL_SYM_CTR	0x18		/* violation symbol count. (read o) */
+#define PL_MIN_IDLE_CTR	0x19		/* minimum idle counter (read only) */
+#define PL_LINK_ERR_CTR	0x1a		/* link error event ctr.(read only) */
+#ifdef	MOT_ELM
+#define	PL_T_FOT_ASS	0x1e		/* FOTOFF Assert Timer */
+#define	PL_T_FOT_DEASS	0x1f		/* FOTOFF Deassert Timer */
+#endif	/* MOT_ELM */
+
+#ifdef	MOT_ELM
+/*
+ * Special Quad-Elm Registers.
+ * A Quad-ELM consists of for ELMs and these additional registers.
+ */
+#define	QELM_XBAR_W	0x80		/* Crossbar Control ELM W */
+#define	QELM_XBAR_X	0x81		/* Crossbar Control ELM X */
+#define	QELM_XBAR_Y	0x82		/* Crossbar Control ELM Y */
+#define	QELM_XBAR_Z	0x83		/* Crossbar Control ELM Z */
+#define	QELM_XBAR_P	0x84		/* Crossbar Control Bus P */
+#define	QELM_XBAR_S	0x85		/* Crossbar Control Bus S */
+#define	QELM_XBAR_R	0x86		/* Crossbar Control Bus R */
+#define	QELM_WR_XBAR	0x87		/* Write the Crossbar now (write) */
+#define	QELM_CTR_W	0x88		/* Counter W */
+#define	QELM_CTR_X	0x89		/* Counter X */
+#define	QELM_CTR_Y	0x8a		/* Counter Y */
+#define	QELM_CTR_Z	0x8b		/* Counter Z */
+#define	QELM_INT_MASK	0x8c		/* Interrupt mask register */
+#define	QELM_INT_DATA	0x8d		/* Interrupt data (event) register */
+#define	QELM_ELMB	0x00		/* Elm base */
+#define	QELM_ELM_SIZE	0x20		/* ELM size */
+#endif	/* MOT_ELM */
+/*
+ * PLC control register A (PL_CNTRL_A: log. addr. 0x00)
+ * It is used for timer configuration, specification of PCM MAINT state option,
+ * counter interrupt frequency, PLC data path config. and Built In Self Test.
+ */
+#define	PL_RUN_BIST	0x0001		/* begin running its Built In Self T.*/
+#define	PL_RF_DISABLE	0x0002		/* disable the Repeat Filter state m.*/
+#define	PL_SC_REM_LOOP	0x0004		/* remote loopback path */
+#define	PL_SC_BYPASS	0x0008		/* by providing a physical bypass */
+#define	PL_LM_LOC_LOOP	0x0010		/* loop path just after elastic buff.*/
+#define	PL_EB_LOC_LOOP	0x0020		/* loop path just prior to PDT/PDR IF*/
+#define	PL_FOT_OFF	0x0040		/* assertion of /FOTOFF pin of PLC */
+#define	PL_LOOPBACK	0x0080		/* it cause the /LPBCK pin ass. low */
+#define	PL_MINI_CTR_INT 0x0100		/* partially contr. when bit is ass. */
+#define	PL_VSYM_CTR_INT	0x0200		/* controls when int bit is asserted */
+#define	PL_ENA_PAR_CHK	0x0400		/* enable parity check */
+#define	PL_REQ_SCRUB	0x0800		/* limited access to scrub capability*/
+#define	PL_TPC_16BIT	0x1000		/* causes the TPC as a 16 bit timer */
+#define	PL_TNE_16BIT	0x2000		/* causes the TNE as a 16 bit timer */
+#define	PL_NOISE_TIMER	0x4000		/* allows the noise timing function */
+
+/*
+ * PLC control register B (PL_CNTRL_B: log. addr. 0x01)
+ * It contains signals and requeste to direct the process of PCM and it is also
+ * used to control the Line State Match interrupt.
+ */
+#define	PL_PCM_CNTRL	0x0003		/* control PCM state machine */
+#define	PL_PCM_NAF	(0)		/* state is not affected */
+#define	PL_PCM_START	(1)		/* goes to the BREAK state */
+#define	PL_PCM_TRACE	(2)		/* goes to the TRACE state */
+#define	PL_PCM_STOP	(3)		/* goes to the OFF state */
+
+#define	PL_MAINT	0x0004		/* if OFF state --> MAINT state */
+#define	PL_LONG		0x0008		/* perf. a long Link Confid.Test(LCT)*/
+#define	PL_PC_JOIN	0x0010		/* if NEXT state --> JOIN state */
+
+#define	PL_PC_LOOP	0x0060		/* loopback used in the LCT */
+#define	PL_NOLCT	(0<<5)		/* no LCT is performed */
+#define	PL_TPDR		(1<<5)		/* PCM asserts transmit PDR */
+#define	PL_TIDLE	(2<<5)		/* PCM asserts transmit idle */
+#define	PL_RLBP		(3<<5)		/* trans. PDR & remote loopb. path */
+
+#define	PL_CLASS_S	0x0080		/* signif. that single att. station */
+
+#define	PL_MAINT_LS	0x0700		/* line state while in the MAINT st. */
+#define	PL_M_QUI0	(0<<8)		/* transmit QUIET line state */
+#define	PL_M_IDLE	(1<<8)		/* transmit IDLE line state */
+#define	PL_M_HALT	(2<<8)		/* transmit HALT line state */
+#define	PL_M_MASTR	(3<<8)		/* transmit MASTER line state */
+#define	PL_M_QUI1	(4<<8)		/* transmit QUIET line state */
+#define	PL_M_QUI2	(5<<8)		/* transmit QUIET line state */
+#define	PL_M_TPDR	(6<<8)		/* tr. PHY_DATA requ.-symbol is tr.ed*/
+#define	PL_M_QUI3	(7<<8)		/* transmit QUIET line state */
+
+#define	PL_MATCH_LS	0x7800		/* line state to be comp. with curr.*/
+#define	PL_I_ANY	(0<<11)		/* Int. on any change in *_LINE_ST */
+#define	PL_I_IDLE	(1<<11)		/* Interrupt on IDLE line state */
+#define	PL_I_HALT	(2<<11)		/* Interrupt on HALT line state */
+#define	PL_I_MASTR	(4<<11)		/* Interrupt on MASTER line state */
+#define	PL_I_QUIET	(8<<11)		/* Interrupt on QUIET line state */
+
+#define	PL_CONFIG_CNTRL	0x8000		/* control over scrub, byp. & loopb.*/
+
+/*
+ * PLC control register C (PL_CNTRL_C: log. addr. 0x0a)
+ * It contains the scrambling control registers (PLC-S only)
+ */
+#define PL_C_CIPHER_ENABLE	(1<<0)	/* enable scrambler */
+#define PL_C_CIPHER_LPBCK	(1<<1)	/* loopback scrambler */
+#define PL_C_SDOFF_ENABLE	(1<<6)	/* enable SDOFF timer */
+#define PL_C_SDON_ENABLE	(1<<7)	/* enable SDON timer */
+#ifdef	MOT_ELM
+#define PL_C_FOTOFF_CTRL	(3<<2)	/* FOTOFF timer control */
+#define PL_C_FOTOFF_TIM		(0<<2)	/* FOTOFF use timer for (de)-assert */
+#define PL_C_FOTOFF_INA		(2<<2)	/* FOTOFF forced inactive */
+#define PL_C_FOTOFF_ACT		(3<<2)	/* FOTOFF forced active */
+#define PL_C_FOTOFF_SRCE	(1<<4)	/* FOTOFF source is PCM state != OFF */
+#define	PL_C_RXDATA_EN		(1<<5)	/* Rec scr data forced to 0 */
+#define	PL_C_SDNRZEN		(1<<8)	/* Monitor rec descr. data for act */
+#else	/* nMOT_ELM */
+#define PL_C_FOTOFF_CTRL	(3<<8)	/* FOTOFF timer control */
+#define PL_C_FOTOFF_0		(0<<8)	/* timer off */
+#define PL_C_FOTOFF_30		(1<<8)	/* 30uS */
+#define PL_C_FOTOFF_50		(2<<8)	/* 50uS */
+#define PL_C_FOTOFF_NEVER	(3<<8)	/* never */
+#define PL_C_SDON_TIMER		(3<<10)	/* SDON timer control */
+#define PL_C_SDON_084		(0<<10)	/* 0.84 uS */
+#define PL_C_SDON_132		(1<<10)	/* 1.32 uS */
+#define PL_C_SDON_252		(2<<10)	/* 2.52 uS */
+#define PL_C_SDON_512		(3<<10)	/* 5.12 uS */
+#define PL_C_SOFF_TIMER		(3<<12)	/* SDOFF timer control */
+#define PL_C_SOFF_076		(0<<12)	/* 0.76 uS */
+#define PL_C_SOFF_132		(1<<12)	/* 1.32 uS */
+#define PL_C_SOFF_252		(2<<12)	/* 2.52 uS */
+#define PL_C_SOFF_512		(3<<12)	/* 5.12 uS */
+#define PL_C_TSEL		(3<<14)	/* scrambler path select */
+#endif	/* nMOT_ELM */
+
+/*
+ * PLC status register A (PL_STATUS_A: log. addr. 0x10)
+ * It is used to report status information to the Node Processor about the 
+ * Line State Machine (LSM).
+ */
+#ifdef	MOT_ELM
+#define PLC_INT_MASK	0xc000		/* ELM integration bits in status A */
+#define PLC_INT_C	0x0000		/* ELM Revision Band C */
+#define PLC_INT_CAMEL	0x4000		/* ELM integrated into CAMEL */
+#define PLC_INT_QE	0x8000		/* ELM integrated into Quad ELM */
+#define PLC_REV_MASK	0x3800		/* revision bits in status A */
+#define PLC_REVISION_B	0x0000		/* rev bits for ELM Rev B */
+#define PLC_REVISION_QA	0x0800		/* rev bits for ELM core in QELM-A */
+#else	/* nMOT_ELM */
+#define PLC_REV_MASK	0xf800		/* revision bits in status A */
+#define PLC_REVISION_A	0x0000		/* revision bits for PLC */
+#define PLC_REVISION_S	0xf800		/* revision bits for PLC-S */
+#define PLC_REV_SN3	0x7800		/* revision bits for PLC-S in IFCP */
+#endif	/* nMOT_ELM */
+#define	PL_SYM_PR_CTR	0x0007		/* contains the LSM symbol pair Ctr. */
+#define	PL_UNKN_LINE_ST	0x0008		/* unknown line state bit from LSM */
+#define	PL_LSM_STATE	0x0010		/* state bit of LSM */
+
+#define	PL_LINE_ST	0x00e0		/* contains recogn. line state of LSM*/
+#define	PL_L_NLS	(0<<5)		/* noise line state */
+#define	PL_L_ALS	(1<<5)		/* activ line state */
+#define	PL_L_UND	(2<<5)		/* undefined */
+#define	PL_L_ILS4	(3<<5)		/* idle l. s. (after 4 idle symbols) */
+#define	PL_L_QLS	(4<<5)		/* quiet line state */
+#define	PL_L_MLS	(5<<5)		/* master line state */
+#define	PL_L_HLS	(6<<5)		/* halt line state */
+#define	PL_L_ILS16	(7<<5)		/* idle line state (after 16 idle s.)*/
+
+#define	PL_PREV_LINE_ST	0x0300		/* value of previous line state */
+#define	PL_P_QLS	(0<<8)		/* quiet line state */
+#define	PL_P_MLS	(1<<8)		/* master line state */
+#define	PL_P_HLS	(2<<8)		/* halt line state */
+#define	PL_P_ILS16	(3<<8)		/* idle line state (after 16 idle s.)*/
+
+#define	PL_SIGNAL_DET	0x0400		/* 1=that signal detect is deasserted*/
+
+
+/*
+ * PLC status register B (PL_STATUS_B: log. addr. 0x11)
+ * It contains signals and status from the repeat filter and PCM state machine.
+ */
+#define	PL_BREAK_REASON	0x0007		/* reason for PCM state mach.s to br.*/
+#define	PL_B_NOT	(0)		/* PCM SM has not gone to BREAK state*/
+#define	PL_B_PCS	(1)		/* PC_Start issued */
+#define	PL_B_TPC	(2)		/* TPC timer expired after T_OUT */
+#define	PL_B_TNE	(3)		/* TNE timer expired after NS_MAX */
+#define	PL_B_QLS	(4)		/* quit line state detected */
+#define	PL_B_ILS	(5)		/* idle line state detected */
+#define	PL_B_HLS	(6)		/* halt line state detected */
+
+#define	PL_TCF		0x0008		/* transmit code flag (start exec.) */
+#define	PL_RCF		0x0010		/* receive code flag (start exec.) */
+#define	PL_LSF		0x0020		/* line state flag (l.s. has been r.)*/
+#define	PL_PCM_SIGNAL	0x0040		/* indic. that XMIT_VECTOR hb.written*/
+
+#define	PL_PCM_STATE	0x0780		/* state bits of PCM state machine */
+#define	PL_PC0		(0<<7)		/* OFF	   - when /RST or PCM_CNTRL */
+#define	PL_PC1		(1<<7)		/* BREAK   - entry point in start PCM*/
+#define	PL_PC2		(2<<7)		/* TRACE   - to localize stuck Beacon*/
+#define	PL_PC3		(3<<7)		/* CONNECT - synchronize ends of conn*/
+#define	PL_PC4		(4<<7)		/* NEXT	   - to seperate the signalng*/
+#define	PL_PC5		(5<<7)		/* SIGNAL  - PCM trans/rec. bit infos*/
+#define	PL_PC6		(6<<7)		/* JOIN	   - 1. state to activ conn. */
+#define	PL_PC7		(7<<7)		/* VERIFY  - 2. - " - (3. ACTIVE) */
+#define	PL_PC8		(8<<7)		/* ACTIVE  - PHY has been incorporated*/
+#define	PL_PC9		(9<<7)		/* MAINT   - for test purposes or so 
+					   that PCM op. completely in softw. */
+
+#define	PL_PCI_SCRUB	0x0800		/* scrubbing function is being exec. */
+
+#define	PL_PCI_STATE	0x3000		/* Physical Connect. Insertion SM */
+#define	PL_CI_REMV	(0<<12)		/* REMOVED */
+#define	PL_CI_ISCR	(1<<12)		/* INSERT_SCRUB */
+#define	PL_CI_RSCR	(2<<12)		/* REMOVE_SCRUB */
+#define	PL_CI_INS	(3<<12)		/* INSERTED */
+
+#define	PL_RF_STATE	0xc000		/* state bit of repeate filter SM */
+#define	PL_RF_REPT	(0<<14)		/* REPEAT */
+#define	PL_RF_IDLE	(1<<14)		/* IDLE */
+#define	PL_RF_HALT1	(2<<14)		/* HALT1 */
+#define	PL_RF_HALT2	(3<<14)		/* HALT2 */
+
+
+/*
+ * PLC interrupt event register (PL_INTR_EVENT: log. addr. 0x17)
+ * It is read only and is clearde whenever it is read!
+ * It is used by the PLC to report events to the node processor.
+ */
+#define	PL_PARITY_ERR	0x0001		/* p. error h.b.detected on TX9-0 inp*/
+#define	PL_LS_MATCH	0x0002		/* l.s.== l.s. PLC_CNTRL_B's MATCH_LS*/
+#define	PL_PCM_CODE	0x0004		/* transmit&receive | LCT complete */
+#define	PL_TRACE_PROP	0x0008		/* master l.s. while PCM ACTIV|TRACE */
+#define	PL_SELF_TEST	0x0010		/* QUIET|HALT while PCM in TRACE st. */
+#define	PL_PCM_BREAK	0x0020		/* PCM has entered the BREAK state */
+#define	PL_PCM_ENABLED	0x0040		/* asserted SC_JOIN, scrub. & ACTIV */
+#define	PL_TPC_EXPIRED	0x0080		/* TPC timer reached zero */
+#define	PL_TNE_EXPIRED	0x0100		/* TNE timer reached zero */
+#define	PL_EBUF_ERR	0x0200		/* elastic buff. det. over-|underflow*/
+#define	PL_PHYINV	0x0400		/* physical layer invalid signal */
+#define	PL_VSYM_CTR	0x0800		/* violation symbol counter has incr.*/
+#define	PL_MINI_CTR	0x1000		/* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
+#define	PL_LE_CTR	0x2000		/* link error event counter */
+#define	PL_LSDO		0x4000		/* SDO input pin changed to a 1 */
+#define	PL_NP_ERR	0x8000		/* NP has requested to r/w an inv. r.*/
+
+/*
+ * The PLC interrupt mask register (PL_INTR_MASK: log. addr. 0x02) constr. is
+ * equal PL_INTR_EVENT register.
+ * For each set bit, the setting of corresponding bit generate an int to NP. 
+ */
+
+#ifdef	MOT_ELM
+/*
+ * Quad ELM Crosbar Control register values (QELM_XBAR_?)
+ */
+#define	QELM_XOUT_IDLE	0x0000		/* Idles/Passthrough */
+#define	QELM_XOUT_P	0x0001		/* Output to: Bus P */
+#define	QELM_XOUT_S	0x0002		/* Output to: Bus S */
+#define	QELM_XOUT_R	0x0003		/* Output to: Bus R */
+#define	QELM_XOUT_W	0x0004		/* Output to: ELM W */
+#define	QELM_XOUT_X	0x0005		/* Output to: ELM X */
+#define	QELM_XOUT_Y	0x0006		/* Output to: ELM Y */
+#define	QELM_XOUT_Z	0x0007		/* Output to: ELM Z */
+
+/*
+ * Quad ELM Interrupt data and event registers.
+ */
+#define	QELM_NP_ERR	(1<<15)		/* Node Processor Error */
+#define	QELM_COUNT_Z	(1<<7)		/* Counter Z Interrupt */
+#define	QELM_COUNT_Y	(1<<6)		/* Counter Y Interrupt */
+#define	QELM_COUNT_X	(1<<5)		/* Counter X Interrupt */
+#define	QELM_COUNT_W	(1<<4)		/* Counter W Interrupt */
+#define	QELM_ELM_Z	(1<<3)		/* ELM Z Interrupt */
+#define	QELM_ELM_Y	(1<<2)		/* ELM Y Interrupt */
+#define	QELM_ELM_X	(1<<1)		/* ELM X Interrupt */
+#define	QELM_ELM_W	(1<<0)		/* ELM W Interrupt */
+#endif	/* MOT_ELM */
+/*
+ * PLC Timing Parameters
+ */
+#define	TP_C_MIN	0xff9c	/*   2    ms */
+#define	TP_TL_MIN	0xfff0	/*   0.3  ms */
+#define	TP_TB_MIN	0xff10	/*   5    ms */
+#define	TP_T_OUT	0xd9db	/* 200    ms */
+#define	TP_LC_LENGTH	0xf676	/*  50    ms */
+#define	TP_LC_LONGLN	0xa0a2	/* 500    ms */
+#define	TP_T_SCRUB	0xff6d	/*   3.5  ms */
+#define	TP_NS_MAX	0xf021	/*   1.3   ms */
+
+/*
+ * BIST values
+ */
+#define PLC_BIST	0x6ecd		/* BIST signature for PLC */
+#define PLCS_BIST	0x5b6b 		/* BIST signature for PLC-S */
+#define	PLC_ELM_B_BIST	0x6ecd		/* BIST signature of ELM Rev. B */
+#define	PLC_ELM_D_BIST	0x5b6b		/* BIST signature of ELM Rev. D */
+#define	PLC_CAM_A_BIST	0x9e75		/* BIST signature of CAMEL Rev. A */
+#define	PLC_CAM_B_BIST	0x5b6b		/* BIST signature of CAMEL Rev. B */
+#define	PLC_IFD_A_BIST	0x9e75		/* BIST signature of IFDDI Rev. A */
+#define	PLC_IFD_B_BIST	0x5b6b		/* BIST signature of IFDDI Rev. B */
+#define	PLC_QELM_A_BIST	0x5b6b		/* BIST signature of QELM Rev. A */
+
+/*
+ 	FDDI board recources	
+ */
+
+/*
+ * request register array (log. addr: RQA_A + a<<1 {a=0..7}) write only.
+ * It specifies to FORMAC+ the type of buffer memory access the host requires.
+ */
+#define	RQ_NOT		0		/* not request */
+#define	RQ_RES		1		/* reserved */
+#define	RQ_SFW		2		/* special frame write */
+#define	RQ_RRQ		3		/* read request: receive queue */
+#define	RQ_WSQ		4		/* write request: synchronous queue */
+#define	RQ_WA0		5		/* write requ.: asynchronous queue 0 */
+#define	RQ_WA1		6		/* write requ.: asynchronous queue 1 */
+#define	RQ_WA2		7		/* write requ.: asynchronous queue 2 */
+
+#define	SZ_LONG		(sizeof(long))
+
+/*
+ * FDDI defaults
+ * NOTE : In the ANSI docs, times are specified in units of "symbol time".
+ * 	  AMD chips use BCLK as unit. 1 BCKL == 2 symbols
+ */
+#define	COMPLREF	((u_long)32*256*256)	/* two's complement 21 bit */
+#define MSTOBCLK(x)	((u_long)(x)*12500L)
+#define MSTOTVX(x)	(((u_long)(x)*1000L)/80/255)
+
+#endif	/* _SUPERNET_ */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/targethw.h linux/drivers/net/skfp/h/targethw.h
--- v2.3.46/linux/drivers/net/skfp/h/targethw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/targethw.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_TARGETHW_
+#define _TARGETHW_
+
+	/*
+	 *  PCI Watermark definition
+	 */
+#ifdef	PCI
+#define	RX_WATERMARK	24
+#define TX_WATERMARK	24
+#define SK_ML_ID_1	0x20
+#define SK_ML_ID_2	0x30
+#endif
+
+#include	"h/skfbi.h"
+#ifndef TAG_MODE	
+#include	"h/fplus.h"
+#else
+#include	"h/fplustm.h"
+#endif
+
+#ifndef	HW_PTR
+#ifdef  MEM_MAPPED_IO
+#define HW_PTR  u_long
+#else
+#define HW_PTR  u_short
+#endif
+#endif
+
+#ifdef MULT_OEM
+#define	OI_STAT_LAST		0	/* end of OEM data base */
+#define	OI_STAT_PRESENT		1	/* entry present but not empty */
+#define	OI_STAT_VALID		2	/* holds valid ID, but is not active */ 
+#define	OI_STAT_ACTIVE		3	/* holds valid ID, entry is active */
+					/* active = adapter is supported */
+
+/* Memory representation of IDs must match representation in adapter. */
+struct	s_oem_ids {
+	u_char	oi_status ;		/* Stat: last, present, valid, active */
+	u_char	oi_mark[5] ;		/* "PID00" .. "PID07" ..	*/
+	u_char 	oi_id[4] ;		/* id bytes, representation as	*/
+					/* defined by hardware,		*/	
+#ifdef PCI
+	u_char 	oi_sub_id[4] ;		/* sub id bytes, representation as */
+					/* defined by hardware,		*/
+#endif
+#ifdef ISA
+	u_char	oi_logo_len ;		/* the length of the adapter logo */	
+	u_char	oi_logo[6] ;		/* the adapter logo		*/
+	u_char	oi_reserved1 ;
+#endif	/* ISA */
+} ;
+#endif	/* MULT_OEM */
+
+
+struct s_smt_hw {
+	/*
+	 * global
+	 */
+	HW_PTR	iop ;			/* IO base address */
+	short	dma ;			/* DMA channel */
+	short	irq ;			/* IRQ level */
+	short	eprom ;			/* FLASH prom */
+#ifndef	PCI
+	short	DmaWriteExtraBytes ;	/* add bytes for DMA write */
+#endif
+
+#ifndef SYNC
+	u_short	n_a_send ;		/* pending send requests */
+#endif
+
+#if	(defined(EISA) || defined(MCA) || defined(PCI))
+	short	slot ;			/* slot number */
+	short   max_slots ;		/* maximum number of slots */
+#endif
+
+#if	(defined(PCI) || defined(MCA))
+	short	wdog_used ;		/* TRUE if the watch dog is used */
+#endif
+
+#ifdef	MCA
+	short	slot_32 ;		/* 32bit slot (1) or 16bit slot (0) */
+	short	rev ;			/* Board revision (FMx_REV). */
+	short	VFullRead ;		/* V_full value for DMA read */
+	short	VFullWrite ;		/* V_full value for DMA write */
+#endif
+
+#ifdef	EISA
+	short	led ;			/* LED for FE card */
+
+	short	dma_rmode ;		/* read mode */
+	short	dma_wmode ;		/* write mode */
+	short	dma_emode ;		/* extend mode */
+
+	/* DMA controller channel dependent io addresses */
+	u_short dma_base_word_count ;
+	u_short dma_base_address ;
+	u_short dma_base_address_page ;
+#endif
+
+#ifdef	PCI
+	u_short	pci_handle ;		/* handle to access the BIOS func */
+	u_long	is_imask ;		/* int maske for the int source reg */
+	u_long	phys_mem_addr ;		/* physical memory address */
+	u_short	mc_dummy ;		/* work around for MC compiler bug */	
+	/*
+	 * state of the hardware
+	 */
+	u_short hw_state ;		/* started or stopped */
+
+#define	STARTED		1
+#define	STOPPED		0
+
+	int	hw_is_64bit ;		/* does we have a 64 bit adapter */
+#endif
+
+#ifdef	TAG_MODE
+	u_long	pci_fix_value ;		/* value parsed by PCIFIX */
+#endif
+
+	/*
+	 * hwt.c
+	 */
+	u_long	t_start ;		/* HWT start */
+	u_long	t_stop ;		/* HWT stop */
+	u_short	timer_activ ;		/* HWT timer active */
+
+	/*
+	 * PIC
+	 */
+	u_char	pic_a1 ;
+	u_char	pic_21 ;
+
+	/*
+	 * GENERIC ; do not modify beyond this line
+	 */
+
+	/*
+	 * physical and canonical address
+	 */
+	struct fddi_addr fddi_home_addr ;
+	struct fddi_addr fddi_canon_addr ;
+	struct fddi_addr fddi_phys_addr ;
+
+	/*
+	 * mac variables
+	 */
+	struct mac_parameter mac_pa ;	/* tmin, tmax, tvx, treq .. */
+	struct mac_counter mac_ct ;	/* recv., lost, error  */
+	u_short	mac_ring_is_up ;	/* ring is up flag */
+
+	struct s_smt_fp	fp ;		/* formac+ */
+
+#ifdef MULT_OEM
+	struct s_oem_ids *oem_id ;	/* pointer to selected id */
+	int oem_min_status ;		/* IDs to take care of */
+#endif	/* MULT_OEM */
+
+} ;
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/targetos.h linux/drivers/net/skfp/h/targetos.h
--- v2.3.46/linux/drivers/net/skfp/h/targetos.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/targetos.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	Operating system specific definitions for driver and
+ *	hardware module.
+ */
+
+#ifndef	TARGETOS_H
+#define TARGETOS_H
+
+
+//-------- those should go into include/linux/pci.h
+#define PCI_VENDOR_ID_SK		0x1148
+#define PCI_DEVICE_ID_SK_FP		0x4000
+//--------
+
+
+
+//-------- those should go into include/linux/if_fddi.h
+#define FDDI_MAC_HDR_LEN 13
+
+#define FDDI_RII	0x01 /* routing information bit */
+#define FDDI_RCF_DIR_BIT 0x80
+#define FDDI_RCF_LEN_MASK 0x1f
+#define FDDI_RCF_BROADCAST 0x8000
+#define FDDI_RCF_LIMITED_BROADCAST 0xA000
+#define FDDI_RCF_FRAME2K 0x20
+#define FDDI_RCF_FRAME4K 0x30
+//--------
+
+
+#undef ADDR
+
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+// is redefined by linux, but we need our definition
+#undef ADDR
+#ifdef MEM_MAPPED_IO
+#define	ADDR(a) (char far *) smc->hw.iop+(a)
+#else
+#define	ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#endif
+
+#include "h/hwmtm.h"
+
+#define TRUE  1
+#define FALSE 0
+
+// HWM Definitions
+// -----------------------
+#define FDDI_TRACE(string, arg1, arg2, arg3)	// Performance analysis.
+#ifdef PCI
+#define NDD_TRACE(string, arg1, arg2, arg3)	// Performance analysis.
+#endif	// PCI
+#define SMT_PAGESIZE	PAGE_SIZE	// Size of a memory page (power of 2).
+// -----------------------
+
+
+// SMT Definitions
+// -----------------------
+#define	TICKS_PER_SECOND	HZ
+#define SMC_VERSION    		1
+// -----------------------
+
+
+// OS-Driver Definitions
+// -----------------------
+#define NO_ADDRESS 0xffe0	/* No Device (I/O) Address */
+#define SKFP_MAX_NUM_BOARDS 8	/* maximum number of PCI boards */
+
+#define SK_BUS_TYPE_PCI		0
+#define SK_BUS_TYPE_EISA	1
+
+#define FP_IO_LEN		256	/* length of IO area used */
+
+#define u8	unsigned char
+#define u16	unsigned short
+#define u32	unsigned long
+
+#define MAX_TX_QUEUE_LEN	20 // number of packets queued by driver
+#define MAX_FRAME_SIZE		4550
+
+#define	RX_LOW_WATERMARK	NUM_RECEIVE_BUFFERS  / 2
+#define TX_LOW_WATERMARK	NUM_TRANSMIT_BUFFERS - 2
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define	SKFPIOCTL	SIOCDEVPRIVATE
+
+struct s_skfp_ioctl {
+	unsigned short cmd;                /* Command to run */
+	unsigned short len;                /* Length of the data buffer */
+	unsigned char  *data;              /* Pointer to the data buffer */
+};
+
+/* 
+** Recognised ioctl commands for the driver 
+*/
+#define SKFP_GET_STATS		0x05 /* Get the driver statistics */
+#define SKFP_CLR_STATS		0x06 /* Zero out the driver statistics */
+
+// The per-adapter driver structure
+struct s_smt_os {
+	struct net_device *dev;
+	struct net_device *next_module;
+	u32	bus_type;		/* bus type (0 == PCI, 1 == EISA) */
+	struct pci_dev 	pdev;		/* PCI device structure */
+	
+	u32	base_addr;
+	unsigned char factory_mac_addr[8];
+	ulong	SharedMemSize;
+	ulong	SharedMemHeap;
+	void*	SharedMemAddr;
+
+	ulong	QueueSkb;
+	struct	sk_buff_head SendSkbQueue;
+
+	ulong	MaxFrameSize;
+	u8	ResetRequested;
+
+	// MAC statistics structure
+	struct fddi_statistics MacStat;
+
+	// receive into this local buffer if no skb available
+	// data will be not valid, because multiple RxDs can
+	// point here at the same time
+	unsigned char LocalRxBuffer[MAX_FRAME_SIZE];
+	
+	// Version (required by SMT module).
+	u_long smc_version ;
+
+	// Required by Hardware Module (HWM).
+	struct hw_modul hwm ;
+	
+	// For SMP-savety
+	spinlock_t DriverLock;
+	
+};
+
+typedef struct s_smt_os skfddi_priv;
+
+#endif	 // _TARGETOS_
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/types.h linux/drivers/net/skfp/h/types.h
--- v2.3.46/linux/drivers/net/skfp/h/types.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/h/types.h	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include	<linux/types.h>
+/*
+	----------------------
+	Basic SMT system types
+	----------------------
+*/
+#ifndef _TYPES_
+#define	_TYPES_
+
+#define _packed
+#ifndef far
+#define far
+#endif
+#ifndef _far
+#define _far
+#endif
+
+#ifndef MEM_MAPPED_IO // "normal" IO
+#define inp(p)  inb(p)
+#define inpw(p)	inw(p)
+#define inpd(p) inl(p)
+#define outp(p,c)  outb(c,p)
+#define outpw(p,s) outw(s,p)
+#define outpd(p,l) outl(l,p)
+#else // memory mapped io
+#define inp(a)		readb(a)
+#define inpw(a)		readw(a)
+#define inpd(a)		readl(a)
+#define outp(a,v)	writeb(v, a)	
+#define outpw(a,v)	writew(v, a)	
+#define outpd(a,v)	writel(v, a)	
+#endif
+
+#endif	/* _TYPES_ */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/hwmtm.c linux/drivers/net/skfp/hwmtm.c
--- v2.3.46/linux/drivers/net/skfp/hwmtm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/hwmtm.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,2261 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static char const ID_sccs[] = "@(#)hwmtm.c	1.40 99/05/31 (C) SK" ;
+#endif
+
+#define	HWMTM
+
+#ifndef FDDI
+#define	FDDI
+#endif
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "h/skfbiinc.h"
+
+/*
+	-------------------------------------------------------------
+	DOCUMENTATION
+	-------------------------------------------------------------
+	BEGIN_MANUAL_ENTRY(DOCUMENTATION)
+
+			T B D
+
+	END_MANUAL_ENTRY
+*/
+/*
+	-------------------------------------------------------------
+	LOCAL VARIABLES:
+	-------------------------------------------------------------
+*/
+#ifdef COMMON_MB_POOL
+static	SMbuf *mb_start = 0 ;
+static	SMbuf *mb_free = 0 ;
+static	int mb_init = FALSE ;
+static	int call_count = 0 ;
+#endif
+
+/*
+	-------------------------------------------------------------
+	EXTERNE VARIABLES:
+	-------------------------------------------------------------
+*/
+
+#ifdef	DEBUG
+#ifndef	DEBUG_BRD
+extern	struct smt_debug	debug ;
+#endif
+#endif
+
+#ifdef	NDIS_OS2
+extern	u_char	offDepth ;
+extern	u_char	force_irq_pending ;
+#endif
+
+/*
+	-------------------------------------------------------------
+	LOCAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+static	void	queue_llc_rx(),		smt_to_llc(),
+		init_txd_ring(),	init_rxd_ring(),
+		queue_txd_mb() ;
+
+static	u_long	init_descr_ring(),	repair_txd_ring(),
+		repair_rxd_ring() ;
+
+static	SMbuf	*get_llc_rx(),		*get_txd_mb() ;
+
+
+/*
+	-------------------------------------------------------------
+	EXTERNAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+/*	The external SMT functions are listed in cmtdef.h */
+
+extern	void	*mac_drv_get_space(),	*mac_drv_get_desc_mem(),
+		init_board(),		mac_drv_fill_rxd(),
+		plc1_irq(),		mac_drv_tx_complete(),
+		plc2_irq(),		mac1_irq(),
+		mac2_irq(),		mac3_irq(),
+		timer_irq(),		mac_drv_rx_complete(),
+		mac_drv_requeue_rxd(),	init_plc(),
+		mac_drv_clear_rxd(),	llc_restart_tx(),
+		ev_dispatcher(),	smt_force_irq() ;
+
+#ifdef	USE_OS_CPY
+extern	void	hwm_cpy_rxd2mb(),	hwm_cpy_txd2mb() ;
+#endif
+#ifdef	ALL_RX_COMPLETE
+extern	void	mac_drv_all_receives_complete() ;
+#endif
+
+extern	u_long	mac_drv_virt2phys(),	dma_master() ;
+
+#ifdef	NDIS_OS2
+extern	void	post_proc() ;
+#else
+extern	void	dma_complete() ;
+#endif
+
+extern	int	init_fplus(),		mac_drv_rx_init() ;
+
+/*
+	-------------------------------------------------------------
+	PUBLIC FUNCTIONS:
+	-------------------------------------------------------------
+*/
+	void	process_receive(),	smt_send_mbuf(),
+		fddi_isr(),		mac_drv_clear_txd(),
+		smt_free_mbuf(),	init_driver_fplus(),
+		mac_drv_rx_mode(),	init_fddi_driver(),
+		mac_drv_clear_tx_queue(),
+		mac_drv_clear_rx_queue(),
+		hwm_tx_frag(),		hwm_rx_frag() ;
+
+	int	mac_drv_rx_frag(),	mac_drv_init(),
+		hwm_tx_init() ;
+
+	u_int	mac_drv_check_space() ;
+
+	SMbuf 	*smt_get_mbuf() ;
+
+#ifdef DEBUG
+	void	mac_drv_debug_lev() ;
+#endif
+
+/*
+	-------------------------------------------------------------
+	MACROS:
+	-------------------------------------------------------------
+*/
+#ifndef	UNUSED
+#ifdef	lint
+#define UNUSED(x)	(x) = (x)
+#else
+#define UNUSED(x)
+#endif
+#endif
+
+#ifdef	USE_CAN_ADDR
+#define MA		smc->hw.fddi_canon_addr.a
+#define	GROUP_ADDR_BIT	0x01
+#else
+#define	MA		smc->hw.fddi_home_addr.a
+#define	GROUP_ADDR_BIT	0x80
+#endif
+
+#define RXD_TXD_COUNT	(HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\
+			SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT)
+
+#ifdef	MB_OUTSIDE_SMC
+#define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\
+			MAX_MBUF*sizeof(SMbuf))
+#define	EXT_VIRT_MEM_2	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
+#else
+#define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
+#endif
+
+	/*
+	 * define critical read for 16 Bit drivers
+	 */
+#if	defined(NDIS_OS2) || defined(ODI2)
+#define CR_READ(var)	((var) & 0xffff0000 | ((var) & 0xffff))
+#else
+#define CR_READ(var)	(u_long)(var)
+#endif
+
+#define IMASK_SLOW	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+			 IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
+			 IS_R1_C | IS_XA_C | IS_XS_C)
+
+/*
+	-------------------------------------------------------------
+	INIT- AND SMT FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_check_space)
+ *	u_int mac_drv_check_space()
+ *
+ *	function	DOWNCALL	(drvsr.c)
+ *			This function calculates the needed non virtual
+ *			memory for MBufs, RxD and TxD descriptors etc.
+ *			needed by the driver.
+ *
+ *	return		u_int	memory in bytes
+ *
+ *	END_MANUAL_ENTRY
+ */
+u_int mac_drv_check_space()
+{
+#ifdef	MB_OUTSIDE_SMC
+#ifdef	COMMON_MB_POOL
+	call_count++ ;
+	if (call_count == 1) {
+		return(EXT_VIRT_MEM) ;
+	}
+	else {
+		return(EXT_VIRT_MEM_2) ;
+	}
+#else
+	return (EXT_VIRT_MEM) ;
+#endif
+#else
+	return (0) ;
+#endif
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_init)
+ *	void mac_drv_init(smc)
+ *
+ *	function	DOWNCALL	(drvsr.c)
+ *			In this function the hardware module allocates it's
+ *			memory.
+ *			The operating system dependent module should call
+ *			mac_drv_init once, after the adatper is detected.
+ *	END_MANUAL_ENTRY
+ */
+int mac_drv_init(smc)
+struct s_smc *smc ;
+{
+	if (sizeof(struct s_smt_fp_rxd) % 16) {
+		SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ;
+	}
+	if (sizeof(struct s_smt_fp_txd) % 16) {
+		SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ;
+	}
+
+	/*
+	 * get the required memory for the RxDs and TxDs
+	 */
+	if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *)
+		mac_drv_get_desc_mem(smc,(u_int)
+		(RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) {
+		return(1) ;	/* no space the hwm modul can't work */
+	}
+
+	/*
+	 * get the memory for the SMT MBufs
+	 */
+#ifndef	MB_OUTSIDE_SMC
+	smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ;
+#else
+#ifndef	COMMON_MB_POOL
+	if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc,
+		MAX_MBUF*sizeof(SMbuf)))) {
+		return(1) ;	/* no space the hwm modul can't work */
+	}
+#else
+	if (!mb_start) {
+		if (!(mb_start = (SMbuf *) mac_drv_get_space(smc,
+			MAX_MBUF*sizeof(SMbuf)))) {
+			return(1) ;	/* no space the hwm modul can't work */
+		}
+	}
+#endif
+#endif
+	return (0) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(init_driver_fplus)
+ *	init_driver_fplus(smc)
+ *
+ * Sets hardware modul specific values for the mode register 2
+ * (e.g. the byte alignment for the received frames, the position of the
+ *	 least significant byte etc.)
+ *	END_MANUAL_ENTRY
+ */
+void init_driver_fplus(smc)
+struct s_smc *smc ;
+{
+	smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ;
+
+#ifdef	PCI
+	smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ;
+#endif
+	smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ;
+
+#ifdef	USE_CAN_ADDR
+	/* enable address bit swapping */
+	smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ;
+#endif
+}
+
+static u_long init_descr_ring(smc,start,count)
+struct s_smc *smc ;
+union s_fp_descr volatile *start;
+int count ;
+{
+	int i ;
+	union s_fp_descr volatile *d1 ;
+	union s_fp_descr volatile *d2 ;
+	u_long	phys ;
+
+	DB_GEN("descr ring starts at = %x ",(void *)start,0,3) ;
+	for (i=count-1, d1=start; i ; i--) {
+		d2 = d1 ;
+		d1++ ;		/* descr is owned by the host */
+		d2->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ;
+		d2->r.rxd_next = &d1->r ;
+		phys = mac_drv_virt2phys(smc,(void *)d1) ;
+		d2->r.rxd_nrdadr = AIX_REVERSE(phys) ;
+	}
+	DB_GEN("descr ring ends at = %x ",(void *)d1,0,3) ;
+	d1->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ;
+	d1->r.rxd_next = &start->r ;
+	phys = mac_drv_virt2phys(smc,(void *)start) ;
+	d1->r.rxd_nrdadr = AIX_REVERSE(phys) ;
+
+	for (i=count, d1=start; i ; i--) {
+		DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ;
+		d1++;
+	}
+	return(phys) ;
+}
+
+static void init_txd_ring(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_txd volatile *ds ;
+	struct s_smt_tx_queue *queue ;
+	u_long	phys ;
+
+	/*
+	 * initialize the transmit descriptors
+	 */
+	ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p +
+		SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ;
+	queue = smc->hw.fp.tx[QUEUE_A0] ;
+	DB_GEN("Init async TxD ring, %d TxDs ",HWM_ASYNC_TXD_COUNT,0,3) ;
+	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+		HWM_ASYNC_TXD_COUNT) ;
+	phys = AIX_REVERSE(ds->txd_ntdadr) ;
+	ds++ ;
+	queue->tx_curr_put = queue->tx_curr_get = ds ;
+	ds-- ;
+	queue->tx_free = HWM_ASYNC_TXD_COUNT ;
+	queue->tx_used = 0 ;
+	outpd(ADDR(B5_XA_DA),phys) ;
+
+	ds = (struct s_smt_fp_txd volatile *) ((char *)ds +
+		HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ;
+	queue = smc->hw.fp.tx[QUEUE_S] ;
+	DB_GEN("Init sync TxD ring, %d TxDs ",HWM_SYNC_TXD_COUNT,0,3) ;
+	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+		HWM_SYNC_TXD_COUNT) ;
+	phys = AIX_REVERSE(ds->txd_ntdadr) ;
+	ds++ ;
+	queue->tx_curr_put = queue->tx_curr_get = ds ;
+	queue->tx_free = HWM_SYNC_TXD_COUNT ;
+	queue->tx_used = 0 ;
+	outpd(ADDR(B5_XS_DA),phys) ;
+}
+
+static void init_rxd_ring(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_rxd volatile *ds ;
+	struct s_smt_rx_queue *queue ;
+	u_long	phys ;
+
+	/*
+	 * initialize the receive descriptors
+	 */
+	ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ;
+	queue = smc->hw.fp.rx[QUEUE_R1] ;
+	DB_GEN("Init RxD ring, %d RxDs ",SMT_R1_RXD_COUNT,0,3) ;
+	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+		SMT_R1_RXD_COUNT) ;
+	phys = AIX_REVERSE(ds->rxd_nrdadr) ;
+	ds++ ;
+	queue->rx_curr_put = queue->rx_curr_get = ds ;
+	queue->rx_free = SMT_R1_RXD_COUNT ;
+	queue->rx_used = 0 ;
+	outpd(ADDR(B4_R1_DA),phys) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(init_fddi_driver)
+ *	void init_fddi_driver(smc,mac_addr)
+ *
+ * initializes the driver and it's variables
+ *
+ *	END_MANUAL_ENTRY
+ */
+void init_fddi_driver(smc,mac_addr)
+struct	s_smc	*smc ;
+u_char		*mac_addr ;	/* canonical address */
+{
+	SMbuf	*mb ;
+	int	i ;
+
+	init_board(smc,mac_addr) ;
+	(void)init_fplus(smc) ;
+
+	/*
+	 * initialize the SMbufs for the SMT
+	 */
+#ifndef	COMMON_MB_POOL
+	mb = smc->os.hwm.mbuf_pool.mb_start ;
+	smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ;
+	for (i = 0; i < MAX_MBUF; i++) {
+		mb->sm_use_count = 1 ;
+		smt_free_mbuf(smc,mb)	;
+		mb++ ;
+	}
+#else
+	mb = mb_start ;
+	if (!mb_init) {
+		mb_free = 0 ;
+		for (i = 0; i < MAX_MBUF; i++) {
+			mb->sm_use_count = 1 ;
+			smt_free_mbuf(smc,mb)	;
+			mb++ ;
+		}
+		mb_init = TRUE ;
+	}
+#endif
+
+	/*
+	 * initialize the other variables
+	 */
+	smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ;
+	smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ;
+	smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ;
+	smc->os.hwm.pass_llc_promisc = TRUE ;
+	smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ;
+	smc->os.hwm.detec_count = 0 ;
+	smc->os.hwm.rx_break = 0 ;
+	smc->os.hwm.rx_len_error = 0 ;
+	smc->os.hwm.isr_flag = FALSE ;
+
+	/*
+	 * make sure that the start pointer is 16 byte aligned
+	 */
+	i = 16 - ((int)smc->os.hwm.descr_p & 0xf) ;
+	if (i != 16) {
+		DB_GEN("i = %d",i,0,3) ;
+		smc->os.hwm.descr_p = (union s_fp_descr volatile *)
+			((char *)smc->os.hwm.descr_p+i) ;
+	}
+	DB_GEN("pt to descr area = %x",(void *)smc->os.hwm.descr_p,0,3) ;
+
+	init_txd_ring(smc) ;
+	init_rxd_ring(smc) ;
+	mac_drv_fill_rxd(smc) ;
+
+	init_plc(smc) ;
+}
+
+
+SMbuf *smt_get_mbuf(smc)
+struct s_smc *smc ;
+{
+	register SMbuf	*mb ;
+
+#ifndef	COMMON_MB_POOL
+	mb = smc->os.hwm.mbuf_pool.mb_free ;
+#else
+	mb = mb_free ;
+#endif
+	if (mb) {
+#ifndef	COMMON_MB_POOL
+		smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ;
+#else
+		mb_free = mb->sm_next ;
+#endif
+		mb->sm_off = 8 ;
+		mb->sm_use_count = 1 ;
+	}
+	DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ;
+	return (mb) ;	/* May be NULL */
+}
+
+void smt_free_mbuf(smc, mb)
+struct s_smc	*smc ;
+SMbuf		*mb;
+{
+
+	if (mb) {
+		mb->sm_use_count-- ;
+		DB_GEN("free_mbuf: sm_use_count = %d",mb->sm_use_count,0,3) ;
+		/*
+		 * If the use_count is != zero the MBuf is queued
+		 * more than once and must not queued into the
+		 * free MBuf queue
+		 */
+		if (!mb->sm_use_count) {
+			DB_GEN("free SMbuf: mb = %x",(void *)mb,0,3) ;
+#ifndef	COMMON_MB_POOL
+			mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ;
+			smc->os.hwm.mbuf_pool.mb_free = mb ;
+#else
+			mb->sm_next = mb_free ;
+			mb_free = mb ;
+#endif
+		}
+	}
+	else
+		SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ;
+}
+
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_repair_descr)
+ *	void mac_drv_repair_descr(smc)
+ *
+ * function	called from SMT	(HWM / hwmtm.c)
+ *		The BMU is idle when this function is called.
+ *		Mac_drv_repair_descr sets up the physical address
+ *		for all receive and transmit queues where the BMU
+ *		should continue.
+ *		It may be that the BMU was reseted during a fragmented
+ *		transfer. In this case there are some fragments which will
+ *		never completed by the BMU. The OWN bit of this fragments
+ *		must be switched to be owned by the host.
+ *
+ *		Give a start command to the receive BMU.
+ *		Start the transmit BMUs if transmit frames pending.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_repair_descr(smc)
+struct s_smc *smc ;
+{
+	u_long	phys ;
+
+	if (smc->hw.hw_state != STOPPED) {
+		SK_BREAK() ;
+		SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ;
+		return ;
+	}
+
+	/*
+	 * repair tx queues: don't start
+	 */
+	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ;
+	outpd(ADDR(B5_XA_DA),phys) ;
+	if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) {
+		outpd(ADDR(B0_XA_CSR),CSR_START) ;
+	}
+	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ;
+	outpd(ADDR(B5_XS_DA),phys) ;
+	if (smc->hw.fp.tx_q[QUEUE_S].tx_used) {
+		outpd(ADDR(B0_XS_CSR),CSR_START) ;
+	}
+
+	/*
+	 * repair rx queues
+	 */
+	phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ;
+	outpd(ADDR(B4_R1_DA),phys) ;
+	outpd(ADDR(B0_R1_CSR),CSR_START) ;
+}
+
+static u_long repair_txd_ring(smc,queue)
+struct s_smc *smc ;
+struct s_smt_tx_queue *queue ;
+{
+	int i ;
+	int tx_used ;
+	u_long phys ;
+	u_long tbctrl ;
+	struct s_smt_fp_txd volatile *t ;
+
+	SK_UNUSED(smc) ;
+
+	t = queue->tx_curr_get ;
+	tx_used = queue->tx_used ;
+	for (i = tx_used+queue->tx_free-1 ; i ; i-- ) {
+		t = t->txd_next ;
+	}
+	phys = AIX_REVERSE(t->txd_ntdadr) ;
+
+	t = queue->tx_curr_get ;
+	while (tx_used) {
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
+		tbctrl = AIX_REVERSE(t->txd_tbctrl) ;
+
+		if (tbctrl & BMU_OWN) {
+			if (tbctrl & BMU_STF) {
+				break ;		/* exit the loop */
+			}
+			else {
+				/*
+				 * repair the descriptor
+				 */
+				t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			}
+		}
+		phys = AIX_REVERSE(t->txd_ntdadr) ;
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+		t = t->txd_next ;
+		tx_used-- ;
+	}
+	return(phys) ;
+}
+
+/*
+ * Repairs the receive descriptor ring and returns the physical address
+ * where the BMU should continue working.
+ *
+ *	o The physical address where the BMU was stopped has to be
+ *	  determined. This is the next RxD after rx_curr_get with an OWN
+ *	  bit set.
+ *	o The BMU should start working at beginning of the next frame.
+ *	  RxDs with an OWN bit set but with a reset STF bit should be
+ *	  skipped and owned by the driver (OWN = 0). 
+ */
+static u_long repair_rxd_ring(smc,queue)
+struct s_smc *smc ;
+struct s_smt_rx_queue *queue ;
+{
+	int i ;
+	int rx_used ;
+	u_long phys ;
+	u_long rbctrl ;
+	struct s_smt_fp_rxd volatile *r ;
+
+	SK_UNUSED(smc) ;
+
+	r = queue->rx_curr_get ;
+	rx_used = queue->rx_used ;
+	for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) {
+		r = r->rxd_next ;
+	}
+	phys = AIX_REVERSE(r->rxd_nrdadr) ;
+
+	r = queue->rx_curr_get ;
+	while (rx_used) {
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		rbctrl = AIX_REVERSE(r->rxd_rbctrl) ;
+
+		if (rbctrl & BMU_OWN) {
+			if (rbctrl & BMU_STF) {
+				break ;		/* exit the loop */
+			}
+			else {
+				/*
+				 * repair the descriptor
+				 */
+				r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			}
+		}
+		phys = AIX_REVERSE(r->rxd_nrdadr) ;
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+		r = r->rxd_next ;
+		rx_used-- ;
+	}
+	return(phys) ;
+}
+
+
+/*
+	-------------------------------------------------------------
+	INTERRUPT SERVICE ROUTINE:
+	-------------------------------------------------------------
+*/
+
+/*
+ *	BEGIN_MANUAL_ENTRY(fddi_isr)
+ *	void fddi_isr(smc)
+ *
+ * function	DOWNCALL	(drvsr.c)
+ *		interrupt service routine, handles the interrupt requests
+ *		generated by the FDDI adapter.
+ *
+ * NOTE:	The operating system dependent module must garantee that the
+ *		interrupts of the adapter are disabled when it calls fddi_isr.
+ *
+ *	About the USE_BREAK_ISR mechanismn:
+ *
+ *	The main requirement of this mechanismn is to force an timer IRQ when
+ *	leaving process_receive() with leave_isr set. process_receive() may
+ *	be called at any time from anywhere!
+ *	To be sure we don't miss such event we set 'force_irq' per default.
+ *	We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND
+ *	'force_irq' are set. 'force_irq' may be reset if a receive complete
+ *	IRQ is pending.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void fddi_isr(smc)
+struct s_smc *smc ;
+{
+	u_long		is ;		/* ISR source */
+	u_short		stu, stl ;
+	SMbuf		*mb ;
+
+#ifdef	USE_BREAK_ISR
+	int	force_irq ;
+#endif
+
+#ifdef	ODI2
+	if (smc->os.hwm.rx_break) {
+		mac_drv_fill_rxd(smc) ;
+		if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) {
+			smc->os.hwm.rx_break = 0 ;
+			process_receive(smc) ;
+		}
+		else {
+			smc->os.hwm.detec_count = 0 ;
+			smt_force_irq(smc) ;
+		}
+	}
+#endif
+	smc->os.hwm.isr_flag = TRUE ;
+
+#ifdef	USE_BREAK_ISR
+	force_irq = TRUE ;
+	if (smc->os.hwm.leave_isr) {
+		smc->os.hwm.leave_isr = FALSE ;
+		process_receive(smc) ;
+	}
+#endif
+
+	while ((is = GET_ISR() & ISR_MASK)) {
+		NDD_TRACE("CH0B",is,0,0) ;
+		DB_GEN("ISA = 0x%x",is,0,7) ;
+
+		if (is & IMASK_SLOW) {
+			NDD_TRACE("CH1b",is,0,0) ;
+			if (is & IS_PLINT1) {	/* PLC1 */
+				plc1_irq(smc) ;
+			}
+			if (is & IS_PLINT2) {	/* PLC2 */
+				plc2_irq(smc) ;
+			}
+			if (is & IS_MINTR1) {	/* FORMAC+ STU1(U/L) */
+				stu = inpw(FM_A(FM_ST1U)) ;
+				stl = inpw(FM_A(FM_ST1L)) ;
+				DB_GEN("Slow transmit complete",0,0,6) ;
+				mac1_irq(smc,stu,stl) ;
+			}
+			if (is & IS_MINTR2) {	/* FORMAC+ STU2(U/L) */
+				stu= inpw(FM_A(FM_ST2U)) ;
+				stl= inpw(FM_A(FM_ST2L)) ;
+				DB_GEN("Slow receive complete",0,0,6) ;
+				DB_GEN("stl = %x : stu = %x",stl,stu,7) ;
+				mac2_irq(smc,stu,stl) ;
+			}
+			if (is & IS_MINTR3) {	/* FORMAC+ STU3(U/L) */
+				stu= inpw(FM_A(FM_ST3U)) ;
+				stl= inpw(FM_A(FM_ST3L)) ;
+				DB_GEN("FORMAC Mode Register 3",0,0,6) ;
+				mac3_irq(smc,stu,stl) ;
+			}
+			if (is & IS_TIMINT) {	/* Timer 82C54-2 */
+				timer_irq(smc) ;
+#ifdef	NDIS_OS2
+				force_irq_pending = 0 ;
+#endif
+				/*
+				 * out of RxD detection
+				 */
+				if (++smc->os.hwm.detec_count > 4) {
+					/*
+					 * check out of RxD condition
+					 */
+					 process_receive(smc) ;
+				}
+			}
+			if (is & IS_TOKEN) {	/* Restricted Token Monitor */
+				rtm_irq(smc) ;
+			}
+			if (is & IS_R1_P) {	/* Parity error rx queue 1 */
+				/* clear IRQ */
+				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ;
+				SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ;
+			}
+			if (is & IS_R1_C) {	/* Encoding error rx queue 1 */
+				/* clear IRQ */
+				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ;
+				SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ;
+			}
+			if (is & IS_XA_C) {	/* Encoding error async tx q */
+				/* clear IRQ */
+				outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ;
+				SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ;
+			}
+			if (is & IS_XS_C) {	/* Encoding error sync tx q */
+				/* clear IRQ */
+				outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ;
+				SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ;
+			}
+		}
+
+		/*
+		 *	Fast Tx complete Async/Sync Queue (BMU service)
+		 */
+		if (is & (IS_XS_F|IS_XA_F)) {
+			DB_GEN("Fast tx complete queue",0,0,6) ;
+			/*
+			 * clear IRQ, Note: no IRQ is lost, because
+			 * 	we always service both queues
+			 */
+			outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ;
+			outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ;
+			mac_drv_clear_txd(smc) ;
+			llc_restart_tx(smc) ;
+		}
+
+		/*
+		 *	Fast Rx Complete (BMU service)
+		 */
+		if (is & IS_R1_F) {
+			DB_GEN("Fast receive complete",0,0,6) ;
+			/* clear IRQ */
+#ifndef USE_BREAK_ISR
+			outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
+			process_receive(smc) ;
+#else
+			process_receive(smc) ;
+			if (smc->os.hwm.leave_isr) {
+				force_irq = FALSE ;
+			} else {
+				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
+				process_receive(smc) ;
+			}
+#endif
+		}
+
+#ifndef	NDIS_OS2
+		while ((mb = get_llc_rx(smc))) {
+			smt_to_llc(smc,mb) ;
+		}
+#else
+		if (offDepth)
+			post_proc() ;
+
+		while (!offDepth && (mb = get_llc_rx(smc))) {
+			smt_to_llc(smc,mb) ;
+		}
+
+		if (!offDepth && smc->os.hwm.rx_break) {
+			process_receive(smc) ;
+		}
+#endif
+		if (smc->q.ev_get != smc->q.ev_put) {
+			NDD_TRACE("CH2a",0,0,0) ;
+			ev_dispatcher(smc) ;
+		}
+#ifdef	NDIS_OS2
+		post_proc() ;
+		if (offDepth) {		/* leave fddi_isr because */
+			break ;		/* indications not allowed */
+		}
+#endif
+#ifdef	USE_BREAK_ISR
+		if (smc->os.hwm.leave_isr) {
+			break ;		/* leave fddi_isr */
+		}
+#endif
+
+		/* NOTE: when the isr is left, no rx is pending */
+	}	/* end of interrupt source polling loop */
+
+#ifdef	USE_BREAK_ISR
+	if (smc->os.hwm.leave_isr && force_irq) {
+		smt_force_irq(smc) ;
+	}
+#endif
+	smc->os.hwm.isr_flag = FALSE ;
+	NDD_TRACE("CH0E",0,0,0) ;
+}
+
+
+/*
+	-------------------------------------------------------------
+	RECEIVE FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+#ifndef	NDIS_OS2
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_rx_mode)
+ *	void mac_drv_rx_mode(smc,mode)
+ *
+ * function	DOWNCALL	(fplus.c)
+ *		Corresponding to the parameter mode, the operating system
+ *		dependent module can activate several receive modes.
+ *
+ * para	mode	= 1:	RX_ENABLE_ALLMULTI	enable all multicasts
+ *		= 2:	RX_DISABLE_ALLMULTI	disable "enable all multicasts"
+ *		= 3:	RX_ENABLE_PROMISC	enable promiscuous
+ *		= 4:	RX_DISABLE_PROMISC	disable promiscuous
+ *		= 5:	RX_ENABLE_NSA		enable rec. of all NSA frames
+ *			(disabled after 'driver reset' & 'set station address')
+ *		= 6:	RX_DISABLE_NSA		disable rec. of all NSA frames
+ *
+ *		= 21:	RX_ENABLE_PASS_SMT	( see description )
+ *		= 22:	RX_DISABLE_PASS_SMT	(  "	   "	  )
+ *		= 23:	RX_ENABLE_PASS_NSA	(  "	   "	  )
+ *		= 24:	RX_DISABLE_PASS_NSA	(  "	   "	  )
+ *		= 25:	RX_ENABLE_PASS_DB	(  "	   "	  )
+ *		= 26:	RX_DISABLE_PASS_DB	(  "	   "	  )
+ *		= 27:	RX_DISABLE_PASS_ALL	(  "	   "	  )
+ *		= 28:	RX_DISABLE_LLC_PROMISC	(  "	   "	  )
+ *		= 29:	RX_ENABLE_LLC_PROMISC	(  "	   "	  )
+ *
+ *
+ *		RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT
+ *
+ *		If the operating system dependent module activates the
+ *		mode RX_ENABLE_PASS_SMT, the hardware module
+ *		duplicates all SMT frames with the frame control
+ *		FC_SMT_INFO and passes them to the LLC receive channel
+ *		by calling mac_drv_rx_init.
+ *		The SMT Frames which are sent by the local SMT and the NSA
+ *		frames whose A- and C-Indicator is not set are also duplicated
+ *		and passed.
+ *		The receive mode RX_DISABLE_PASS_SMT disables the passing
+ *		of SMT frames.
+ *
+ *		RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA
+ *
+ *		If the operating system dependent module activates the
+ *		mode RX_ENABLE_PASS_NSA, the hardware module
+ *		duplicates all NSA frames with frame control FC_SMT_NSA
+ *		and a set A-Indicator and passed them to the LLC
+ *		receive channel by calling mac_drv_rx_init.
+ *		All NSA Frames which are sent by the local SMT
+ *		are also duplicated and passed.
+ *		The receive mode RX_DISABLE_PASS_NSA disables the passing
+ *		of NSA frames with the A- or C-Indicator set.
+ *
+ * NOTE:	For fear that the hardware module receives NSA frames with
+ *		a reset A-Indicator, the operating system dependent module
+ *		has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA
+ *		before activate the RX_ENABLE_PASS_NSA mode and after every
+ *		'driver reset' and 'set station address'.
+ *
+ *		RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB
+ *
+ *		If the operating system dependent module activates the
+ *		mode RX_ENABLE_PASS_DB, direct BEACON frames
+ *		(FC_BEACON frame control) are passed to the LLC receive
+ *		channel by mac_drv_rx_init.
+ *		The receive mode RX_DISABLE_PASS_DB disables the passing
+ *		of direct BEACON frames.
+ *
+ *		RX_DISABLE_PASS_ALL
+ *
+ *		Disables all special receives modes. It is equal to
+ *		call mac_drv_set_rx_mode successively with the
+ *		parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT,
+ *		RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB.
+ *
+ *		RX_ENABLE_LLC_PROMISC
+ *
+ *		(default) all received LLC frames and all SMT/NSA/DBEACON
+ *		frames depending on the attitude of the flags
+ *		PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the
+ *		LLC layer
+ *
+ *		RX_DISABLE_LLC_PROMISC
+ *
+ *		all received SMT/NSA/DBEACON frames depending on the
+ *		attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON
+ *		will be delivered to the LLC layer.
+ *		all received LLC frames with a directed address, Multicast
+ *		or Broadcast address will be delivered to the LLC
+ *		layer too.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_rx_mode(smc,mode)
+struct s_smc *smc ;
+int mode ;
+{
+	switch(mode) {
+	case RX_ENABLE_PASS_SMT:
+		smc->os.hwm.pass_SMT = TRUE ;
+		break ;
+	case RX_DISABLE_PASS_SMT:
+		smc->os.hwm.pass_SMT = FALSE ;
+		break ;
+	case RX_ENABLE_PASS_NSA:
+		smc->os.hwm.pass_NSA = TRUE ;
+		break ;
+	case RX_DISABLE_PASS_NSA:
+		smc->os.hwm.pass_NSA = FALSE ;
+		break ;
+	case RX_ENABLE_PASS_DB:
+		smc->os.hwm.pass_DB = TRUE ;
+		break ;
+	case RX_DISABLE_PASS_DB:
+		smc->os.hwm.pass_DB = FALSE ;
+		break ;
+	case RX_DISABLE_PASS_ALL:
+		smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ;
+		smc->os.hwm.pass_DB = FALSE ;
+		smc->os.hwm.pass_llc_promisc = TRUE ;
+		mac_set_rx_mode(smc,RX_DISABLE_NSA) ;
+		break ;
+	case RX_DISABLE_LLC_PROMISC:
+		smc->os.hwm.pass_llc_promisc = FALSE ;
+		break ;
+	case RX_ENABLE_LLC_PROMISC:
+		smc->os.hwm.pass_llc_promisc = TRUE ;
+		break ;
+	case RX_ENABLE_ALLMULTI:
+	case RX_DISABLE_ALLMULTI:
+	case RX_ENABLE_PROMISC:
+	case RX_DISABLE_PROMISC:
+	case RX_ENABLE_NSA:
+	case RX_DISABLE_NSA:
+	default:
+		mac_set_rx_mode(smc,mode) ;
+		break ;
+	}
+}
+#endif	/* ifndef NDIS_OS2 */
+
+/*
+ * process receive queue
+ */
+void process_receive(smc)
+struct s_smc *smc ;
+{
+	int i ;
+	int n ;
+	int frag_count ;		/* number of RxDs of the curr rx buf */
+	int used_frags ;		/* number of RxDs of the curr frame */
+	struct s_smt_rx_queue *queue ;	/* points to the queue ctl struct */
+	struct s_smt_fp_rxd volatile *r ;	/* rxd pointer */
+	struct s_smt_fp_rxd volatile *rxd ;	/* first rxd of rx frame */
+	u_long rbctrl ;			/* receive buffer control word */
+	u_long rfsw ;			/* receive frame status word */
+	u_short rx_used ;
+	u_char far *virt ;
+	char far *data ;
+	SMbuf *mb ;
+	u_char fc ;			/* Frame control */
+	int len ;			/* Frame length */
+
+	smc->os.hwm.detec_count = 0 ;
+	queue = smc->hw.fp.rx[QUEUE_R1] ;
+	NDD_TRACE("RHxB",0,0,0) ;
+	for ( ; ; ) {
+		r = queue->rx_curr_get ;
+		rx_used = queue->rx_used ;
+		frag_count = 0 ;
+
+#ifdef	USE_BREAK_ISR
+		if (smc->os.hwm.leave_isr) {
+			goto rx_end ;
+		}
+#endif
+#ifdef	NDIS_OS2
+		if (offDepth) {
+			smc->os.hwm.rx_break = 1 ;
+			goto rx_end ;
+		}
+		smc->os.hwm.rx_break = 0 ;
+#endif
+#ifdef	ODI2
+		if (smc->os.hwm.rx_break) {
+			goto rx_end ;
+		}
+#endif
+		n = 0 ;
+		do {
+			DB_RX("Check RxD %x for OWN and EOF",(void *)r,0,5) ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+			rbctrl = CR_READ(r->rxd_rbctrl) ;
+#ifdef	AIX
+			rbctrl = AIX_REVERSE(rbctrl) ;
+#endif
+			if (rbctrl & BMU_OWN) {
+				NDD_TRACE("RHxE",r,rfsw,rbctrl) ;
+				DB_RX("End of RxDs",0,0,4) ;
+				goto rx_end ;
+			}
+			/*
+			 * out of RxD detection
+			 */
+			if (!rx_used) {
+				SK_BREAK() ;
+				SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ;
+				/* Either we don't have an RxD or all
+				 * RxDs are filled. Therefore it's allowed
+				 * for to set the STOPPED flag */
+				smc->hw.hw_state = STOPPED ;
+				mac_drv_clear_rx_queue(smc) ;
+				smc->hw.hw_state = STARTED ;
+				mac_drv_fill_rxd(smc) ;
+				smc->os.hwm.detec_count = 0 ;
+				goto rx_end ;
+			}
+			rfsw = AIX_REVERSE(r->rxd_rfsw) ;
+			if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) {
+				/*
+				 * The BMU_STF bit is deleted, 1 frame is
+				 * placed into more than 1 rx buffer
+				 *
+				 * skip frame by setting the rx len to 0
+				 *
+				 * if fragment count == 0
+				 *	The missing STF bit belongs to the
+				 *	current frame, search for the
+				 *	EOF bit to complete the frame
+				 * else
+				 *	the fragment belongs to the next frame,
+				 *	exit the loop and process the frame
+				 */
+				SK_BREAK() ;
+				rfsw = 0 ;
+				if (frag_count) {
+					break ;
+				}
+			}
+			n += rbctrl & 0xffff ;
+			r = r->rxd_next ;
+			frag_count++ ;
+			rx_used-- ;
+		} while (!(rbctrl & BMU_EOF)) ;
+		used_frags = frag_count ;
+		DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ;
+
+		/* may be next 2 DRV_BUF_FLUSH() can be skipped, because */
+		/* BMU_ST_BUF will not be changed by the ASIC */
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		while (rx_used && !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) {
+			DB_RX("Check STF bit in %x",(void *)r,0,5) ;
+			r = r->rxd_next ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+			frag_count++ ;
+			rx_used-- ;
+		}
+		DB_RX("STF bit found",0,0,5) ;
+
+		/*
+		 * The received frame is finished for the process receive
+		 */
+		rxd = queue->rx_curr_get ;
+		queue->rx_curr_get = r ;
+		queue->rx_free += frag_count ;
+		queue->rx_used = rx_used ;
+
+		/*
+		 * ASIC Errata no. 7 (STF - Bit Bug)
+		 */
+		rxd->rxd_rbctrl &= AIX_REVERSE(~BMU_STF) ;
+
+		for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){
+			DB_RX("dma_complete for RxD %x",(void *)r,0,5) ;
+			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
+		}
+		smc->hw.fp.err_stats.err_valid++ ;
+		smc->mib.m[MAC0].fddiMACCopied_Ct++ ;
+
+		/* the length of the data including the FC */
+		len = (rfsw & RD_LENGTH) - 4 ;
+
+		DB_RX("frame length = %d",len,0,4) ;
+		/*
+		 * check the frame_lenght and all error flags
+		 */
+		if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){
+			if (rfsw & RD_S_MSRABT) {
+				DB_RX("Frame aborted by the FORMAC",0,0,2) ;
+				smc->hw.fp.err_stats.err_abort++ ;
+			}
+			/*
+			 * check frame status
+			 */
+			if (rfsw & RD_S_SEAC2) {
+				DB_RX("E-Indicator set",0,0,2) ;
+				smc->hw.fp.err_stats.err_e_indicator++ ;
+			}
+			if (rfsw & RD_S_SFRMERR) {
+				DB_RX("CRC error",0,0,2) ;
+				smc->hw.fp.err_stats.err_crc++ ;
+			}
+			if (rfsw & RX_FS_IMPL) {
+				DB_RX("Implementer frame",0,0,2) ;
+				smc->hw.fp.err_stats.err_imp_frame++ ;
+			}
+			goto abort_frame ;
+		}
+		if (len > FDDI_RAW_MTU-4) {
+			DB_RX("Frame to long error",0,0,2) ;
+			smc->hw.fp.err_stats.err_too_long++ ;
+			goto abort_frame ;
+		}
+		/*
+		 * SUPERNET 3 Bug: FORMAC delivers status words
+		 * of aborded frames to the BMU
+		 */
+		if (len <= 4) {
+			DB_RX("Frame length = 0",0,0,2) ;
+			goto abort_frame ;
+		}
+
+		if (len != (n-4)) {
+			DB_RX("BMU: rx len differs: [%d:%d]",len,n,4);
+			smc->os.hwm.rx_len_error++ ;
+			goto abort_frame ;
+		}
+
+		/*
+		 * Check SA == MA
+		 */
+		virt = (u_char far *) rxd->rxd_virt ;
+		DB_RX("FC = %x",*virt,0,2) ;
+		if (virt[12] == MA[5] &&
+		    virt[11] == MA[4] &&
+		    virt[10] == MA[3] &&
+		    virt[9] == MA[2] &&
+		    virt[8] == MA[1] &&
+		    (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) {
+			goto abort_frame ;
+		}
+
+		/*
+		 * test if LLC frame
+		 */
+		if (rfsw & RX_FS_LLC) {
+			/*
+			 * if pass_llc_promisc is disable
+			 *	if DA != Multicast or Broadcast or DA!=MA
+			 *		abort the frame
+			 */
+			if (!smc->os.hwm.pass_llc_promisc) {
+				if(!(virt[1] & GROUP_ADDR_BIT)) {
+					if (virt[6] != MA[5] ||
+					    virt[5] != MA[4] ||
+					    virt[4] != MA[3] ||
+					    virt[3] != MA[2] ||
+					    virt[2] != MA[1] ||
+					    virt[1] != MA[0]) {
+						DB_RX("DA != MA and not multi- or broadcast",0,0,2) ;
+						goto abort_frame ;
+					}
+				}
+			}
+
+			/*
+			 * LLC frame received
+			 */
+			DB_RX("LLC - receive",0,0,4) ;
+			mac_drv_rx_complete(smc,rxd,frag_count,len) ;
+		}
+		else {
+			if (!(mb = smt_get_mbuf(smc))) {
+				smc->hw.fp.err_stats.err_no_buf++ ;
+				DB_RX("No SMbuf; receive terminated",0,0,4) ;
+				goto abort_frame ;
+			}
+			data = smtod(mb,char *) - 1 ;
+
+			/*
+			 * copy the frame into a SMT_MBuf
+			 */
+#ifdef USE_OS_CPY
+			hwm_cpy_rxd2mb(rxd,data,len) ;
+#else
+			for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){
+				n = AIX_REVERSE(r->rxd_rbctrl) & RD_LENGTH ;
+				DB_RX("cp SMT frame to mb: len = %d",n,0,6) ;
+				memcpy(data,r->rxd_virt,n) ;
+				data += n ;
+			}
+			data = smtod(mb,char *) - 1 ;
+#endif
+			fc = *(char *)mb->sm_data = *data ;
+			mb->sm_len = len - 1 ;		/* len - fc */
+			data++ ;
+
+			/*
+			 * SMT frame received
+			 */
+			switch(fc) {
+			case FC_SMT_INFO :
+				smc->hw.fp.err_stats.err_smt_frame++ ;
+				DB_RX("SMT frame received ",0,0,5) ;
+
+				if (smc->os.hwm.pass_SMT) {
+					DB_RX("pass SMT frame ",0,0,5) ;
+					mac_drv_rx_complete(smc, rxd,
+						frag_count,len) ;
+				}
+				else {
+					DB_RX("requeue RxD",0,0,5) ;
+					mac_drv_requeue_rxd(smc,rxd,frag_count);
+				}
+
+				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
+				break ;
+			case FC_SMT_NSA :
+				smc->hw.fp.err_stats.err_smt_frame++ ;
+				DB_RX("SMT frame received ",0,0,5) ;
+
+				/* if pass_NSA set pass the NSA frame or */
+				/* pass_SMT set and the A-Indicator */
+				/* is not set, pass the NSA frame */
+				if (smc->os.hwm.pass_NSA ||
+					(smc->os.hwm.pass_SMT &&
+					!(rfsw & A_INDIC))) {
+					DB_RX("pass SMT frame ",0,0,5) ;
+					mac_drv_rx_complete(smc, rxd,
+						frag_count,len) ;
+				}
+				else {
+					DB_RX("requeue RxD",0,0,5) ;
+					mac_drv_requeue_rxd(smc,rxd,frag_count);
+				}
+
+				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
+				break ;
+			case FC_BEACON :
+				if (smc->os.hwm.pass_DB) {
+					DB_RX("pass DB frame ",0,0,5) ;
+					mac_drv_rx_complete(smc, rxd,
+						frag_count,len) ;
+				}
+				else {
+					DB_RX("requeue RxD",0,0,5) ;
+					mac_drv_requeue_rxd(smc,rxd,frag_count);
+				}
+				smt_free_mbuf(smc,mb) ;
+				break ;
+			default :
+				/*
+				 * unknown FC abord the frame
+				 */
+				DB_RX("unknown FC error",0,0,2) ;
+				smt_free_mbuf(smc,mb) ;
+				DB_RX("requeue RxD",0,0,5) ;
+				mac_drv_requeue_rxd(smc,rxd,frag_count) ;
+				if ((fc & 0xf0) == FC_MAC)
+					smc->hw.fp.err_stats.err_mac_frame++ ;
+				else
+					smc->hw.fp.err_stats.err_imp_frame++ ;
+
+				break ;
+			}
+		}
+
+		DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ;
+		NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ;
+
+		continue ;
+	/*--------------------------------------------------------------------*/
+abort_frame:
+		DB_RX("requeue RxD",0,0,5) ;
+		mac_drv_requeue_rxd(smc,rxd,frag_count) ;
+
+		DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ;
+		NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ;
+	}
+rx_end:
+#ifdef	ALL_RX_COMPLETE
+	mac_drv_all_receives_complete(smc) ;
+#endif
+	return ;	/* lint bug: needs return detect end of function */
+}
+
+static void smt_to_llc(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+	u_char	fc ;
+
+	DB_RX("send a queued frame to the llc layer",0,0,4) ;
+	smc->os.hwm.r.len = mb->sm_len ;
+	smc->os.hwm.r.mb_pos = smtod(mb,char *) ;
+	fc = *smc->os.hwm.r.mb_pos ;
+	(void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc,
+		smc->os.hwm.r.mb_pos,(int)mb->sm_len) ;
+	smt_free_mbuf(smc,mb) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(hwm_rx_frag)
+ *	void hwm_rx_frag(smc,virt,phys,len,frame_status)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This function calls dma_master for preparing the
+ *		system hardware for the DMA transfer and initializes
+ *		the current RxD with the length and the physical and
+ *		virtual address of the fragment. Furthermore, it sets the
+ *		STF and EOF bits depending on the frame status byte,
+ *		switches the OWN flag of the RxD, so that it is owned by the
+ *		adapter and issues an rx_start.
+ *
+ * para	virt	virtual pointer to the fragment
+ *	len	the length of the fragment
+ *	frame_status	status of the frame, see design description
+ *
+ * NOTE:	It is possible to call this function with a fragment length
+ *		of zero.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void hwm_rx_frag(smc,virt,phys,len,frame_status)
+struct s_smc *smc ;
+char far *virt ;
+u_long phys ;
+int len ;
+int frame_status ;
+{
+	struct s_smt_fp_rxd volatile *r ;
+#ifdef	AIX
+	u_long	rbctrl ;
+#endif
+
+	NDD_TRACE("RHfB",virt,len,frame_status) ;
+	DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ;
+	r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ;
+	r->rxd_virt = virt ;
+	r->rxd_rbadr = AIX_REVERSE(phys) ;
+#ifndef	AIX
+	r->rxd_rbctrl = (((u_long)frame_status & (FIRST_FRAG|LAST_FRAG))<<26) |
+		(((u_long) frame_status & FIRST_FRAG) << 21) |
+		BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len ;
+#else
+	rbctrl = AIX_REVERSE( (((u_long)frame_status &
+		(FIRST_FRAG|LAST_FRAG))<<26) |
+		(((u_long) frame_status & FIRST_FRAG) << 21) |
+		BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ;
+	r->rxd_rbctrl = rbctrl ;
+#endif
+	DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+	outpd(ADDR(B0_R1_CSR),CSR_START) ;
+	smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ;
+	smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ;
+	smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ;
+	NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
+}
+
+#ifndef	NDIS_OS2
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
+ *	int mac_drv_rx_frag(smc,virt,len)
+ *
+ * function	DOWNCALL	(hwmtm.c)
+ *		mac_drv_rx_frag fills the fragment with a part of the frame.
+ *
+ * para	virt	the virtual address of the fragment
+ *	len	the length in bytes of the fragment
+ *
+ * return 0:	success code, no errors possible
+ *
+ *	END_MANUAL_ENTRY
+ */
+int mac_drv_rx_frag(smc,virt,len)
+struct s_smc *smc ;
+void far *virt ;
+int len ;
+{
+	NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
+
+	DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
+	memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
+	smc->os.hwm.r.mb_pos += len ;
+
+	NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
+	return(0) ;
+}
+#endif
+
+
+/*
+ *	BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
+ *
+ * void mac_drv_clear_rx_queue(smc)
+ * struct s_smc *smc ;
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		mac_drv_clear_rx_queue is called by the OS-specific module
+ *		after it has issued a card_stop.
+ *		In this case, the frames in the receive queue are obsolete and
+ *		should be removed. For removing mac_drv_clear_rx_queue
+ *		calls dma_master for each RxD and mac_drv_clear_rxd for each
+ *		receive buffer.
+ *
+ * NOTE:	calling sequence card_stop:
+ *		CLI_FBI(), card_stop(),
+ *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
+ *
+ * NOTE:	The caller is responsible that the BMUs are idle
+ *		when this function is called.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_clear_rx_queue(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_rxd volatile *r ;
+	struct s_smt_fp_rxd volatile *next_rxd ;
+	struct s_smt_rx_queue *queue ;
+	int frag_count ;
+	int i ;
+
+	if (smc->hw.hw_state != STOPPED) {
+		SK_BREAK() ;
+		SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ;
+		return ;
+	}
+
+	queue = smc->hw.fp.rx[QUEUE_R1] ;
+	DB_RX("clear_rx_queue",0,0,5) ;
+
+	/*
+	 * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers
+	 */
+	r = queue->rx_curr_get ;
+	while (queue->rx_used) {
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ;
+		r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+		frag_count = 1 ;
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+		r = r->rxd_next ;
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		while (r != queue->rx_curr_put &&
+			!(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) {
+			DB_RX("Check STF bit in %x",(void *)r,0,5) ;
+			r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+			r = r->rxd_next ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+			frag_count++ ;
+		}
+		DB_RX("STF bit found",0,0,5) ;
+		next_rxd = r ;
+
+		for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){
+			DB_RX("dma_complete for RxD %x",(void *)r,0,5) ;
+			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
+		}
+
+		DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ",
+			(void *)queue->rx_curr_get,frag_count,5) ;
+		mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ;
+
+		queue->rx_curr_get = next_rxd ;
+		queue->rx_used -= frag_count ;
+		queue->rx_free += frag_count ;
+	}
+}
+
+
+/*
+	-------------------------------------------------------------
+	SEND FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+/*
+ *	BEGIN_MANUAL_ENTRY(hwm_tx_init)
+ *	int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
+ *
+ * function	DOWN_CALL	(hardware module, hwmtm.c)
+ *		hwm_tx_init checks if the frame can be sent through the
+ *		corresponding send queue.
+ *
+ * para	fc	the frame control. To determine through which
+ *		send queue the frame should be transmitted.
+ *		0x50 - 0x57:	asynchronous LLC frame
+ *		0xD0 - 0xD7:	synchronous LLC frame
+ *		0x41, 0x4F:	SMT frame to the network
+ *		0x42:		SMT frame to the network and to the local SMT
+ *		0x43:		SMT frame to the local SMT
+ *	frag_count	count of the fragments for this frame
+ *	frame_len	length of the frame
+ *	frame_status	status of the frame, the send queue bit is already
+ *			specified
+ *
+ * return		frame_status
+ *
+ *	END_MANUAL_ENTRY
+ */
+int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
+struct	s_smc *smc ;
+u_char fc ;
+int frag_count ;
+int frame_len ;
+int frame_status ;
+{
+	NDD_TRACE("THiB",fc,frag_count,frame_len) ;
+	smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ;
+	smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ;
+	smc->os.hwm.tx_len = frame_len ;
+	DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ;
+	if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
+		frame_status |= LAN_TX ;
+	}
+	else {
+		switch (fc) {
+		case FC_SMT_INFO :
+		case FC_SMT_NSA :
+			frame_status |= LAN_TX ;
+			break ;
+		case FC_SMT_LOC :
+			frame_status |= LOC_TX ;
+			break ;
+		case FC_SMT_LAN_LOC :
+			frame_status |= LAN_TX | LOC_TX ;
+			break ;
+		default :
+			SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ;
+		}
+	}
+	if (!smc->hw.mac_ring_is_up) {
+		frame_status &= ~LAN_TX ;
+		frame_status |= RING_DOWN ;
+		DB_TX("Ring is down: terminate LAN_TX",0,0,2) ;
+	}
+	if (frag_count > smc->os.hwm.tx_p->tx_free) {
+#ifndef	NDIS_OS2
+		mac_drv_clear_txd(smc) ;
+		if (frag_count > smc->os.hwm.tx_p->tx_free) {
+			DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ;
+			frame_status &= ~LAN_TX ;
+			frame_status |= OUT_OF_TXD ;
+		}
+#else
+		DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ;
+		frame_status &= ~LAN_TX ;
+		frame_status |= OUT_OF_TXD ;
+#endif
+	}
+	DB_TX("frame_status = %x",frame_status,0,3) ;
+	NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ;
+	return(frame_status) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(hwm_tx_frag)
+ *	void hwm_tx_frag(smc,virt,phys,len,frame_status)
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		If the frame should be sent to the LAN, this function calls
+ *		dma_master, fills the current TxD with the virtual and the
+ *		physical address, sets the STF and EOF bits dependent on
+ *		the frame status, and requests the BMU to start the
+ *		transmit.
+ *		If the frame should be sent to the local SMT, an SMT_MBuf
+ *		is allocated if the FIRST_FRAG bit is set in the frame_status.
+ *		The fragment of the frame is copied into the SMT MBuf.
+ *		The function smt_received_pack is called if the LAST_FRAG
+ *		bit is set in the frame_status word.
+ *
+ * para	virt	virtual pointer to the fragment
+ *	len	the length of the fragment
+ *	frame_status	status of the frame, see design description
+ *
+ * return	nothing returned, no parameter is modified
+ *
+ * NOTE:	It is possible to invoke this macro with a fragment length
+ *		of zero.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void hwm_tx_frag(smc,virt,phys,len,frame_status)
+struct	s_smc *smc ;
+char far *virt ;
+u_long phys ;
+int len ;
+int frame_status ;
+{
+	struct s_smt_fp_txd volatile *t ;
+	struct s_smt_tx_queue *queue ;
+#ifdef	AIX
+	u_long	tbctrl ;
+#endif
+
+	queue = smc->os.hwm.tx_p ;
+
+	NDD_TRACE("THfB",virt,len,frame_status) ;
+	/* Bug fix: AF / May 31 1999 (#missing)
+	 * snmpinfo problem reported by IBM is caused by invalid
+	 * t-pointer (txd) if LAN_TX is not set but LOC_TX only.
+	 * Set: t = queue->tx_curr_put  here !
+	 */
+	t = queue->tx_curr_put ;
+
+	DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ;
+	if (frame_status & LAN_TX) {
+		/* '*t' is already defined */
+		DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ;
+		t->txd_virt = virt ;
+		t->txd_txdscr = AIX_REVERSE(smc->os.hwm.tx_descr) ;
+		t->txd_tbadr = AIX_REVERSE(phys) ;
+#ifndef	AIX
+		t->txd_tbctrl = (((u_long)frame_status &
+			(FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) |
+			BMU_OWN|BMU_CHECK |len ;
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+		outpd(queue->tx_bmu_ctl,CSR_START) ;
+
+#else	/* ifndef AIX */
+		tbctrl = AIX_REVERSE((((u_long)frame_status &
+			(FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) |
+			BMU_OWN|BMU_CHECK |len) ;
+		t->txd_tbctrl = tbctrl ;
+
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+		if (frame_status & QUEUE_A0) {
+			outpd(ADDR(B0_XA_CSR),CSR_START) ;
+		}
+		else {
+			outpd(ADDR(B0_XS_CSR),CSR_START) ;
+		}
+#endif
+		queue->tx_free-- ;
+		queue->tx_used++ ;
+		queue->tx_curr_put = t->txd_next ;
+		if (frame_status & LAST_FRAG) {
+			smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
+		}
+	}
+	if (frame_status & LOC_TX) {
+		DB_TX("LOC_TX: ",0,0,3) ;
+		if (frame_status & FIRST_FRAG) {
+			if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) {
+				smc->hw.fp.err_stats.err_no_buf++ ;
+				DB_TX("No SMbuf; transmit terminated",0,0,4) ;
+			}
+			else {
+				smc->os.hwm.tx_data =
+					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
+#ifdef USE_OS_CPY
+#ifdef PASS_1ST_TXD_2_TX_COMP
+				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
+					smc->os.hwm.tx_len) ;
+#endif
+#endif
+			}
+		}
+		if (smc->os.hwm.tx_mb) {
+#ifndef	USE_OS_CPY
+			DB_TX("copy fragment into MBuf ",0,0,3) ;
+			memcpy(smc->os.hwm.tx_data,virt,len) ;
+			smc->os.hwm.tx_data += len ;
+#endif
+			if (frame_status & LAST_FRAG) {
+#ifdef	USE_OS_CPY
+#ifndef PASS_1ST_TXD_2_TX_COMP
+				/*
+				 * hwm_cpy_txd2mb(txd,data,len) copies 'len' 
+				 * bytes from the virtual pointer in 'rxd'
+				 * to 'data'. The virtual pointer of the 
+				 * os-specific tx-buffer should be written
+				 * in the LAST txd.
+				 */ 
+				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
+					smc->os.hwm.tx_len) ;
+#endif	/* nPASS_1ST_TXD_2_TX_COMP */
+#endif	/* USE_OS_CPY */
+				smc->os.hwm.tx_data =
+					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
+				*(char *)smc->os.hwm.tx_mb->sm_data =
+					*smc->os.hwm.tx_data ;
+				smc->os.hwm.tx_data++ ;
+				smc->os.hwm.tx_mb->sm_len =
+					smc->os.hwm.tx_len - 1 ;
+				DB_TX("pass LLC frame to SMT ",0,0,3) ;
+				smt_received_pack(smc,smc->os.hwm.tx_mb,
+						RD_FS_LOCAL) ;
+			}
+		}
+	}
+	NDD_TRACE("THfE",t,queue->tx_free,0) ;
+}
+
+
+/*
+ * queues a receive for later send
+ */
+static void queue_llc_rx(smc,mb)
+struct	s_smc *smc ;
+SMbuf	*mb ;
+{
+	DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ;
+	smc->os.hwm.queued_rx_frames++ ;
+	mb->sm_next = (SMbuf *)NULL ;
+	if (smc->os.hwm.llc_rx_pipe == 0) {
+		smc->os.hwm.llc_rx_pipe = mb ;
+	}
+	else {
+		smc->os.hwm.llc_rx_tail->sm_next = mb ;
+	}
+	smc->os.hwm.llc_rx_tail = mb ;
+
+	/*
+	 * force an timer IRQ to receive the data
+	 */
+	if (!smc->os.hwm.isr_flag) {
+		smt_force_irq(smc) ;
+	}
+}
+
+/*
+ * get a SMbuf from the llc_rx_queue
+ */
+static SMbuf *get_llc_rx(smc)
+struct	s_smc *smc ;
+{
+	SMbuf	*mb ;
+
+	if ((mb = smc->os.hwm.llc_rx_pipe)) {
+		smc->os.hwm.queued_rx_frames-- ;
+		smc->os.hwm.llc_rx_pipe = mb->sm_next ;
+	}
+	DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ;
+	return(mb) ;
+}
+
+/*
+ * queues a transmit SMT MBuf during the time were the MBuf is
+ * queued the TxD ring
+ */
+static void queue_txd_mb(smc,mb)
+struct	s_smc *smc ;
+SMbuf	*mb ;
+{
+	DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ;
+	smc->os.hwm.queued_txd_mb++ ;
+	mb->sm_next = (SMbuf *)NULL ;
+	if (smc->os.hwm.txd_tx_pipe == 0) {
+		smc->os.hwm.txd_tx_pipe = mb ;
+	}
+	else {
+		smc->os.hwm.txd_tx_tail->sm_next = mb ;
+	}
+	smc->os.hwm.txd_tx_tail = mb ;
+}
+
+/*
+ * get a SMbuf from the txd_tx_queue
+ */
+static SMbuf *get_txd_mb(smc)
+struct	s_smc *smc ;
+{
+	SMbuf *mb ;
+
+	if ((mb = smc->os.hwm.txd_tx_pipe)) {
+		smc->os.hwm.queued_txd_mb-- ;
+		smc->os.hwm.txd_tx_pipe = mb->sm_next ;
+	}
+	DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ;
+	return(mb) ;
+}
+
+/*
+ *	SMT Send function
+ */
+void smt_send_mbuf(smc,mb,fc)
+struct s_smc	*smc;
+SMbuf		*mb;
+int		fc;
+{
+	char far *data ;
+	int	len ;
+	int	n ;
+	int	i ;
+	int	frag_count ;
+	int	frame_status ;
+	SK_LOC_DECL(char far,*virt[3]) ;
+	int	frag_len[3] ;
+	struct s_smt_tx_queue *queue ;
+	struct s_smt_fp_txd volatile *t ;
+	u_long	phys ;
+#ifdef	AIX
+	u_long	tbctrl ;
+#endif
+
+	NDD_TRACE("THSB",mb,fc,0) ;
+	DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ;
+
+	mb->sm_off-- ;	/* set to fc */
+	mb->sm_len++ ;	/* + fc */
+	data = smtod(mb,char *) ;
+	*data = fc ;
+	if (fc == FC_SMT_LOC)
+		*data = FC_SMT_INFO ;
+
+	/*
+	 * determine the frag count and the virt addresses of the frags
+	 */
+	frag_count = 0 ;
+	len = mb->sm_len ;
+	while (len) {
+		n = SMT_PAGESIZE - ((int)data & (SMT_PAGESIZE-1)) ;
+		if (n >= len) {
+			n = len ;
+		}
+		DB_TX("frag: virt/len = 0x%x/%d ",(void *)data,n,5) ;
+		virt[frag_count] = data ;
+		frag_len[frag_count] = n ;
+		frag_count++ ;
+		len -= n ;
+		data += n ;
+	}
+
+	/*
+	 * determine the frame status
+	 */
+	queue = smc->hw.fp.tx[QUEUE_A0] ;
+	if (fc == FC_BEACON || fc == FC_SMT_LOC) {
+		frame_status = LOC_TX ;
+	}
+	else {
+		frame_status = LAN_TX ;
+		if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) ||
+		   (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO)))
+			frame_status |= LOC_TX ;
+	}
+
+	if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) {
+		if (frame_status &= ~LAN_TX) {
+			DB_TX("Ring is down: terminate LAN_TX",0,0,2) ;
+		}
+		else {
+			DB_TX("Ring is down: terminate transmission",0,0,2) ;
+			smt_free_mbuf(smc,mb) ;
+			return ;
+		}
+	}
+	DB_TX("frame_status = 0x%x ",frame_status,0,5) ;
+
+	if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) {
+		mb->sm_use_count = 2 ;
+	}
+
+	if (frame_status & LAN_TX) {
+		t = queue->tx_curr_put ;
+		frame_status |= FIRST_FRAG ;
+		for (i = 0; i < frag_count; i++) {
+			DB_TX("init TxD = 0x%x",(void *)t,0,5) ;
+			if (i == frag_count-1) {
+				frame_status |= LAST_FRAG ;
+				t->txd_txdscr = AIX_REVERSE(TX_DESCRIPTOR |
+					(((u_long)(mb->sm_len-1)&3) << 27)) ;
+			}
+			t->txd_virt = virt[i] ;
+			phys = dma_master(smc, (void far *)virt[i],
+				frag_len[i], DMA_RD|SMT_BUF) ;
+			t->txd_tbadr = AIX_REVERSE(phys) ;
+#ifndef	AIX
+			t->txd_tbctrl = (((u_long) frame_status &
+				(FIRST_FRAG|LAST_FRAG)) << 26) |
+				BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i] ;
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+			outpd(queue->tx_bmu_ctl,CSR_START) ;
+#else
+			tbctrl = AIX_REVERSE((((u_long) frame_status &
+				(FIRST_FRAG|LAST_FRAG)) << 26) |
+				BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ;
+			t->txd_tbctrl = tbctrl ;
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+			outpd(ADDR(B0_XA_CSR),CSR_START) ;
+#endif
+			frame_status &= ~FIRST_FRAG ;
+			queue->tx_curr_put = t = t->txd_next ;
+			queue->tx_free-- ;
+			queue->tx_used++ ;
+		}
+		smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
+		queue_txd_mb(smc,mb) ;
+	}
+
+	if (frame_status & LOC_TX) {
+		DB_TX("pass Mbuf to LLC queue",0,0,5) ;
+		queue_llc_rx(smc,mb) ;
+	}
+
+	/*
+	 * We need to unqueue the free SMT_MBUFs here, because it may
+	 * be that the SMT want's to send more than 1 frame for one down call
+	 */
+	mac_drv_clear_txd(smc) ;
+	NDD_TRACE("THSE",t,queue->tx_free,frag_count) ;
+}
+
+/*	BEGIN_MANUAL_ENTRY(mac_drv_clear_txd)
+ *	void mac_drv_clear_txd(smc)
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		mac_drv_clear_txd searches in both send queues for TxD's
+ *		which were finished by the adapter. It calls dma_complete
+ *		for each TxD. If the last fragment of an LLC frame is
+ *		reached, it calls mac_drv_tx_complete to release the
+ *		send buffer.
+ *
+ * return	nothing
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_clear_txd(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_tx_queue *queue ;
+	struct s_smt_fp_txd volatile *t1 ;
+	struct s_smt_fp_txd volatile *t2=0 ;
+	SMbuf *mb ;
+	u_long	tbctrl ;
+	int i ;
+	int frag_count ;
+	int n ;
+
+	NDD_TRACE("THcB",0,0,0) ;
+	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+		queue = smc->hw.fp.tx[i] ;
+		t1 = queue->tx_curr_get ;
+		DB_TX("clear_txd: QUEUE = %d (0=sync/1=async)",i,0,5) ;
+
+		for ( ; ; ) {
+			frag_count = 0 ;
+
+			do {
+				DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ;
+				DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ;
+				tbctrl = CR_READ(t1->txd_tbctrl) ;
+#ifdef	AIX
+				tbctrl = AIX_REVERSE(tbctrl) ;
+#endif
+				if (tbctrl & BMU_OWN || !queue->tx_used){
+					DB_TX("End of TxDs queue %d",i,0,4) ;
+					goto free_next_queue ;	/* next queue */
+				}
+				t1 = t1->txd_next ;
+				frag_count++ ;
+			} while (!(tbctrl & BMU_EOF)) ;
+
+			t1 = queue->tx_curr_get ;
+			for (n = frag_count; n; n--) {
+				tbctrl = AIX_REVERSE(t1->txd_tbctrl) ;
+				dma_complete(smc,
+					(union s_fp_descr volatile *) t1,
+					(int) (DMA_RD |
+					((tbctrl & BMU_SMT_TX) >> 18))) ;
+				t2 = t1 ;
+				t1 = t1->txd_next ;
+			}
+
+			if (tbctrl & BMU_SMT_TX) {
+				mb = get_txd_mb(smc) ;
+				smt_free_mbuf(smc,mb) ;
+			}
+			else {
+#ifndef PASS_1ST_TXD_2_TX_COMP
+				DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ;
+				mac_drv_tx_complete(smc,t2) ;
+#else
+				DB_TX("mac_drv_tx_comp for TxD 0x%x",
+					queue->tx_curr_get,0,4) ;
+				mac_drv_tx_complete(smc,queue->tx_curr_get) ;
+#endif
+			}
+			queue->tx_curr_get = t1 ;
+			queue->tx_free += frag_count ;
+			queue->tx_used -= frag_count ;
+		}
+free_next_queue: ;
+	}
+	NDD_TRACE("THcE",0,0,0) ;
+}
+
+/*
+ *	BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue)
+ *
+ * void mac_drv_clear_tx_queue(smc)
+ * struct s_smc *smc ;
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		mac_drv_clear_tx_queue is called from the SMT when
+ *		the RMT state machine has entered the ISOLATE state.
+ *		This function is also called by the os-specific module
+ *		after it has called the function card_stop().
+ *		In this case, the frames in the send queues are obsolete and
+ *		should be removed.
+ *
+ * note		calling sequence:
+ *		CLI_FBI(), card_stop(),
+ *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
+ *
+ * NOTE:	The caller is responsible that the BMUs are idle
+ *		when this function is called.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_clear_tx_queue(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_txd volatile *t ;
+	struct s_smt_tx_queue *queue ;
+	int tx_used ;
+	int i ;
+
+	if (smc->hw.hw_state != STOPPED) {
+		SK_BREAK() ;
+		SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ;
+		return ;
+	}
+
+	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+		queue = smc->hw.fp.tx[i] ;
+		DB_TX("clear_tx_queue: QUEUE = %d (0=sync/1=async)",i,0,5) ;
+
+		/*
+		 * switch the OWN bit of all pending frames to the host
+		 */
+		t = queue->tx_curr_get ;
+		tx_used = queue->tx_used ;
+		while (tx_used) {
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
+			DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ;
+			t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+			t = t->txd_next ;
+			tx_used-- ;
+		}
+	}
+
+	/*
+	 * release all TxD's for both send queues
+	 */
+	mac_drv_clear_txd(smc) ;
+
+	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+		queue = smc->hw.fp.tx[i] ;
+		t = queue->tx_curr_get ;
+
+		/*
+		 * write the phys pointer of the NEXT descriptor into the
+		 * BMU's current address descriptor pointer and set
+		 * tx_curr_get and tx_curr_put to this position
+		 */
+		if (i == QUEUE_S) {
+			outpd(ADDR(B5_XS_DA),AIX_REVERSE(t->txd_ntdadr)) ;
+		}
+		else {
+			outpd(ADDR(B5_XA_DA),AIX_REVERSE(t->txd_ntdadr)) ;
+		}
+
+		queue->tx_curr_put = queue->tx_curr_get->txd_next ;
+		queue->tx_curr_get = queue->tx_curr_put ;
+	}
+}
+
+
+/*
+	-------------------------------------------------------------
+	TEST FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+#ifdef	DEBUG
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_debug_lev)
+ *	void mac_drv_debug_lev(smc,flag,lev)
+ *
+ * function	DOWNCALL	(drvsr.c)
+ *		To get a special debug info the user can assign a debug level
+ *		to any debug flag.
+ *
+ * para	flag	debug flag, possible values are:
+ *			= 0:	reset all debug flags (the defined level is
+ *				ignored)
+ *			= 1:	debug.d_smtf
+ *			= 2:	debug.d_smt
+ *			= 3:	debug.d_ecm
+ *			= 4:	debug.d_rmt
+ *			= 5:	debug.d_cfm
+ *			= 6:	debug.d_pcm
+ *
+ *			= 10:	debug.d_os.hwm_rx (hardware module receive path)
+ *			= 11:	debug.d_os.hwm_tx(hardware module transmit path)
+ *			= 12:	debug.d_os.hwm_gen(hardware module general flag)
+ *
+ *	lev	debug level
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_debug_lev(smc,flag,lev)
+struct s_smc *smc ;
+int flag ;
+int lev ;
+{
+	switch(flag) {
+	case (int)NULL:
+		DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ;
+		DB_P.d_cfm = 0 ;
+		DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ;
+#ifdef	SBA
+		DB_P.d_sba = 0 ;
+#endif
+#ifdef	ESS
+		DB_P.d_ess = 0 ;
+#endif
+		break ;
+	case DEBUG_SMTF:
+		DB_P.d_smtf = lev ;
+		break ;
+	case DEBUG_SMT:
+		DB_P.d_smt = lev ;
+		break ;
+	case DEBUG_ECM:
+		DB_P.d_ecm = lev ;
+		break ;
+	case DEBUG_RMT:
+		DB_P.d_rmt = lev ;
+		break ;
+	case DEBUG_CFM:
+		DB_P.d_cfm = lev ;
+		break ;
+	case DEBUG_PCM:
+		DB_P.d_pcm = lev ;
+		break ;
+	case DEBUG_SBA:
+#ifdef	SBA
+		DB_P.d_sba = lev ;
+#endif
+		break ;
+	case DEBUG_ESS:
+#ifdef	ESS
+		DB_P.d_ess = lev ;
+#endif
+		break ;
+	case DB_HWM_RX:
+		DB_P.d_os.hwm_rx = lev ;
+		break ;
+	case DB_HWM_TX:
+		DB_P.d_os.hwm_tx = lev ;
+		break ;
+	case DB_HWM_GEN:
+		DB_P.d_os.hwm_gen = lev ;
+		break ;
+	default:
+		break ;
+	}
+}
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/hwt.c linux/drivers/net/skfp/hwt.c
--- v2.3.46/linux/drivers/net/skfp/hwt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/hwt.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,314 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Timer Driver for FBI board (timer chip 82C54)
+ */
+
+/*
+ * Modifications:
+ *
+ *	28-Jun-1994 sw	Edit v1.6.
+ *			MCA: Added support for the SK-NET FDDI-FM2 adapter. The
+ *			 following functions have been added(+) or modified(*):
+ *			 hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)hwt.c	1.13 97/04/23 (C) SK " ;
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
+/*static*/ void hwt_restart() ;
+
+/************************
+ *
+ *	hwt_start
+ *
+ *	Start hardware timer (clock ticks are 16us).
+ *
+ *	void hwt_start(
+ *		struct s_smc *smc,
+ *		u_long time) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ *
+ *	time - The time in units of 16us to load the timer with.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+#define	HWT_MAX	(65000)
+
+void hwt_start(smc, time)
+struct s_smc *smc ;
+u_long time ;
+{
+	u_short	cnt ;
+
+	if (time > HWT_MAX)
+		time = HWT_MAX ;
+
+	smc->hw.t_start = time ;
+	smc->hw.t_stop = 0L ;
+
+	cnt = (u_short)time ;
+	/*
+	 * if time < 16 us
+	 *	time = 16 us
+	 */
+	if (!cnt)
+		cnt++ ;
+#ifndef	PCI
+	/*
+	 * 6.25MHz -> CLK0 : T0 (cnt0 = 16us)	-> OUT0
+	 *    OUT0 -> CLK1 : T1 (cnt1)	OUT1	-> ISRA(IS_TIMINT)
+	 */
+	OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */
+	OUT_82c54_TIMER(1,cnt & 0xff) ;		/* LSB */
+	OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ;	/* MSB */
+	/*
+	 * start timer by switching counter 0 to mode 3
+	 *	T0 resolution 16 us (CLK0=0.16us)
+	 */
+	OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ;	/* counter 0, mode 3 */
+	OUT_82c54_TIMER(0,100) ;		/* LSB */
+	OUT_82c54_TIMER(0,0) ;			/* MSB */
+#else	/* PCI */
+	outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */
+	outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */
+#endif	/* PCI */
+	smc->hw.timer_activ = TRUE ;
+}
+
+/************************
+ *
+ *	hwt_stop
+ *
+ *	Stop hardware timer.
+ *
+ *	void hwt_stop(
+ *		struct s_smc *smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void hwt_stop(smc)
+struct s_smc *smc ;
+{
+#ifndef PCI
+	/* stop counter 0 by switching to mode 0 */
+	OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ;	/* counter 0, mode 0 */
+	OUT_82c54_TIMER(0,0) ;			/* LSB */
+	OUT_82c54_TIMER(0,0) ;			/* MSB */
+#else	/* PCI */
+	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
+	outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
+#endif	/* PCI */
+
+	smc->hw.timer_activ = FALSE ;
+}
+
+/************************
+ *
+ *	hwt_init
+ *
+ *	Initialize hardware timer.
+ *
+ *	void hwt_init(
+ *		struct s_smc *smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void hwt_init(smc)
+struct s_smc *smc ;
+{
+	smc->hw.t_start = 0 ;
+	smc->hw.t_stop	= 0 ;
+	smc->hw.timer_activ = FALSE ;
+
+	hwt_restart(smc) ;
+}
+
+/************************
+ *
+ *	hwt_restart
+ *
+ *	Clear timer interrupt.
+ *
+ *	void hwt_restart(
+ *		struct s_smc *smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void hwt_restart(smc)
+struct s_smc *smc ;
+{
+	hwt_stop(smc) ;
+#ifndef	PCI
+	OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */
+	OUT_82c54_TIMER(1,1 ) ;			/* LSB */
+	OUT_82c54_TIMER(1,0 ) ;			/* MSB */
+#endif
+}
+
+/************************
+ *
+ *	hwt_read
+ *
+ *	Stop hardware timer and read time elapsed since last start.
+ *
+ *	u_long hwt_read(smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	The elapsed time since last start in units of 16us.
+ *
+ ************************/
+u_long hwt_read(smc)
+struct s_smc *smc ;
+{
+	u_short	tr ;
+#ifndef	PCI
+	u_short	is ;
+#else
+	u_long	is ;
+#endif
+
+	if (smc->hw.timer_activ) {
+		hwt_stop(smc) ;
+#ifndef	PCI
+		OUT_82c54_TIMER(3,1<<6) ;	/* latch command */
+		tr = IN_82c54_TIMER(1) & 0xff ;
+		tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
+#else	/* PCI */
+		tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
+#endif	/* PCI */
+		is = GET_ISR() ;
+		/* Check if timer expired (or wraparound). */
+		if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
+			hwt_restart(smc) ;
+			smc->hw.t_stop = smc->hw.t_start ;
+		}
+		else
+			smc->hw.t_stop = smc->hw.t_start - tr ;
+	}
+	return (smc->hw.t_stop) ;
+}
+
+#ifdef	PCI
+/************************
+ *
+ *	hwt_quick_read
+ *
+ *	Stop hardware timer and read timer value and start the timer again.
+ *
+ *	u_long hwt_read(smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	current timer value in units of 80ns.
+ *
+ ************************/
+u_long hwt_quick_read(smc)
+struct s_smc *smc ;
+{
+	u_long interval ;
+	u_long time ;
+
+	interval = inpd(ADDR(B2_TI_INI)) ;
+	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
+	time = inpd(ADDR(B2_TI_VAL)) ;
+	outpd(ADDR(B2_TI_INI),time) ;
+	outpw(ADDR(B2_TI_CRTL), TIM_START) ;
+	outpd(ADDR(B2_TI_INI),interval) ;
+
+	return(time) ;
+}
+
+/************************
+ *
+ *	hwt_wait_time(smc,start,duration)
+ *
+ *	This function returnes after the amount of time is elapsed
+ *	since the start time.
+ * 
+ * para	start		start time
+ *	duration	time to wait
+ *
+ * NOTE: The fuction will return immediatly, if the timer is not 
+ *	 started
+ ************************/
+void hwt_wait_time(smc,start,duration)
+struct s_smc *smc ;
+u_long	start ;
+long	duration ;
+{
+	long	diff ;
+	long	interval ;
+	int	wrapped ;
+
+	/*
+	 * check if timer is running
+	 */
+	if (smc->hw.timer_activ == FALSE ||
+		hwt_quick_read(smc) == hwt_quick_read(smc)) {
+		return ;
+	}
+
+	interval = inpd(ADDR(B2_TI_INI)) ;
+	if (interval > duration) {
+		do {
+			diff = (long)(start - hwt_quick_read(smc)) ;
+			if (diff < 0) {
+				diff += interval ;
+			}
+		} while (diff <= duration) ;
+	}
+	else {
+		diff = interval ;
+		wrapped = 0 ;
+		do {
+			if (!wrapped) {
+				if (hwt_quick_read(smc) >= start) {
+					diff += interval ;
+					wrapped = 1 ;
+				}
+			}
+			else {
+				if (hwt_quick_read(smc) < start) {
+					wrapped = 0 ;
+				}
+			}
+		} while (diff <= duration) ;
+	}
+}
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/lnkstat.c linux/drivers/net/skfp/lnkstat.c
--- v2.3.46/linux/drivers/net/skfp/lnkstat.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/lnkstat.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	IBM FDDI read error log function
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/lnkstat.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)lnkstat.c	1.8 97/04/11 (C) SK " ;
+#endif
+
+#ifdef	sun
+#define _far
+#endif
+
+#define EL_IS_OK(x,l)	((((int)&(((struct s_error_log *)0)->x)) + \
+			sizeof(er->x)) <= l)
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_get_error_word(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT error work for AIX events.
+
+Return	smt_error_word	These bits are supported:
+
+		SMT_ERL_ALC	== 	[PS/PA].fddiPORTLerFlag
+		SMT_ERL_BLC	==	[PB].fddiPORTLerFlag
+		SMT_ERL_NCC	==	fddiMACNotCopiedFlag
+		SMT_ERL_FEC	==	fddiMACFrameErrorFlag
+
+	END_MANUAL_ENTRY()
+ */
+u_long smt_get_error_word(smc)
+struct s_smc *smc ;
+{
+	u_long	st;
+
+	/*
+	 * smt error word low
+	 */
+	st = 0 ;
+	if (smc->s.sas == SMT_SAS) {
+		if (smc->mib.p[PS].fddiPORTLerFlag)
+			st |= SMT_ERL_ALC ;
+	}
+	else {
+		if (smc->mib.p[PA].fddiPORTLerFlag)
+			st |= SMT_ERL_ALC ;
+		if (smc->mib.p[PB].fddiPORTLerFlag)
+			st |= SMT_ERL_BLC ;
+	}
+	if (smc->mib.m[MAC0].fddiMACNotCopiedFlag)
+		st |= SMT_ERL_NCC ;		/* not copied condition */
+	if (smc->mib.m[MAC0].fddiMACFrameErrorFlag)
+		st |= SMT_ERL_FEC ;		/* frame error condition */
+
+	return st;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_get_event_word(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT event work for AIX events.
+
+Return	smt_event_word	always 0
+
+	END_MANUAL_ENTRY()
+ */
+u_long smt_get_event_word(smc)
+struct s_smc *smc ;
+{
+	return (u_long) 0;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_get_port_event_word(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT port event work for AIX events.
+
+Return	smt_port_event_word	always 0
+
+	END_MANUAL_ENTRY()
+ */
+u_long smt_get_port_event_word(smc)
+struct s_smc *smc ;
+{
+	return (u_long) 0;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_read_errorlog(smc,p,len)
+	struct s_smc *smc ;
+	char _far *p ;
+	int len ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT error log field for AIX events.
+
+Para	p	pointer to the error log field
+	len	len of the error log field
+
+Return	len	used len of the error log field
+
+	END_MANUAL_ENTRY()
+ */
+int smt_read_errorlog(smc,p,len)
+struct s_smc *smc ;
+char _far *p ;
+int len ;
+{
+	int			i ;
+	int			st ;
+	struct s_error_log _far	*er ;
+
+	er = (struct s_error_log _far *) p ;
+	if (len > sizeof(struct s_error_log))
+		len = sizeof(struct s_error_log) ;
+	for (i = 0 ; i < len ; i++)
+		*p++ = 0 ;
+	/*
+	 * set count
+	 */
+	if (EL_IS_OK(set_count_high,len)) {
+		er->set_count_low = (u_short)smc->mib.fddiSMTSetCount.count ;
+		er->set_count_high =
+			(u_short)(smc->mib.fddiSMTSetCount.count >> 16L) ;
+	}
+	/*
+	 * aci
+	 */
+	if (EL_IS_OK(aci_id_code,len)) {
+		er->aci_id_code = 0 ;
+	}
+	/*
+	 * purge counter is missed frames; 16 bits only
+	 */
+	if (EL_IS_OK(purge_frame_counter,len)) {
+		if (smc->mib.m[MAC0].fddiMACCopied_Ct > 0xffff)
+			er->purge_frame_counter = 0xffff ;
+		else
+			er->purge_frame_counter =
+				(u_short)smc->mib.m[MAC0].fddiMACCopied_Ct ;
+	}
+	/*
+	 * CMT and RMT state machines
+	 */
+	if (EL_IS_OK(ecm_state,len))
+		er->ecm_state = smc->mib.fddiSMTECMState ;
+
+	if (EL_IS_OK(pcm_b_state,len)) {
+		if (smc->s.sas == SMT_SAS) {
+			er->pcm_a_state = smc->y[PS].mib->fddiPORTPCMState ;
+			er->pcm_b_state = 0 ;
+		}
+		else {
+			er->pcm_a_state = smc->y[PA].mib->fddiPORTPCMState ;
+			er->pcm_b_state = smc->y[PB].mib->fddiPORTPCMState ;
+		}
+	}
+	if (EL_IS_OK(cfm_state,len))
+		er->cfm_state = smc->mib.fddiSMTCF_State ;
+	if (EL_IS_OK(rmt_state,len))
+		er->rmt_state = smc->mib.m[MAC0].fddiMACRMTState ;
+
+	/*
+	 * smt error word low (we only need the low order 16 bits.)
+	 */
+
+	st = smt_get_error_word(smc) & 0xffff ;
+
+	if (EL_IS_OK(smt_error_low,len))
+		er->smt_error_low = st ;
+
+	if (EL_IS_OK(ucode_version_level,len))
+		er->ucode_version_level = 0x0101 ;
+	return(len) ;
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/pcmplc.c linux/drivers/net/skfp/pcmplc.c
--- v2.3.46/linux/drivers/net/skfp/pcmplc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/pcmplc.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,2094 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	PCM
+	Physical Connection Management
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * 		queue_event()
+ * 		smt_timer_start()
+ * 		smt_timer_stop()
+ *
+ * 	The following external HW dependant functions are referenced :
+ * 		sm_pm_control()
+ *		sm_ph_linestate()
+ *		sm_pm_ls_latch()
+ *
+ * 	The following HW dependant events are required :
+ *		PC_QLS
+ *		PC_ILS
+ *		PC_HLS
+ *		PC_MLS
+ *		PC_NSE
+ *		PC_LEM
+ *
+ */
+
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)pcmplc.c	2.55 99/08/05 (C) SK " ;
+#endif
+
+#ifdef	FDDI_MIB
+extern int snmp_fddi_trap(
+#ifdef	ANSIC
+struct s_smc	* smc, int  type, int  index
+#endif
+);
+#endif
+#ifdef	CONCENTRATOR
+extern int plc_is_installed(
+#ifdef	ANSIC
+struct s_smc *smc ,
+int p
+#endif
+) ;
+#endif
+/*
+ * FSM Macros
+ */
+#define AFLAG		(0x20)
+#define GO_STATE(x)	(mib->fddiPORTPCMState = (x)|AFLAG)
+#define ACTIONS_DONE()	(mib->fddiPORTPCMState &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+/*
+ * PCM states
+ */
+#define PC0_OFF			0
+#define PC1_BREAK		1
+#define PC2_TRACE		2
+#define PC3_CONNECT		3
+#define PC4_NEXT		4
+#define PC5_SIGNAL		5
+#define PC6_JOIN		6
+#define PC7_VERIFY		7
+#define PC8_ACTIVE		8
+#define PC9_MAINT		9
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const pcm_states[] =  {
+	"PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT",
+	"PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const pcm_events[] = {
+	"NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL",
+	"PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR",
+	"PC_ENABLE","PC_DISABLE",
+	"PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE",
+	"PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN",
+	"PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT",
+	"PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT",
+	"PC_NSE","PC_LEM"
+} ;
+#endif
+
+#ifdef	MOT_ELM
+/*
+ * PCL-S control register
+ * this register in the PLC-S controls the scrambling parameters
+ */
+#define PLCS_CONTROL_C_U	0
+#define PLCS_CONTROL_C_S	(PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
+				 PL_C_CIPHER_ENABLE)
+#define	PLCS_FASSERT_U		0
+#define	PLCS_FASSERT_S		0xFd76	/* 52.0 us */
+#define	PLCS_FDEASSERT_U	0
+#define	PLCS_FDEASSERT_S	0
+#else	/* nMOT_ELM */
+/*
+ * PCL-S control register
+ * this register in the PLC-S controls the scrambling parameters
+ * can be patched for ANSI compliance if standard changes
+ */
+static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ;
+static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ;
+
+#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))
+#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
+#endif	/* nMOT_ELM */
+
+/*
+ * external vars
+ */
+/* struct definition see 'cmtdef.h' (also used by CFM) */
+
+#define PS_OFF		0
+#define PS_BIT3		1
+#define PS_BIT4		2
+#define PS_BIT7		3
+#define PS_LCT		4
+#define PS_BIT8		5
+#define PS_JOIN		6
+#define PS_ACTIVE	7
+
+#define LCT_LEM_MAX	255
+
+/*
+ * PLC timing parameter
+ */
+
+#define PLC_MS(m)	((int)((0x10000L-(m*100000L/2048))))
+#define SLOW_TL_MIN	PLC_MS(6)
+#define SLOW_C_MIN	PLC_MS(10)
+
+static	const struct plt {
+	int	timer ;			/* relative plc timer address */
+	int	para ;			/* default timing parameters */
+} pltm[] = {
+	{ PL_C_MIN, SLOW_C_MIN },	/* min t. to remain Connect State */
+	{ PL_TL_MIN, SLOW_TL_MIN },	/* min t. to transmit a Line State */
+	{ PL_TB_MIN, TP_TB_MIN },	/* min break time */
+	{ PL_T_OUT, TP_T_OUT },		/* Signaling timeout */
+	{ PL_LC_LENGTH, TP_LC_LENGTH },	/* Link Confidence Test Time */
+	{ PL_T_SCRUB, TP_T_SCRUB },	/* Scrub Time == MAC TVX time ! */
+	{ PL_NS_MAX, TP_NS_MAX },	/* max t. that noise is tolerated */
+	{ 0,0 }
+} ;
+
+/*
+ * interrupt mask
+ */
+#ifdef	SUPERNET_3
+/*
+ * Do we need the EBUF error during signaling, too, to detect SUPERNET_3
+ * PLL bug?
+ */
+static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
+#else	/* SUPERNET_3 */
+/*
+ * We do NOT need the elasticity buffer error during signaling.
+ */
+static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+			PL_PCM_ENABLED | PL_SELF_TEST ;
+#endif	/* SUPERNET_3 */
+static int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
+
+/* external functions */
+void	all_selection_criteria ();
+
+/* internal functions */
+static void pcm_fsm() ;
+static void pc_rcode_actions() ;
+static void pc_tcode_actions() ;
+static void reset_lem_struct() ;
+static void plc_init() ;
+static void sm_ph_lem_start() ;
+static void sm_ph_lem_stop() ;
+static void sm_ph_linestate() ;
+static void real_init_plc() ;
+
+/*
+ * SMT timer interface
+ *      start PCM timer 0
+ */
+static void start_pcm_timer0(smc,value,event,phy)
+struct s_smc *smc ;
+u_long value;
+int event;
+struct s_phy *phy;
+{
+	phy->timer0_exp = FALSE ;       /* clear timer event flag */
+	smt_timer_start(smc,&phy->pcm_timer0,value,
+		EV_TOKEN(EVENT_PCM+phy->np,event)) ;
+}
+/*
+ * SMT timer interface
+ *      stop PCM timer 0
+ */
+static void stop_pcm_timer0(smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy;
+{
+	if (phy->pcm_timer0.tm_active)
+		smt_timer_stop(smc,&phy->pcm_timer0) ;
+}
+
+/*
+	init PCM state machine (called by driver)
+	clear all PCM vars and flags
+*/
+void pcm_init(smc)
+struct s_smc *smc ;
+{
+	int		i ;
+	int		np ;
+	struct s_phy	*phy ;
+	struct fddi_mib_p	*mib ;
+
+	for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) {
+		/* Indicates the type of PHY being used */
+		mib = phy->mib ;
+		mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ;
+		phy->np = np ;
+		switch (smc->s.sas) {
+#ifdef	CONCENTRATOR
+		case SMT_SAS :
+			mib->fddiPORTMy_Type = (np == PS) ? TS : TM ;
+			break ;
+		case SMT_DAS :
+			mib->fddiPORTMy_Type = (np == PA) ? TA :
+					(np == PB) ? TB : TM ;
+			break ;
+		case SMT_NAC :
+			mib->fddiPORTMy_Type = TM ;
+			break;
+#else
+		case SMT_SAS :
+			mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ;
+			mib->fddiPORTHardwarePresent = (np == PS) ? TRUE :
+					FALSE ;
+#ifndef	SUPERNET_3
+			smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ;
+#else
+			smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ;
+#endif
+			break ;
+		case SMT_DAS :
+			mib->fddiPORTMy_Type = (np == PB) ? TB : TA ;
+			break ;
+#endif
+		}
+		/*
+		 * set PMD-type
+		 */
+		phy->pmd_scramble = 0 ;
+		switch (phy->pmd_type[PMD_SK_PMD]) {
+		case 'P' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
+			break ;
+		case 'L' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ;
+			break ;
+		case 'D' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			break ;
+		case 'S' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			phy->pmd_scramble = TRUE ;
+			break ;
+		case 'U' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			phy->pmd_scramble = TRUE ;
+			break ;
+		case '1' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
+			break ;
+		case '2' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
+			break ;
+		case '3' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
+			break ;
+		case '4' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
+			break ;
+		case 'H' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
+			break ;
+		case 'I' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			break ;
+		case 'G' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			break ;
+		default:
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
+			break ;
+		}
+		/*
+		 * A and B port can be on primary and secondary path
+		 */
+		switch (mib->fddiPORTMy_Type) {
+		case TA :
+			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_SEC_PREFER ;
+			mib->fddiPORTRequestedPaths[3] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_SEC_PREFER |
+				MIB_P_PATH_THRU ;
+			break ;
+		case TB :
+			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_PRIM_PREFER ;
+			mib->fddiPORTRequestedPaths[3] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_PRIM_PREFER |
+				MIB_P_PATH_CON_PREFER |
+				MIB_P_PATH_THRU ;
+			break ;
+		case TS :
+			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_PRIM_PREFER ;
+			mib->fddiPORTRequestedPaths[3] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_PRIM_PREFER ;
+			break ;
+		case TM :
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_SEC_ALTER |
+				MIB_P_PATH_PRIM_ALTER ;
+			mib->fddiPORTRequestedPaths[3] = 0 ;
+			break ;
+		}
+
+		phy->pc_lem_fail = FALSE ;
+		mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ;
+		mib->fddiPORTLCTFail_Ct = 0 ;
+		mib->fddiPORTBS_Flag = 0 ;
+		mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		mib->fddiPORTNeighborType = TNONE ;
+		phy->ls_flag = 0 ;
+		phy->rc_flag = 0 ;
+		phy->tc_flag = 0 ;
+		phy->td_flag = 0 ;
+		if (np >= PM)
+			phy->phy_name = '0' + np - PM ;
+		else
+			phy->phy_name = 'A' + np ;
+		phy->wc_flag = FALSE ;		/* set by SMT */
+		memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ;
+		reset_lem_struct(phy) ;
+		memset((char *)&phy->plc,0,sizeof(struct s_plc)) ;
+		phy->plc.p_state = PS_OFF ;
+		for (i = 0 ; i < NUMBITS ; i++) {
+			phy->t_next[i] = 0 ;
+		}
+	}
+	real_init_plc(smc) ;
+}
+
+void init_plc(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * dummy
+	 * this is an obsolete public entry point that has to remain
+	 * for compat. It is used by various drivers.
+	 * the work is now done in real_init_plc()
+	 * which is called from pcm_init() ;
+	 */
+}
+
+static void real_init_plc(smc)
+struct s_smc *smc ;
+{
+	int	p ;
+
+	for (p = 0 ; p < NUMPHYS ; p++)
+		plc_init(smc,p) ;
+}
+
+static void plc_init(smc,p)
+struct s_smc *smc ;
+int p;
+{
+	int	i ;
+#ifndef	MOT_ELM
+	int	rev ;	/* Revision of PLC-x */
+#endif	/* MOT_ELM */
+
+	/* transit PCM state machine to MAINT state */
+	outpw(PLC(p,PL_CNTRL_B),0) ;
+	outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ;
+	outpw(PLC(p,PL_CNTRL_A),0) ;
+
+	/*
+	 * if PLC-S then set control register C
+	 */
+#ifndef	MOT_ELM
+	rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ;
+	if (rev != PLC_REVISION_A)
+#endif	/* MOT_ELM */
+	{
+		if (smc->y[p].pmd_scramble) {
+			outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ;
+#ifdef	MOT_ELM
+			outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ;
+			outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ;
+#endif	/* MOT_ELM */
+		}
+		else {
+			outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ;
+#ifdef	MOT_ELM
+			outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ;
+			outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ;
+#endif	/* MOT_ELM */
+		}
+	}
+
+	/*
+	 * set timer register
+	 */
+	for ( i = 0 ; pltm[i].timer; i++)	/* set timer parameter reg */
+		outpw(PLC(p,pltm[i].timer),pltm[i].para) ;
+
+	(void)inpw(PLC(p,PL_INTR_EVENT)) ;	/* clear interrupt event reg */
+	plc_clear_irq(smc,p) ;
+	outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */
+
+	/*
+	 * if PCM is configured for class s, it will NOT go to the
+	 * REMOVE state if offline (page 3-36;)
+	 * in the concentrator, all inactive PHYS always must be in
+	 * the remove state
+	 * there's no real need to use this feature at all ..
+	 */
+#ifndef	CONCENTRATOR
+	if ((smc->s.sas == SMT_SAS) && (p == PS)) {
+		outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ;
+	}
+#endif
+}
+
+/*
+ * control PCM state machine
+ */
+static void plc_go_state(smc,p,state)
+struct s_smc *smc ;
+int p;
+int state;
+{
+	HW_PTR port ;
+	int val ;
+
+	SK_UNUSED(smc) ;
+
+	port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ;
+	val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ;
+	outpw(port,val) ;
+	outpw(port,val | state) ;
+}
+
+/*
+ * read current line state (called by ECM & PCM)
+ */
+int sm_pm_get_ls(smc,phy)
+struct s_smc *smc ;
+int phy;
+{
+	int	state ;
+
+#ifdef	CONCENTRATOR
+	if (!plc_is_installed(smc,phy))
+		return(PC_QLS) ;
+#endif
+
+	state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ;
+	switch(state) {
+	case PL_L_QLS:
+		state = PC_QLS ;
+		break ;
+	case PL_L_MLS:
+		state = PC_MLS ;
+		break ;
+	case PL_L_HLS:
+		state = PC_HLS ;
+		break ;
+	case PL_L_ILS4:
+	case PL_L_ILS16:
+		state = PC_ILS ;
+		break ;
+	case PL_L_ALS:
+		state = PC_LS_PDR ;
+		break ;
+	default :
+		state = PC_LS_NONE ;
+	}
+	return(state) ;
+}
+
+static int plc_send_bits(smc,phy,len)
+struct s_smc *smc ;
+struct s_phy *phy;
+int len;
+{
+	int np = phy->np ;		/* PHY index */
+	int	n ;
+	int	i ;
+
+	SK_UNUSED(smc) ;
+
+	/* create bit vector */
+	for (i = len-1,n = 0 ; i >= 0 ; i--) {
+		n = (n<<1) | phy->t_val[phy->bitn+i] ;
+	}
+	if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
+#if	0
+		printf("PL_PCM_SIGNAL is set\n") ;
+#endif
+		return(1) ;
+	}
+	/* write bit[n] & length = 1 to regs */
+	outpw(PLC(np,PL_VECTOR_LEN),len-1) ;	/* len=nr-1 */
+	outpw(PLC(np,PL_XMIT_VECTOR),n) ;
+#ifdef	DEBUG
+#if 1
+#ifdef	DEBUG_BRD
+	if (smc->debug.d_plc & 0x80)
+#else
+	if (debug.d_plc & 0x80)
+#endif
+		printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ;
+#endif
+#endif
+	return(0) ;
+}
+
+/*
+ * config plc muxes
+ */
+void plc_config_mux(smc,mux)
+struct s_smc *smc ;
+int mux ;
+{
+	if (smc->s.sas != SMT_DAS)
+		return ;
+	if (mux == MUX_WRAPB) {
+		SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
+		SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
+	}
+	else {
+		CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
+		CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ;
+	}
+	CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
+	CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ;
+}
+
+/*
+	PCM state machine
+	called by dispatcher  & fddi_init() (driver)
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void pcm(smc,np,event)
+struct s_smc *smc ;
+const int np;
+int event;
+{
+	int	state ;
+	int	oldstate ;
+	struct s_phy	*phy ;
+	struct fddi_mib_p	*mib ;
+
+#ifndef	CONCENTRATOR
+	/*
+	 * ignore 2nd PHY if SAS
+	 */
+	if ((np != PS) && (smc->s.sas == SMT_SAS))
+		return ;
+#endif
+	phy = &smc->y[np] ;
+	mib = phy->mib ;
+	oldstate = mib->fddiPORTPCMState ;
+	do {
+		DB_PCM("PCM %c: state %s",
+			phy->phy_name,
+			(mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ;
+		DB_PCM("%s, event %s\n",
+			pcm_states[mib->fddiPORTPCMState & ~AFLAG],
+			pcm_events[event]) ;
+		state = mib->fddiPORTPCMState ;
+		pcm_fsm(smc,phy,event) ;
+		event = 0 ;
+	} while (state != mib->fddiPORTPCMState) ;
+	/*
+	 * because the PLC does the bit signaling for us,
+	 * we're always in SIGNAL state
+	 * the MIB want's to see CONNECT
+	 * we therefore fake an entry in the MIB
+	 */
+	if (state == PC5_SIGNAL)
+		mib->fddiPORTPCMStateX = PC3_CONNECT ;
+	else
+		mib->fddiPORTPCMStateX = state ;
+
+#ifndef	SLIM_SMT
+	/*
+	 * path change
+	 */
+	if (	mib->fddiPORTPCMState != oldstate &&
+		((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) {
+		smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE,
+			(int) (INDEX_PORT+ phy->np),0) ;
+	}
+#endif
+
+#ifdef FDDI_MIB
+	/* check whether a snmp-trap has to be sent */
+
+	if ( mib->fddiPORTPCMState != oldstate ) {
+		/* a real state change took place */
+		DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState);
+		if ( mib->fddiPORTPCMState == PC0_OFF ) {
+			/* send first trap */
+			snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex );
+		} else if ( oldstate == PC0_OFF ) {
+			/* send second trap */
+			snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex );
+		} else if ( mib->fddiPORTPCMState != PC2_TRACE &&
+			oldstate == PC8_ACTIVE ) {
+			/* send third trap */
+			snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex );
+		} else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) {
+			/* send fourth trap */
+			snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex );
+		}
+	}
+#endif
+
+	pcm_state_change(smc,np,state) ;
+}
+
+/*
+ * PCM state machine
+ */
+static void pcm_fsm(smc,phy,cmd)
+struct s_smc *smc ;
+struct s_phy *phy;
+int cmd;
+{
+	int	i ;
+	int	np = phy->np ;		/* PHY index */
+	struct s_plc	*plc ;
+	struct fddi_mib_p	*mib ;
+#ifndef	MOT_ELM
+	u_short	plc_rev ;		/* Revision of the plc */
+#endif	/* nMOT_ELM */
+
+	plc = &phy->plc ;
+	mib = phy->mib ;
+
+	/*
+	 * general transitions independant of state
+	 */
+	switch (cmd) {
+	case PC_STOP :
+		/*PC00-PC80*/
+		if (mib->fddiPORTPCMState != PC9_MAINT) {
+			GO_STATE(PC0_OFF) ;
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP,
+				smt_get_port_event_word(smc));
+		}
+		return ;
+	case PC_START :
+		/*PC01-PC81*/
+		if (mib->fddiPORTPCMState != PC9_MAINT)
+			GO_STATE(PC1_BREAK) ;
+		return ;
+	case PC_DISABLE :
+		/* PC09-PC99 */
+		GO_STATE(PC9_MAINT) ;
+		AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+			FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED,
+			smt_get_port_event_word(smc));
+		return ;
+	case PC_TIMEOUT_LCT :
+		/* if long or extended LCT */
+		stop_pcm_timer0(smc,phy) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		/* end of LCT is indicate by PCM_CODE (initiate PCM event) */
+		return ;
+	}
+
+	switch(mib->fddiPORTPCMState) {
+	case ACTIONS(PC0_OFF) :
+		stop_pcm_timer0(smc,phy) ;
+		outpw(PLC(np,PL_CNTRL_A),0) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
+		phy->cf_loop = FALSE ;
+		phy->cf_join = FALSE ;
+		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+		plc_go_state(smc,np,PL_PCM_STOP) ;
+		mib->fddiPORTConnectState = PCM_DISABLED ;
+		ACTIONS_DONE() ;
+		break ;
+	case PC0_OFF:
+		/*PC09*/
+		if (cmd == PC_MAINT) {
+			GO_STATE(PC9_MAINT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(PC1_BREAK) :
+		/* Stop the LCT timer if we came from Signal state */
+		stop_pcm_timer0(smc,phy) ;
+		ACTIONS_DONE() ;
+		plc_go_state(smc,np,0) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
+		/*
+		 * if vector is already loaded, go to OFF to clear PCM_SIGNAL
+		 */
+#if	0
+		if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
+			plc_go_state(smc,np,PL_PCM_STOP) ;
+			/* TB_MIN ? */
+		}
+#endif
+		/*
+		 * Go to OFF state in any case.
+		 */
+		plc_go_state(smc,np,PL_PCM_STOP) ;
+
+		if (mib->fddiPORTPC_Withhold == PC_WH_NONE)
+			mib->fddiPORTConnectState = PCM_CONNECTING ;
+		phy->cf_loop = FALSE ;
+		phy->cf_join = FALSE ;
+		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+		phy->ls_flag = FALSE ;
+		phy->pc_mode = PM_NONE ;	/* needed by CFM */
+		phy->bitn = 0 ;			/* bit signaling start bit */
+		for (i = 0 ; i < 3 ; i++)
+			pc_tcode_actions(smc,i,phy) ;
+
+		/* Set the non-active interrupt mask register */
+		outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ;
+
+		/*
+		 * If the LCT was stopped. There might be a
+		 * PCM_CODE interrupt event present.
+		 * This must be cleared.
+		 */
+		(void)inpw(PLC(np,PL_INTR_EVENT)) ;
+#ifndef	MOT_ELM
+		/* Get the plc revision for revision dependent code */
+		plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ;
+
+		if (plc_rev != PLC_REV_SN3)
+#endif	/* MOT_ELM */
+		{
+			/*
+			 * No supernet III PLC, so set Xmit verctor and
+			 * length BEFORE starting the state machine.
+			 */
+			if (plc_send_bits(smc,phy,3)) {
+				return ;
+			}
+		}
+
+		/*
+		 * Now give the Start command.
+		 * - The start command shall be done before setting the bits
+		 *   to be signaled. (In PLC-S description and PLCS in SN3.
+		 * - The start command shall be issued AFTER setting the
+		 *   XMIT vector and the XMIT length register.
+		 *
+		 * We do it exactly according this specs for the old PLC and
+		 * the new PLCS inside the SN3.
+		 * For the usual PLCS we try it the way it is done for the
+		 * old PLC and set the XMIT registers again, if the PLC is
+		 * not in SIGNAL state. This is done according to an PLCS
+		 * errata workaround.
+		 */
+
+		plc_go_state(smc,np,PL_PCM_START) ;
+
+		/*
+		 * workaround for PLC-S eng. sample errata
+		 */
+#ifdef	MOT_ELM
+		if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
+#else	/* nMOT_ELM */
+		if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) !=
+			PLC_REVISION_A) &&
+			!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
+#endif	/* nMOT_ELM */
+		{
+			/*
+			 * Set register again (PLCS errata) or the first time
+			 * (new SN3 PLCS).
+			 */
+			(void) plc_send_bits(smc,phy,3) ;
+		}
+		/*
+		 * end of workaround
+		 */
+
+		GO_STATE(PC5_SIGNAL) ;
+		plc->p_state = PS_BIT3 ;
+		plc->p_bits = 3 ;
+		plc->p_start = 0 ;
+
+		break ;
+	case PC1_BREAK :
+		break ;
+	case ACTIONS(PC2_TRACE) :
+		plc_go_state(smc,np,PL_PCM_TRACE) ;
+		ACTIONS_DONE() ;
+		break ;
+	case PC2_TRACE :
+		break ;
+
+	case PC3_CONNECT :	/* these states are done by hardware */
+	case PC4_NEXT :
+		break ;
+
+	case ACTIONS(PC5_SIGNAL) :
+		ACTIONS_DONE() ;
+	case PC5_SIGNAL :
+		if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT))
+			break ;
+		switch (plc->p_state) {
+		case PS_BIT3 :
+			for (i = 0 ; i <= 2 ; i++)
+				pc_rcode_actions(smc,i,phy) ;
+			pc_tcode_actions(smc,3,phy) ;
+			plc->p_state = PS_BIT4 ;
+			plc->p_bits = 1 ;
+			plc->p_start = 3 ;
+			phy->bitn = 3 ;
+			if (plc_send_bits(smc,phy,1)) {
+				return ;
+			}
+			break ;
+		case PS_BIT4 :
+			pc_rcode_actions(smc,3,phy) ;
+			for (i = 4 ; i <= 6 ; i++)
+				pc_tcode_actions(smc,i,phy) ;
+			plc->p_state = PS_BIT7 ;
+			plc->p_bits = 3 ;
+			plc->p_start = 4 ;
+			phy->bitn = 4 ;
+			if (plc_send_bits(smc,phy,3)) {
+				return ;
+			}
+			break ;
+		case PS_BIT7 :
+			for (i = 3 ; i <= 6 ; i++)
+				pc_rcode_actions(smc,i,phy) ;
+			plc->p_state = PS_LCT ;
+			plc->p_bits = 0 ;
+			plc->p_start = 7 ;
+			phy->bitn = 7 ;
+		sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */
+			/* start LCT */
+			i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ;
+			outpw(PLC(np,PL_CNTRL_B),i) ;	/* must be cleared */
+			outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ;
+			break ;
+		case PS_LCT :
+			/* check for local LCT failure */
+			pc_tcode_actions(smc,7,phy) ;
+			/*
+			 * set tval[7]
+			 */
+			plc->p_state = PS_BIT8 ;
+			plc->p_bits = 1 ;
+			plc->p_start = 7 ;
+			phy->bitn = 7 ;
+			if (plc_send_bits(smc,phy,1)) {
+				return ;
+			}
+			break ;
+		case PS_BIT8 :
+			/* check for remote LCT failure */
+			pc_rcode_actions(smc,7,phy) ;
+			if (phy->t_val[7] || phy->r_val[7]) {
+				plc_go_state(smc,np,PL_PCM_STOP) ;
+				GO_STATE(PC1_BREAK) ;
+				break ;
+			}
+			for (i = 8 ; i <= 9 ; i++)
+				pc_tcode_actions(smc,i,phy) ;
+			plc->p_state = PS_JOIN ;
+			plc->p_bits = 2 ;
+			plc->p_start = 8 ;
+			phy->bitn = 8 ;
+			if (plc_send_bits(smc,phy,2)) {
+				return ;
+			}
+			break ;
+		case PS_JOIN :
+			for (i = 8 ; i <= 9 ; i++)
+				pc_rcode_actions(smc,i,phy) ;
+			plc->p_state = PS_ACTIVE ;
+			GO_STATE(PC6_JOIN) ;
+			break ;
+		}
+		break ;
+
+	case ACTIONS(PC6_JOIN) :
+		/*
+		 * prevent mux error when going from WRAP_A to WRAP_B
+		 */
+		if (smc->s.sas == SMT_DAS && np == PB &&
+			(smc->y[PA].pc_mode == PM_TREE ||
+			 smc->y[PB].pc_mode == PM_TREE)) {
+			SETMASK(PLC(np,PL_CNTRL_A),
+				PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
+			SETMASK(PLC(np,PL_CNTRL_B),
+				PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
+		}
+		SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
+		SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
+		ACTIONS_DONE() ;
+		cmd = 0 ;
+		/* fall thru */
+	case PC6_JOIN :
+		switch (plc->p_state) {
+		case PS_ACTIVE:
+			/*PC88b*/
+			if (!phy->cf_join) {
+				phy->cf_join = TRUE ;
+				queue_event(smc,EVENT_CFM,CF_JOIN+np) ; ;
+			}
+			if (cmd == PC_JOIN)
+				GO_STATE(PC8_ACTIVE) ;
+			/*PC82*/
+			if (cmd == PC_TRACE) {
+				GO_STATE(PC2_TRACE) ;
+				break ;
+			}
+			break ;
+		}
+		break ;
+
+	case PC7_VERIFY :
+		break ;
+
+	case ACTIONS(PC8_ACTIVE) :
+		/*
+		 * start LEM for SMT
+		 */
+		sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ;
+
+		phy->tr_flag = FALSE ;
+		mib->fddiPORTConnectState = PCM_ACTIVE ;
+
+		/* Set the active interrupt mask register */
+		outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ;
+
+		ACTIONS_DONE() ;
+		break ;
+	case PC8_ACTIVE :
+		/*PC81 is done by PL_TNE_EXPIRED irq */
+		/*PC82*/
+		if (cmd == PC_TRACE) {
+			GO_STATE(PC2_TRACE) ;
+			break ;
+		}
+		/*PC88c: is done by TRACE_PROP irq */
+
+		break ;
+	case ACTIONS(PC9_MAINT) :
+		stop_pcm_timer0(smc,phy) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;	/* disable LEM int. */
+		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
+		phy->cf_loop = FALSE ;
+		phy->cf_join = FALSE ;
+		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+		plc_go_state(smc,np,PL_PCM_STOP) ;
+		mib->fddiPORTConnectState = PCM_DISABLED ;
+		SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ;
+		sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ;
+		outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ;
+		ACTIONS_DONE() ;
+		break ;
+	case PC9_MAINT :
+		DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ;
+		/*PC90*/
+		if (cmd == PC_ENABLE) {
+			GO_STATE(PC0_OFF) ;
+			break ;
+		}
+		break ;
+
+	default:
+		SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ;
+		break ;
+	}
+}
+
+/*
+ * force line state on a PHY output	(only in MAINT state)
+ */
+static void sm_ph_linestate(smc,phy,ls)
+struct s_smc *smc ;
+int phy;
+int ls;
+{
+	int	cntrl ;
+
+	SK_UNUSED(smc) ;
+
+	cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) |
+						PL_PCM_STOP | PL_MAINT ;
+	switch(ls) {
+	case PC_QLS: 		/* Force Quiet */
+		cntrl |= PL_M_QUI0 ;
+		break ;
+	case PC_MLS: 		/* Force Master */
+		cntrl |= PL_M_MASTR ;
+		break ;
+	case PC_HLS: 		/* Force Halt */
+		cntrl |= PL_M_HALT ;
+		break ;
+	default :
+	case PC_ILS: 		/* Force Idle */
+		cntrl |= PL_M_IDLE ;
+		break ;
+	case PC_LS_PDR: 	/* Enable repeat filter */
+		cntrl |= PL_M_TPDR ;
+		break ;
+	}
+	outpw(PLC(phy,PL_CNTRL_B),cntrl) ;
+}
+
+
+static void reset_lem_struct(phy)
+struct s_phy *phy;
+{
+	struct lem_counter *lem = &phy->lem ;
+
+	phy->mib->fddiPORTLer_Estimate = 15 ;
+	lem->lem_float_ber = 15 * 100 ;
+}
+
+/*
+ * link error monitor
+ */
+static void lem_evaluate(smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy;
+{
+	int ber ;
+	u_long errors ;
+	struct lem_counter *lem = &phy->lem ;
+	struct fddi_mib_p	*mib ;
+	int			cond ;
+
+	mib = phy->mib ;
+
+	if (!lem->lem_on)
+		return ;
+
+	errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ;
+	lem->lem_errors += errors ;
+	mib->fddiPORTLem_Ct += errors ;
+
+	errors = lem->lem_errors ;
+	/*
+	 * calculation is called on a intervall of 8 seconds
+	 *	-> this means, that one error in 8 sec. is one of 8*125*10E6
+	 *	the same as BER = 10E-9
+	 * Please note:
+	 *	-> 9 errors in 8 seconds mean:
+	 *	   BER = 9 * 10E-9  and this is
+	 *	    < 10E-8, so the limit of 10E-8 is not reached!
+	 */
+
+		if (!errors)		ber = 15 ;
+	else	if (errors <= 9)	ber = 9 ;
+	else	if (errors <= 99)	ber = 8 ;
+	else	if (errors <= 999)	ber = 7 ;
+	else	if (errors <= 9999)	ber = 6 ;
+	else	if (errors <= 99999)	ber = 5 ;
+	else	if (errors <= 999999)	ber = 4 ;
+	else	if (errors <= 9999999)	ber = 3 ;
+	else	if (errors <= 99999999)	ber = 2 ;
+	else	if (errors <= 999999999) ber = 1 ;
+	else				ber = 0 ;
+
+	/*
+	 * weighted average
+	 */
+	ber *= 100 ;
+	lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ;
+	lem->lem_float_ber /= 10 ;
+	mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ;
+	if (mib->fddiPORTLer_Estimate < 4) {
+		mib->fddiPORTLer_Estimate = 4 ;
+	}
+
+	if (lem->lem_errors) {
+		DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ;
+		DB_PCMN(1,"errors      : %ld\n",lem->lem_errors,0) ;
+		DB_PCMN(1,"sum_errors  : %ld\n",mib->fddiPORTLem_Ct,0) ;
+		DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ;
+		DB_PCMN(1,"float BER   : 10E-(%d/100)\n",lem->lem_float_ber,0) ;
+		DB_PCMN(1,"avg. BER    : 10E-%d\n",
+			mib->fddiPORTLer_Estimate,0) ;
+	}
+
+	lem->lem_errors = 0L ;
+
+#ifndef	SLIM_SMT
+	cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ?
+		TRUE : FALSE ;
+#ifdef	SMT_EXT_CUTOFF
+	smt_ler_alarm_check(smc,phy,cond) ;
+#endif	/* nSMT_EXT_CUTOFF */
+	if (cond != mib->fddiPORTLerFlag) {
+		smt_srf_event(smc,SMT_COND_PORT_LER,
+			(int) (INDEX_PORT+ phy->np) ,cond) ;
+	}
+#endif
+
+	if (	mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) {
+		phy->pc_lem_fail = TRUE ;		/* flag */
+		mib->fddiPORTLem_Reject_Ct++ ;
+		/*
+		 * "forgive 10e-2" if we cutoff so we can come
+		 * up again ..
+		 */
+		lem->lem_float_ber += 2*100 ;
+
+		/*PC81b*/
+#ifdef	CONCENTRATOR
+		DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n",
+			phy->np, mib->fddiPORTLer_Cutoff) ;
+#endif
+#ifdef	SMT_EXT_CUTOFF
+		smt_port_off_event(smc,phy->np);
+#else	/* nSMT_EXT_CUTOFF */
+		queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
+#endif	/* nSMT_EXT_CUTOFF */
+	}
+}
+
+/*
+ * called by SMT to calculate LEM bit error rate
+ */
+void sm_lem_evaluate(smc)
+struct s_smc *smc ;
+{
+	int np ;
+
+	for (np = 0 ; np < NUMPHYS ; np++)
+		lem_evaluate(smc,&smc->y[np]) ;
+}
+
+static void lem_check_lct(smc,phy)
+struct s_smc *smc ;
+struct s_phy	*phy ;
+{
+	struct lem_counter	*lem = &phy->lem ;
+	struct fddi_mib_p	*mib ;
+	int errors ;
+
+	mib = phy->mib ;
+
+	phy->pc_lem_fail = FALSE ;		/* flag */
+	errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ;
+	lem->lem_errors += errors ;
+	mib->fddiPORTLem_Ct += errors ;
+	if (lem->lem_errors) {
+		switch(phy->lc_test) {
+		case LC_SHORT:
+			if (lem->lem_errors >= smc->s.lct_short)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		case LC_MEDIUM:
+			if (lem->lem_errors >= smc->s.lct_medium)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		case LC_LONG:
+			if (lem->lem_errors >= smc->s.lct_long)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		case LC_EXTENDED:
+			if (lem->lem_errors >= smc->s.lct_extended)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		}
+		DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ;
+	}
+	if (phy->pc_lem_fail) {
+		mib->fddiPORTLCTFail_Ct++ ;
+		mib->fddiPORTLem_Reject_Ct++ ;
+	}
+	else
+		mib->fddiPORTLCTFail_Ct = 0 ;
+}
+
+/*
+ * LEM functions
+ */
+static void sm_ph_lem_start(smc,np,threshold)
+struct s_smc *smc ;
+int np;
+int threshold;
+{
+	struct lem_counter *lem = &smc->y[np].lem ;
+
+	lem->lem_on = 1 ;
+	lem->lem_errors = 0L ;
+
+	/* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too
+	 * often.
+	 */
+
+	outpw(PLC(np,PL_LE_THRESHOLD),threshold) ;
+	(void)inpw(PLC(np,PL_LINK_ERR_CTR)) ;	/* clear error counter */
+
+	/* enable LE INT */
+	SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ;
+}
+
+static void sm_ph_lem_stop(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	struct lem_counter *lem = &smc->y[np].lem ;
+
+	lem->lem_on = 0 ;
+	CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;
+}
+
+/* ARGSUSED */
+void sm_pm_ls_latch(smc,phy,on_off)
+struct s_smc *smc ;
+int phy;
+int on_off;		/* en- or disable ident. ls */
+{
+	SK_UNUSED(smc) ;
+
+	phy = phy ; on_off = on_off ;
+}
+
+
+/*
+ * PCM pseudo code
+ * receive actions are called AFTER the bit n is received,
+ * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received
+ */
+
+/*
+ * PCM pseudo code 5.1 .. 6.1
+ */
+static void pc_rcode_actions(smc,bit,phy)
+struct s_smc *smc ;
+int bit;
+struct s_phy *phy;
+{
+	struct fddi_mib_p	*mib ;
+
+	mib = phy->mib ;
+
+	DB_PCMN(1,"SIG rec %x %x: \n", bit,phy->r_val[bit] ) ;
+	bit++ ;
+
+	switch(bit) {
+	case 0:
+	case 1:
+	case 2:
+		break ;
+	case 3 :
+		if (phy->r_val[1] == 0 && phy->r_val[2] == 0)
+			mib->fddiPORTNeighborType = TA ;
+		else if (phy->r_val[1] == 0 && phy->r_val[2] == 1)
+			mib->fddiPORTNeighborType = TB ;
+		else if (phy->r_val[1] == 1 && phy->r_val[2] == 0)
+			mib->fddiPORTNeighborType = TS ;
+		else if (phy->r_val[1] == 1 && phy->r_val[2] == 1)
+			mib->fddiPORTNeighborType = TM ;
+		break ;
+	case 4:
+		if (mib->fddiPORTMy_Type == TM &&
+			mib->fddiPORTNeighborType == TM) {
+			DB_PCMN(1,"PCM %c : E100 withhold M-M\n",
+				phy->phy_name,0) ;
+			mib->fddiPORTPC_Withhold = PC_WH_M_M ;
+			RS_SET(smc,RS_EVENT) ;
+		}
+		else if (phy->t_val[3] || phy->r_val[3]) {
+			mib->fddiPORTPC_Withhold = PC_WH_NONE ;
+			if (mib->fddiPORTMy_Type == TM ||
+			    mib->fddiPORTNeighborType == TM)
+				phy->pc_mode = PM_TREE ;
+			else
+				phy->pc_mode = PM_PEER ;
+
+			/* reevaluate the selection criteria (wc_flag) */
+			all_selection_criteria (smc);
+
+			if (phy->wc_flag) {
+				mib->fddiPORTPC_Withhold = PC_WH_PATH ;
+			}
+		}
+		else {
+			mib->fddiPORTPC_Withhold = PC_WH_OTHER ;
+			RS_SET(smc,RS_EVENT) ;
+			DB_PCMN(1,"PCM %c : E101 withhold other\n",
+				phy->phy_name,0) ;
+		}
+		phy->twisted = ((mib->fddiPORTMy_Type != TS) &&
+				(mib->fddiPORTMy_Type != TM) &&
+				(mib->fddiPORTNeighborType ==
+				mib->fddiPORTMy_Type)) ;
+		if (phy->twisted) {
+			DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n",
+				phy->phy_name,0) ;
+		}
+		break ;
+	case 5 :
+		break ;
+	case 6:
+		if (phy->t_val[4] || phy->r_val[4]) {
+			if ((phy->t_val[4] && phy->t_val[5]) ||
+			    (phy->r_val[4] && phy->r_val[5]) )
+				phy->lc_test = LC_EXTENDED ;
+			else
+				phy->lc_test = LC_LONG ;
+		}
+		else if (phy->t_val[5] || phy->r_val[5])
+			phy->lc_test = LC_MEDIUM ;
+		else
+			phy->lc_test = LC_SHORT ;
+		switch (phy->lc_test) {
+		case LC_SHORT :				/* 50ms */
+			outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ;
+			phy->t_next[7] = smc->s.pcm_lc_short ;
+			break ;
+		case LC_MEDIUM :			/* 500ms */
+			outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ;
+			phy->t_next[7] = smc->s.pcm_lc_medium ;
+			break ;
+		case LC_LONG :
+			SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
+			phy->t_next[7] = smc->s.pcm_lc_long ;
+			break ;
+		case LC_EXTENDED :
+			SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
+			phy->t_next[7] = smc->s.pcm_lc_extended ;
+			break ;
+		}
+		if (phy->t_next[7] > smc->s.pcm_lc_medium) {
+			start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy);
+		}
+		DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ;
+		phy->t_next[9] = smc->s.pcm_t_next_9 ;
+		break ;
+	case 7:
+		if (phy->t_val[6]) {
+			phy->cf_loop = TRUE ;
+		}
+		phy->td_flag = TRUE ;
+		break ;
+	case 8:
+		if (phy->t_val[7] || phy->r_val[7]) {
+			DB_PCMN(1,"PCM %c : E103 LCT fail %s\n",
+				phy->phy_name,phy->t_val[7]? "local":"remote") ;
+			queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
+		}
+		break ;
+	case 9:
+		if (phy->t_val[8] || phy->r_val[8]) {
+			if (phy->t_val[8])
+				phy->cf_loop = TRUE ;
+			phy->td_flag = TRUE ;
+		}
+		break ;
+	case 10:
+		if (phy->r_val[9]) {
+			/* neighbor intends to have MAC on output */ ;
+			mib->fddiPORTMacIndicated.R_val = TRUE ;
+		}
+		else {
+			/* neighbor does not intend to have MAC on output */ ;
+			mib->fddiPORTMacIndicated.R_val = FALSE ;
+		}
+		break ;
+	}
+}
+
+/*
+ * PCM pseudo code 5.1 .. 6.1
+ */
+static void pc_tcode_actions(smc,bit,phy)
+struct s_smc *smc ;
+const int bit;
+struct s_phy *phy;
+{
+	int	np = phy->np ;
+	struct fddi_mib_p	*mib ;
+
+	mib = phy->mib ;
+
+	switch(bit) {
+	case 0:
+		phy->t_val[0] = 0 ;		/* no escape used */
+		break ;
+	case 1:
+		if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM)
+			phy->t_val[1] = 1 ;
+		else
+			phy->t_val[1] = 0 ;
+		break ;
+	case 2 :
+		if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM)
+			phy->t_val[2] = 1 ;
+		else
+			phy->t_val[2] = 0 ;
+		break ;
+	case 3:
+		{
+		int	type,ne ;
+		int	policy ;
+
+		type = mib->fddiPORTMy_Type ;
+		ne = mib->fddiPORTNeighborType ;
+		policy = smc->mib.fddiSMTConnectionPolicy ;
+
+		phy->t_val[3] = 1 ;	/* Accept connection */
+		switch (type) {
+		case TA :
+			if (
+				((policy & POLICY_AA) && ne == TA) ||
+				((policy & POLICY_AB) && ne == TB) ||
+				((policy & POLICY_AS) && ne == TS) ||
+				((policy & POLICY_AM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		case TB :
+			if (
+				((policy & POLICY_BA) && ne == TA) ||
+				((policy & POLICY_BB) && ne == TB) ||
+				((policy & POLICY_BS) && ne == TS) ||
+				((policy & POLICY_BM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		case TS :
+			if (
+				((policy & POLICY_SA) && ne == TA) ||
+				((policy & POLICY_SB) && ne == TB) ||
+				((policy & POLICY_SS) && ne == TS) ||
+				((policy & POLICY_SM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		case TM :
+			if (	ne == TM ||
+				((policy & POLICY_MA) && ne == TA) ||
+				((policy & POLICY_MB) && ne == TB) ||
+				((policy & POLICY_MS) && ne == TS) ||
+				((policy & POLICY_MM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		}
+#ifndef	SLIM_SMT
+		/*
+		 * detect undesirable connection attempt event
+		 */
+		if (	(type == TA && ne == TA ) ||
+			(type == TA && ne == TS ) ||
+			(type == TB && ne == TB ) ||
+			(type == TB && ne == TS ) ||
+			(type == TS && ne == TA ) ||
+			(type == TS && ne == TB ) ) {
+			smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION,
+				(int) (INDEX_PORT+ phy->np) ,0) ;
+		}
+#endif
+		}
+		break ;
+	case 4:
+		if (mib->fddiPORTPC_Withhold == PC_WH_NONE) {
+			if (phy->pc_lem_fail) {
+				phy->t_val[4] = 1 ;	/* long */
+				phy->t_val[5] = 0 ;
+			}
+			else {
+				phy->t_val[4] = 0 ;
+				if (mib->fddiPORTLCTFail_Ct > 0)
+					phy->t_val[5] = 1 ;	/* medium */
+				else
+					phy->t_val[5] = 0 ;	/* short */
+
+				/*
+				 * Implementers choice: use medium
+				 * instead of short when undesired
+				 * connection attempt is made.
+				 */
+				if (phy->wc_flag)
+					phy->t_val[5] = 1 ;	/* medium */
+			}
+			mib->fddiPORTConnectState = PCM_CONNECTING ;
+		}
+		else {
+			mib->fddiPORTConnectState = PCM_STANDBY ;
+			phy->t_val[4] = 1 ;	/* extended */
+			phy->t_val[5] = 1 ;
+		}
+		break ;
+	case 5:
+		break ;
+	case 6:
+		/* we do NOT have a MAC for LCT */
+		phy->t_val[6] = 0 ;
+		break ;
+	case 7:
+		phy->cf_loop = FALSE ;
+		lem_check_lct(smc,phy) ;
+		if (phy->pc_lem_fail) {
+			DB_PCMN(1,"PCM %c : E104 LCT failed\n",
+				phy->phy_name,0) ;
+			phy->t_val[7] = 1 ;
+		}
+		else
+			phy->t_val[7] = 0 ;
+		break ;
+	case 8:
+		phy->t_val[8] = 0 ;	/* Don't request MAC loopback */
+		break ;
+	case 9:
+		phy->cf_loop = 0 ;
+		if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) ||
+		     ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) {
+			queue_event(smc,EVENT_PCM+np,PC_START) ;
+			break ;
+		}
+		phy->t_val[9] = FALSE ;
+		switch (smc->s.sas) {
+		case SMT_DAS :
+			/*
+			 * MAC intended on output
+			 */
+			if (phy->pc_mode == PM_TREE) {
+				if ((np == PB) || ((np == PA) &&
+				(smc->y[PB].mib->fddiPORTConnectState !=
+					PCM_ACTIVE)))
+					phy->t_val[9] = TRUE ;
+			}
+			else {
+				if (np == PB)
+					phy->t_val[9] = TRUE ;
+			}
+			break ;
+		case SMT_SAS :
+			if (np == PS)
+				phy->t_val[9] = TRUE ;
+			break ;
+#ifdef	CONCENTRATOR
+		case SMT_NAC :
+			/*
+			 * MAC intended on output
+			 */
+			if (np == PB)
+				phy->t_val[9] = TRUE ;
+			break ;
+#endif
+		}
+		mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ;
+		break ;
+	}
+	DB_PCMN(1,"SIG snd %x %x: \n", bit,phy->t_val[bit] ) ;
+}
+
+/*
+ * return status twisted (called by SMT)
+ */
+int pcm_status_twisted(smc)
+struct s_smc *smc ;
+{
+	int	twist = 0 ;
+	if (smc->s.sas != SMT_DAS)
+		return(0) ;
+	if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE))
+		twist |= 1 ;
+	if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE))
+		twist |= 2 ;
+	return(twist) ;
+}
+
+/*
+ * return status	(called by SMT)
+ *	type
+ *	state
+ *	remote phy type
+ *	remote mac yes/no
+ */
+void pcm_status_state(smc,np,type,state,remote,mac)
+struct s_smc *smc ;
+int np;
+int *type;
+int *state;
+int *remote;
+int *mac;
+{
+	struct s_phy	*phy = &smc->y[np] ;
+	struct fddi_mib_p	*mib ;
+
+	mib = phy->mib ;
+
+	/* remote PHY type and MAC - set only if active */
+	*mac = 0 ;
+	*type = mib->fddiPORTMy_Type ;		/* our PHY type */
+	*state = mib->fddiPORTConnectState ;
+	*remote = mib->fddiPORTNeighborType ;
+
+	switch(mib->fddiPORTPCMState) {
+	case PC8_ACTIVE :
+		*mac = mib->fddiPORTMacIndicated.R_val ;
+		break ;
+	}
+}
+
+/*
+ * return rooted station status (called by SMT)
+ */
+int pcm_rooted_station(smc)
+struct s_smc *smc ;
+{
+	int	n ;
+
+	for (n = 0 ; n < NUMPHYS ; n++) {
+		if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE &&
+		    smc->y[n].mib->fddiPORTNeighborType == TM)
+			return(0) ;
+	}
+	return(1) ;
+}
+
+/*
+ * Interrupt actions for PLC & PCM events
+ */
+void plc_irq(smc,np,cmd)
+struct s_smc *smc ;
+int np;			/* PHY index */
+unsigned int cmd;
+{
+	struct s_phy *phy = &smc->y[np] ;
+	struct s_plc *plc = &phy->plc ;
+	int		n ;
+#ifdef	SUPERNET_3
+	int		corr_mask ;
+#endif	/* SUPERNET_3 */
+	int		i ;
+
+	if (np >= smc->s.numphys) {
+		plc->soft_err++ ;
+		return ;
+	}
+	if (cmd & PL_EBUF_ERR) {	/* elastic buff. det. over-|underflow*/
+		/*
+		 * Check whether the SRF Condition occured.
+		 */
+		if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
+			/*
+			 * This is the real Elasticity Error.
+			 * More than one in a row are treated as a
+			 * single one.
+			 * Only count this in the active state.
+			 */
+			phy->mib->fddiPORTEBError_Ct ++ ;
+
+		}
+
+		plc->ebuf_err++ ;
+		if (plc->ebuf_cont <= 1000) {
+			/*
+			 * Prevent counter from being wrapped after
+			 * hanging years in that interrupt.
+			 */
+			plc->ebuf_cont++ ;	/* Ebuf continous error */
+		}
+
+#ifdef	SUPERNET_3
+		if (plc->ebuf_cont == 1000 &&
+			((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) ==
+			PLC_REV_SN3)) {
+			/*
+			 * This interrupt remeained high for at least
+			 * 1000 consecutive interrupt calls.
+			 *
+			 * This is caused by a hardware error of the
+			 * ORION part of the Supernet III chipset.
+			 *
+			 * Disable this bit from the mask.
+			 */
+			corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ;
+			outpw(PLC(np,PL_INTR_MASK),corr_mask);
+
+			/*
+			 * Disconnect from the ring.
+			 * Call the driver with the reset indication.
+			 */
+			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+
+			/*
+			 * Make an error log entry.
+			 */
+			SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ;
+
+			/*
+			 * Indicate the Reset.
+			 */
+			drv_reset_indication(smc) ;
+		}
+#endif	/* SUPERNET_3 */
+	} else {
+		/* Reset the continous error variable */
+		plc->ebuf_cont = 0 ;	/* reset Ebuf continous error */
+	}
+	if (cmd & PL_PHYINV) {		/* physical layer invalid signal */
+		plc->phyinv++ ;
+	}
+	if (cmd & PL_VSYM_CTR) {	/* violation symbol counter has incr.*/
+		plc->vsym_ctr++ ;
+	}
+	if (cmd & PL_MINI_CTR) {	/* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
+		plc->mini_ctr++ ;
+	}
+	if (cmd & PL_LE_CTR) {		/* link error event counter */
+		int	j ;
+
+		/*
+		 * note: PL_LINK_ERR_CTR MUST be read to clear it
+		 */
+		j = inpw(PLC(np,PL_LE_THRESHOLD)) ;
+		i = inpw(PLC(np,PL_LINK_ERR_CTR)) ;
+
+		if (i < j) {
+			/* wrapped around */
+			i += 256 ;
+		}
+
+		if (phy->lem.lem_on) {
+			/* Note: Lem errors shall only be counted when
+			 * link is ACTIVE or LCT is active.
+			 */
+			phy->lem.lem_errors += i ;
+			phy->mib->fddiPORTLem_Ct += i ;
+		}
+	}
+	if (cmd & PL_TPC_EXPIRED) {	/* TPC timer reached zero */
+		if (plc->p_state == PS_LCT) {
+			/*
+			 * end of LCT
+			 */
+			;
+		}
+		plc->tpc_exp++ ;
+	}
+	if (cmd & PL_LS_MATCH) {	/* LS == LS in PLC_CNTRL_B's MATCH_LS*/
+		switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) {
+		case PL_I_IDLE :	phy->curr_ls = PC_ILS ;		break ;
+		case PL_I_HALT :	phy->curr_ls = PC_HLS ;		break ;
+		case PL_I_MASTR :	phy->curr_ls = PC_MLS ;		break ;
+		case PL_I_QUIET :	phy->curr_ls = PC_QLS ;		break ;
+		}
+	}
+	if (cmd & PL_PCM_BREAK) {	/* PCM has entered the BREAK state */
+		int	reason;
+
+		reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ;
+
+		switch (reason) {
+		case PL_B_PCS :		plc->b_pcs++ ;	break ;
+		case PL_B_TPC :		plc->b_tpc++ ;	break ;
+		case PL_B_TNE :		plc->b_tne++ ;	break ;
+		case PL_B_QLS :		plc->b_qls++ ;	break ;
+		case PL_B_ILS :		plc->b_ils++ ;	break ;
+		case PL_B_HLS :		plc->b_hls++ ;	break ;
+		}
+
+		/*jd 05-Aug-1999 changed: Bug #10419 */
+		DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag);
+		if (smc->e.DisconnectFlag == FALSE) {
+			DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason);
+			queue_event(smc,EVENT_PCM+np,PC_START) ;
+		}
+		else {
+			DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason);
+		}
+		return ;
+	}
+	/*
+	 * If both CODE & ENABLE are set ignore enable
+	 */
+	if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */
+		queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ;
+		n = inpw(PLC(np,PL_RCV_VECTOR)) ;
+		for (i = 0 ; i < plc->p_bits ; i++) {
+			phy->r_val[plc->p_start+i] = n & 1 ;
+			n >>= 1 ;
+		}
+	}
+	else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/
+		queue_event(smc,EVENT_PCM+np,PC_JOIN) ;
+	}
+	if (cmd & PL_TRACE_PROP) {	/* MLS while PC8_ACTIV || PC2_TRACE */
+		/*PC22b*/
+		if (!phy->tr_flag) {
+			DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n",
+				np,smc->mib.fddiSMTECMState) ;
+			phy->tr_flag = TRUE ;
+			smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ;
+			queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
+		}
+	}
+	/*
+	 * filter PLC glitch ???
+	 * QLS || HLS only while in PC2_TRACE state
+	 */
+	if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) {
+		/*PC22a*/
+		if (smc->e.path_test == PT_PASSED) {
+			DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np),
+				phy->mib->fddiPORTPCMState) ;
+
+			smc->e.path_test = PT_PENDING ;
+			queue_event(smc,EVENT_ECM,EC_PATH_TEST) ;
+		}
+	}
+	if (cmd & PL_TNE_EXPIRED) {	/* TNE: length of noise events */
+		/* break_required (TNE > NS_Max) */
+		if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) {
+			if (!phy->tr_flag) {
+			   DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE");
+			   queue_event(smc,EVENT_PCM+np,PC_START) ;
+			   return ;
+			}
+		}
+	}
+#if	0
+	if (cmd & PL_NP_ERR) {		/* NP has requested to r/w an inv reg*/
+		/*
+		 * It's a bug by AMD
+		 */
+		plc->np_err++ ;
+	}
+	/* pin inactiv (GND) */
+	if (cmd & PL_PARITY_ERR) {	/* p. error dedected on TX9-0 inp */
+		plc->parity_err++ ;
+	}
+	if (cmd & PL_LSDO) {		/* carrier detected */
+		;
+	}
+#endif
+}
+
+void pcm_set_lct_short(smc,n)
+struct s_smc *smc ;
+int n ;
+{
+	if (n <= 0 || n > 1000)
+		return ;
+	smc->s.lct_short = n ;
+}
+
+#ifdef	DEBUG
+/*
+ * fill state struct
+ */
+void pcm_get_state(smc,state)
+struct s_smc *smc ;
+struct smt_state *state ;
+{
+	struct s_phy	*phy ;
+	struct pcm_state *pcs ;
+	int	i ;
+	int	ii ;
+	short	rbits ;
+	short	tbits ;
+	struct fddi_mib_p	*mib ;
+
+	for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ;
+		i++ , phy++, pcs++ ) {
+		mib = phy->mib ;
+		pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ;
+		pcs->pcm_state = (u_char) mib->fddiPORTPCMState ;
+		pcs->pcm_mode = phy->pc_mode ;
+		pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ;
+		pcs->pcm_bsf = mib->fddiPORTBS_Flag ;
+		pcs->pcm_lsf = phy->ls_flag ;
+		pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ;
+		pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ;
+		for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) {
+			rbits <<= 1 ;
+			tbits <<= 1 ;
+			if (phy->r_val[NUMBITS-1-ii])
+				rbits |= 1 ;
+			if (phy->t_val[NUMBITS-1-ii])
+				tbits |= 1 ;
+		}
+		pcs->pcm_r_val = rbits ;
+		pcs->pcm_t_val = tbits ;
+	}
+}
+
+int get_pcm_state(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	int pcs ;
+
+	SK_UNUSED(smc) ;
+
+	switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
+		case PL_PC0 :	pcs = PC_STOP ;		break ;
+		case PL_PC1 :	pcs = PC_START ;	break ;
+		case PL_PC2 :	pcs = PC_TRACE ;	break ;
+		case PL_PC3 :	pcs = PC_SIGNAL ;	break ;
+		case PL_PC4 :	pcs = PC_SIGNAL ;	break ;
+		case PL_PC5 :	pcs = PC_SIGNAL ;	break ;
+		case PL_PC6 :	pcs = PC_JOIN ;		break ;
+		case PL_PC7 :	pcs = PC_JOIN ;		break ;
+		case PL_PC8 :	pcs = PC_ENABLE ;	break ;
+		case PL_PC9 :	pcs = PC_MAINT ;	break ;
+		default :	pcs = PC_DISABLE ; 	break ;
+	}
+	return(pcs) ;
+}
+
+char *get_linestate(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	char *ls = "" ;
+
+	SK_UNUSED(smc) ;
+
+	switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) {
+		case PL_L_NLS :	ls = "NOISE" ;	break ;
+		case PL_L_ALS :	ls = "ACTIV" ;	break ;
+		case PL_L_UND :	ls = "UNDEF" ;	break ;
+		case PL_L_ILS4:	ls = "ILS 4" ;	break ;
+		case PL_L_QLS :	ls = "QLS" ;	break ;
+		case PL_L_MLS :	ls = "MLS" ;	break ;
+		case PL_L_HLS :	ls = "HLS" ;	break ;
+		case PL_L_ILS16:ls = "ILS16" ;	break ;
+#ifdef	lint
+		default:	ls = "unknown" ; break ;
+#endif
+	}
+	return(ls) ;
+}
+
+char *get_pcmstate(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	char *pcs ;
+	
+	SK_UNUSED(smc) ;
+
+	switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
+		case PL_PC0 :	pcs = "OFF" ;		break ;
+		case PL_PC1 :	pcs = "BREAK" ;		break ;
+		case PL_PC2 :	pcs = "TRACE" ;		break ;
+		case PL_PC3 :	pcs = "CONNECT";	break ;
+		case PL_PC4 :	pcs = "NEXT" ;		break ;
+		case PL_PC5 :	pcs = "SIGNAL" ;	break ;
+		case PL_PC6 :	pcs = "JOIN" ;		break ;
+		case PL_PC7 :	pcs = "VERIFY" ;	break ;
+		case PL_PC8 :	pcs = "ACTIV" ;		break ;
+		case PL_PC9 :	pcs = "MAINT" ;		break ;
+		default :	pcs = "UNKNOWN" ; 	break ;
+	}
+	return(pcs) ;
+}
+
+void list_phy(smc)
+struct s_smc *smc ;
+{
+	struct s_plc *plc ;
+	int np ;
+
+	for (np = 0 ; np < NUMPHYS ; np++) {
+		plc  = &smc->y[np].plc ;
+		printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ;
+		printf("\tsoft_error: %ld \t\tPC_Start : %ld\n",
+						plc->soft_err,plc->b_pcs);
+		printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n",
+			plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ;
+		printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n",
+						plc->ebuf_err,plc->b_tne) ;
+		printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n",
+			plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ;
+		printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n",
+						plc->vsym_ctr,plc->b_ils)  ;
+		printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n",
+						plc->mini_ctr,plc->b_hls) ;
+		printf("\tnodepr_err: %ld\n",plc->np_err) ;
+		printf("\tTPC_exp : %ld\n",plc->tpc_exp) ;
+		printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ;
+	}
+}
+
+
+#ifdef	CONCENTRATOR
+void pcm_lem_dump(smc)
+struct s_smc *smc ;
+{
+	int		i ;
+	struct s_phy	*phy ;
+	struct fddi_mib_p	*mib ;
+
+	char		*entostring() ;
+
+	printf("PHY	errors	BER\n") ;
+	printf("----------------------\n") ;
+	for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) {
+		if (!plc_is_installed(smc,i))
+			continue ;
+		mib = phy->mib ;
+		printf("%s\t%ld\t10E-%d\n",
+			entostring(smc,ENTITY_PHY(i)),
+			mib->fddiPORTLem_Ct,
+			mib->fddiPORTLer_Estimate) ;
+	}
+}
+#endif
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/pmf.c linux/drivers/net/skfp/pmf.c
--- v2.3.46/linux/drivers/net/skfp/pmf.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/pmf.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,1701 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	Parameter Management Frame processing for SMT 7.2
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	SLIM_SMT
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)pmf.c	1.37 97/08/04 (C) SK " ;
+#endif
+
+static int smt_authorize() ;
+static int smt_check_set_count() ;
+static const struct s_p_tab *smt_get_ptab() ;
+static int smt_mib_phys() ;
+int smt_set_para() ;
+void smt_add_para() ;
+
+#define MOFFSS(e)	((int)&(((struct fddi_mib *)0)->e))
+#define MOFFSA(e)	((int) (((struct fddi_mib *)0)->e))
+
+#define MOFFMS(e)	((int)&(((struct fddi_mib_m *)0)->e))
+#define MOFFMA(e)	((int) (((struct fddi_mib_m *)0)->e))
+
+#define MOFFAS(e)	((int)&(((struct fddi_mib_a *)0)->e))
+#define MOFFAA(e)	((int) (((struct fddi_mib_a *)0)->e))
+
+#define MOFFPS(e)	((int)&(((struct fddi_mib_p *)0)->e))
+#define MOFFPA(e)	((int) (((struct fddi_mib_p *)0)->e))
+
+
+#define AC_G	0x01		/* Get */
+#define AC_GR	0x02		/* Get/Set */
+#define AC_S	0x04		/* Set */
+#define AC_NA	0x08
+#define AC_GROUP	0x10		/* Group */
+#define MS2BCLK(x)	((x)*12500L)
+/*
+	F	LFag (byte)
+	B	byte
+	S	u_short	16 bit
+	C	Counter 32 bit
+	L	Long 32 bit
+	T	Timer_2	32 bit
+	P	TimeStamp ;
+	A	LongAddress (6 byte)
+	E	Enum 16 bit
+	R	ResId 16 Bit
+*/
+static const struct s_p_tab {
+	u_short	p_num ;		/* parameter code */
+	u_char	p_access ;	/* access rights */
+	u_short	p_offset ;	/* offset in mib */
+	char	p_swap[3] ;	/* format string */
+} p_tab[] = {
+	/* StationIdGrp */
+	{ SMT_P100A,AC_GROUP	} ,
+	{ SMT_P100B,AC_G,	MOFFSS(fddiSMTStationId),	"8"	} ,
+	{ SMT_P100D,AC_G,	MOFFSS(fddiSMTOpVersionId),	"S"	} ,
+	{ SMT_P100E,AC_G,	MOFFSS(fddiSMTHiVersionId),	"S"	} ,
+	{ SMT_P100F,AC_G,	MOFFSS(fddiSMTLoVersionId),	"S"	} ,
+	{ SMT_P1010,AC_G,	MOFFSA(fddiSMTManufacturerData), "D" } ,
+	{ SMT_P1011,AC_GR,	MOFFSA(fddiSMTUserData),	"D"	} ,
+	{ SMT_P1012,AC_G,	MOFFSS(fddiSMTMIBVersionId),	"S"	} ,
+
+	/* StationConfigGrp */
+	{ SMT_P1014,AC_GROUP	} ,
+	{ SMT_P1015,AC_G,	MOFFSS(fddiSMTMac_Ct),		"B"	} ,
+	{ SMT_P1016,AC_G,	MOFFSS(fddiSMTNonMaster_Ct),	"B"	} ,
+	{ SMT_P1017,AC_G,	MOFFSS(fddiSMTMaster_Ct),	"B"	} ,
+	{ SMT_P1018,AC_G,	MOFFSS(fddiSMTAvailablePaths),	"B"	} ,
+	{ SMT_P1019,AC_G,	MOFFSS(fddiSMTConfigCapabilities),"S"	} ,
+	{ SMT_P101A,AC_GR,	MOFFSS(fddiSMTConfigPolicy),	"wS"	} ,
+	{ SMT_P101B,AC_GR,	MOFFSS(fddiSMTConnectionPolicy),"wS"	} ,
+	{ SMT_P101D,AC_GR,	MOFFSS(fddiSMTTT_Notify),	"wS"	} ,
+	{ SMT_P101E,AC_GR,	MOFFSS(fddiSMTStatRptPolicy),	"bB"	} ,
+	{ SMT_P101F,AC_GR,	MOFFSS(fddiSMTTrace_MaxExpiration),"lL"	} ,
+	{ SMT_P1020,AC_G,	MOFFSA(fddiSMTPORTIndexes),	"II"	} ,
+	{ SMT_P1021,AC_G,	MOFFSS(fddiSMTMACIndexes),	"I"	} ,
+	{ SMT_P1022,AC_G,	MOFFSS(fddiSMTBypassPresent),	"F"	} ,
+
+	/* StatusGrp */
+	{ SMT_P1028,AC_GROUP	} ,
+	{ SMT_P1029,AC_G,	MOFFSS(fddiSMTECMState),	"E"	} ,
+	{ SMT_P102A,AC_G,	MOFFSS(fddiSMTCF_State),	"E"	} ,
+	{ SMT_P102C,AC_G,	MOFFSS(fddiSMTRemoteDisconnectFlag),"F"	} ,
+	{ SMT_P102D,AC_G,	MOFFSS(fddiSMTStationStatus),	"E"	} ,
+	{ SMT_P102E,AC_G,	MOFFSS(fddiSMTPeerWrapFlag),	"F"	} ,
+
+	/* MIBOperationGrp */
+	{ SMT_P1032,AC_GROUP	} ,
+	{ SMT_P1033,AC_G,	MOFFSA(fddiSMTTimeStamp),"P"		} ,
+	{ SMT_P1034,AC_G,	MOFFSA(fddiSMTTransitionTimeStamp),"P"	} ,
+	/* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */
+	{ SMT_P1035,AC_G,	MOFFSS(fddiSMTSetCount),"4P"		} ,
+	{ SMT_P1036,AC_G,	MOFFSS(fddiSMTLastSetStationId),"8"	} ,
+
+	{ SMT_P103C,AC_S,	0,				"wS"	} ,
+
+	/*
+	 * PRIVATE EXTENSIONS
+	 * only accessable locally to get/set passwd
+	 */
+	{ SMT_P10F0,AC_GR,	MOFFSA(fddiPRPMFPasswd),	"8"	} ,
+	{ SMT_P10F1,AC_GR,	MOFFSS(fddiPRPMFStation),	"8"	} ,
+#ifdef	ESS
+	{ SMT_P10F2,AC_GR,	MOFFSS(fddiESSPayload),		"lL"	} ,
+	{ SMT_P10F3,AC_GR,	MOFFSS(fddiESSOverhead),	"lL"	} ,
+	{ SMT_P10F4,AC_GR,	MOFFSS(fddiESSMaxTNeg),		"lL"	} ,
+	{ SMT_P10F5,AC_GR,	MOFFSS(fddiESSMinSegmentSize),	"lL"	} ,
+	{ SMT_P10F6,AC_GR,	MOFFSS(fddiESSCategory),	"lL"	} ,
+	{ SMT_P10F7,AC_GR,	MOFFSS(fddiESSSynchTxMode),	"wS"	} ,
+#endif
+#ifdef	SBA
+	{ SMT_P10F8,AC_GR,	MOFFSS(fddiSBACommand),		"bF"	} ,
+	{ SMT_P10F9,AC_GR,	MOFFSS(fddiSBAAvailable),	"bF"	} ,
+#endif
+	/* MAC Attributes */
+	{ SMT_P200A,AC_GROUP	} ,
+	{ SMT_P200B,AC_G,	MOFFMS(fddiMACFrameStatusFunctions),"S"	} ,
+	{ SMT_P200D,AC_G,	MOFFMS(fddiMACT_MaxCapabilitiy),"T"	} ,
+	{ SMT_P200E,AC_G,	MOFFMS(fddiMACTVXCapabilitiy),"T"	} ,
+
+	/* ConfigGrp */
+	{ SMT_P2014,AC_GROUP	} ,
+	{ SMT_P2016,AC_G,	MOFFMS(fddiMACAvailablePaths),	"B"	} ,
+	{ SMT_P2017,AC_G,	MOFFMS(fddiMACCurrentPath),	"S"	} ,
+	{ SMT_P2018,AC_G,	MOFFMS(fddiMACUpstreamNbr),	"A"	} ,
+	{ SMT_P2019,AC_G,	MOFFMS(fddiMACDownstreamNbr),	"A"	} ,
+	{ SMT_P201A,AC_G,	MOFFMS(fddiMACOldUpstreamNbr),	"A"	} ,
+	{ SMT_P201B,AC_G,	MOFFMS(fddiMACOldDownstreamNbr),"A"	} ,
+	{ SMT_P201D,AC_G,	MOFFMS(fddiMACDupAddressTest),	"E"	} ,
+	{ SMT_P2020,AC_GR,	MOFFMS(fddiMACRequestedPaths),	"wS"	} ,
+	{ SMT_P2021,AC_G,	MOFFMS(fddiMACDownstreamPORTType),"E"	} ,
+	{ SMT_P2022,AC_G,	MOFFMS(fddiMACIndex),		"S"	} ,
+
+	/* AddressGrp */
+	{ SMT_P2028,AC_GROUP	} ,
+	{ SMT_P2029,AC_G,	MOFFMS(fddiMACSMTAddress),	"A"	} ,
+
+	/* OperationGrp */
+	{ SMT_P2032,AC_GROUP	} ,
+	{ SMT_P2033,AC_G,	MOFFMS(fddiMACT_Req),		"T"	} ,
+	{ SMT_P2034,AC_G,	MOFFMS(fddiMACT_Neg),		"T"	} ,
+	{ SMT_P2035,AC_G,	MOFFMS(fddiMACT_Max),		"T"	} ,
+	{ SMT_P2036,AC_G,	MOFFMS(fddiMACTvxValue),	"T"	} ,
+	{ SMT_P2038,AC_G,	MOFFMS(fddiMACT_Pri0),		"T"	} ,
+	{ SMT_P2039,AC_G,	MOFFMS(fddiMACT_Pri1),		"T"	} ,
+	{ SMT_P203A,AC_G,	MOFFMS(fddiMACT_Pri2),		"T"	} ,
+	{ SMT_P203B,AC_G,	MOFFMS(fddiMACT_Pri3),		"T"	} ,
+	{ SMT_P203C,AC_G,	MOFFMS(fddiMACT_Pri4),		"T"	} ,
+	{ SMT_P203D,AC_G,	MOFFMS(fddiMACT_Pri5),		"T"	} ,
+	{ SMT_P203E,AC_G,	MOFFMS(fddiMACT_Pri6),		"T"	} ,
+
+
+	/* CountersGrp */
+	{ SMT_P2046,AC_GROUP	} ,
+	{ SMT_P2047,AC_G,	MOFFMS(fddiMACFrame_Ct),	"C"	} ,
+	{ SMT_P2048,AC_G,	MOFFMS(fddiMACCopied_Ct),	"C"	} ,
+	{ SMT_P2049,AC_G,	MOFFMS(fddiMACTransmit_Ct),	"C"	} ,
+	{ SMT_P204A,AC_G,	MOFFMS(fddiMACToken_Ct),	"C"	} ,
+	{ SMT_P2051,AC_G,	MOFFMS(fddiMACError_Ct),	"C"	} ,
+	{ SMT_P2052,AC_G,	MOFFMS(fddiMACLost_Ct),		"C"	} ,
+	{ SMT_P2053,AC_G,	MOFFMS(fddiMACTvxExpired_Ct),	"C"	} ,
+	{ SMT_P2054,AC_G,	MOFFMS(fddiMACNotCopied_Ct),	"C"	} ,
+	{ SMT_P2056,AC_G,	MOFFMS(fddiMACRingOp_Ct),	"C"	} ,
+
+	/* FrameErrorConditionGrp */
+	{ SMT_P205A,AC_GROUP	} ,
+	{ SMT_P205F,AC_GR,	MOFFMS(fddiMACFrameErrorThreshold),"wS"	} ,
+	{ SMT_P2060,AC_G,	MOFFMS(fddiMACFrameErrorRatio),	"S"	} ,
+
+	/* NotCopiedConditionGrp */
+	{ SMT_P2064,AC_GROUP	} ,
+	{ SMT_P2067,AC_GR,	MOFFMS(fddiMACNotCopiedThreshold),"wS"	} ,
+	{ SMT_P2069,AC_G,	MOFFMS(fddiMACNotCopiedRatio),	"S"	} ,
+
+	/* StatusGrp */
+	{ SMT_P206E,AC_GROUP	} ,
+	{ SMT_P206F,AC_G,	MOFFMS(fddiMACRMTState),	"S"	} ,
+	{ SMT_P2070,AC_G,	MOFFMS(fddiMACDA_Flag),	"F"	} ,
+	{ SMT_P2071,AC_G,	MOFFMS(fddiMACUNDA_Flag),	"F"	} ,
+	{ SMT_P2072,AC_G,	MOFFMS(fddiMACFrameErrorFlag),	"F"	} ,
+	{ SMT_P2073,AC_G,	MOFFMS(fddiMACNotCopiedFlag),	"F"	} ,
+	{ SMT_P2074,AC_G,	MOFFMS(fddiMACMA_UnitdataAvailable),"F"	} ,
+	{ SMT_P2075,AC_G,	MOFFMS(fddiMACHardwarePresent),	"F"	} ,
+	{ SMT_P2076,AC_GR,	MOFFMS(fddiMACMA_UnitdataEnable),"bF"	} ,
+
+	/*
+	 * PRIVATE EXTENSIONS
+	 * only accessable locally to get/set TMIN
+	 */
+	{ SMT_P20F0,AC_NA						} ,
+	{ SMT_P20F1,AC_GR,	MOFFMS(fddiMACT_Min),		"lT"	} ,
+
+	/* Path Attributes */
+	/*
+	 * DON't swap 320B,320F,3210: they are already swapped in swap_para()
+	 */
+	{ SMT_P320A,AC_GROUP	} ,
+	{ SMT_P320B,AC_G,	MOFFAS(fddiPATHIndex),		"r"	} ,
+	{ SMT_P320F,AC_GR,	MOFFAS(fddiPATHSbaPayload),	"l4"	} ,
+	{ SMT_P3210,AC_GR,	MOFFAS(fddiPATHSbaOverhead),	"l4"	} ,
+	/* fddiPATHConfiguration */
+	{ SMT_P3212,AC_G,	0,				""	} ,
+	{ SMT_P3213,AC_GR,	MOFFAS(fddiPATHT_Rmode),	"lT"	} ,
+	{ SMT_P3214,AC_GR,	MOFFAS(fddiPATHSbaAvailable),	"lL"	} ,
+	{ SMT_P3215,AC_GR,	MOFFAS(fddiPATHTVXLowerBound),	"lT"	} ,
+	{ SMT_P3216,AC_GR,	MOFFAS(fddiPATHT_MaxLowerBound),"lT"	} ,
+	{ SMT_P3217,AC_GR,	MOFFAS(fddiPATHMaxT_Req),	"lT"	} ,
+
+	/* Port Attributes */
+	/* ConfigGrp */
+	{ SMT_P400A,AC_GROUP	} ,
+	{ SMT_P400C,AC_G,	MOFFPS(fddiPORTMy_Type),	"E"	} ,
+	{ SMT_P400D,AC_G,	MOFFPS(fddiPORTNeighborType),	"E"	} ,
+	{ SMT_P400E,AC_GR,	MOFFPS(fddiPORTConnectionPolicies),"bB"	} ,
+	{ SMT_P400F,AC_G,	MOFFPS(fddiPORTMacIndicated),	"2"	} ,
+	{ SMT_P4010,AC_G,	MOFFPS(fddiPORTCurrentPath),	"E"	} ,
+	{ SMT_P4011,AC_GR,	MOFFPA(fddiPORTRequestedPaths),	"l4"	} ,
+	{ SMT_P4012,AC_G,	MOFFPS(fddiPORTMACPlacement),	"S"	} ,
+	{ SMT_P4013,AC_G,	MOFFPS(fddiPORTAvailablePaths),	"B"	} ,
+	{ SMT_P4016,AC_G,	MOFFPS(fddiPORTPMDClass),	"E"	} ,
+	{ SMT_P4017,AC_G,	MOFFPS(fddiPORTConnectionCapabilities),	"B"} ,
+	{ SMT_P401D,AC_G,	MOFFPS(fddiPORTIndex),		"R"	} ,
+
+	/* OperationGrp */
+	{ SMT_P401E,AC_GROUP	} ,
+	{ SMT_P401F,AC_GR,	MOFFPS(fddiPORTMaint_LS),	"wE"	} ,
+	{ SMT_P4021,AC_G,	MOFFPS(fddiPORTBS_Flag),	"F"	} ,
+	{ SMT_P4022,AC_G,	MOFFPS(fddiPORTPC_LS),		"E"	} ,
+
+	/* ErrorCtrsGrp */
+	{ SMT_P4028,AC_GROUP	} ,
+	{ SMT_P4029,AC_G,	MOFFPS(fddiPORTEBError_Ct),	"C"	} ,
+	{ SMT_P402A,AC_G,	MOFFPS(fddiPORTLCTFail_Ct),	"C"	} ,
+
+	/* LerGrp */
+	{ SMT_P4032,AC_GROUP	} ,
+	{ SMT_P4033,AC_G,	MOFFPS(fddiPORTLer_Estimate),	"F"	} ,
+	{ SMT_P4034,AC_G,	MOFFPS(fddiPORTLem_Reject_Ct),	"C"	} ,
+	{ SMT_P4035,AC_G,	MOFFPS(fddiPORTLem_Ct),		"C"	} ,
+	{ SMT_P403A,AC_GR,	MOFFPS(fddiPORTLer_Cutoff),	"bB"	} ,
+	{ SMT_P403B,AC_GR,	MOFFPS(fddiPORTLer_Alarm),	"bB"	} ,
+
+	/* StatusGrp */
+	{ SMT_P403C,AC_GROUP	} ,
+	{ SMT_P403D,AC_G,	MOFFPS(fddiPORTConnectState),	"E"	} ,
+	{ SMT_P403E,AC_G,	MOFFPS(fddiPORTPCMStateX),	"E"	} ,
+	{ SMT_P403F,AC_G,	MOFFPS(fddiPORTPC_Withhold),	"E"	} ,
+	{ SMT_P4040,AC_G,	MOFFPS(fddiPORTLerFlag),	"F"	} ,
+	{ SMT_P4041,AC_G,	MOFFPS(fddiPORTHardwarePresent),"F"	} ,
+
+	{ SMT_P4046,AC_S,	0,				"wS"	} ,
+
+	{ 0,	AC_GROUP	} ,
+	{ 0 }
+} ;
+
+
+static SMbuf *smt_build_pmf_response() ;
+
+void smt_pmf_received_pack(smc,mb,local)
+struct s_smc *smc ;
+SMbuf *mb ;
+int local ;
+{
+	struct smt_header	*sm ;
+	SMbuf		*reply ;
+
+	sm = smtod(mb,struct smt_header *) ;
+	DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ;
+#ifdef	DEBUG
+	dump_smt(smc,sm,"PMF Received") ;
+#endif
+	/*
+	 * Start the watchdog: It may be a long, long packet and
+	 * maybe the watchdog occurs ...
+	 */
+	smt_start_watchdog(smc) ;
+
+	if (sm->smt_class == SMT_PMF_GET ||
+	    sm->smt_class == SMT_PMF_SET) {
+		reply = smt_build_pmf_response(smc,sm,
+			sm->smt_class == SMT_PMF_SET,local) ;
+		if (reply) {
+			sm = smtod(reply,struct smt_header *) ;
+#ifdef	DEBUG
+			dump_smt(smc,sm,"PMF Reply") ;
+#endif
+			smt_send_frame(smc,reply,FC_SMT_INFO,local) ;
+		}
+	}
+}
+
+extern	SMbuf	*smt_get_mbuf() ;
+
+static SMbuf *smt_build_pmf_response(smc,req,set,local)
+struct s_smc *smc ;
+struct smt_header *req ;
+int	set ;
+int	local ;
+{
+	SMbuf			*mb ;
+	struct smt_header	*smt ;
+	struct smt_para		*pa ;
+	struct smt_p_reason	*res ;
+	const struct s_p_tab	*pt ;
+	int			len ;
+	int			index ;
+	int			idx_end ;
+	int			error ;
+	int			range ;
+	SK_LOC_DECL(struct s_pcon,pcon) ;
+	SK_LOC_DECL(struct s_pcon,set_pcon) ;
+
+	/*
+	 * build SMT header
+	 */
+	if (!(mb = smt_get_mbuf(smc)))
+		return(mb) ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = req->smt_source ;	/* DA == source of request */
+	smt->smt_class = req->smt_class ;	/* same class (GET/SET) */
+	smt->smt_type = SMT_REPLY ;
+	smt->smt_version = SMT_VID_2 ;
+	smt->smt_tid = req->smt_tid ;		/* same TID */
+	smt->smt_pad = 0 ;
+	smt->smt_len = 0 ;
+
+	/*
+	 * setup parameter status
+	 */
+	pcon.pc_len = SMT_MAX_INFO_LEN ;	/* max para length */
+	pcon.pc_err = 0 ;			/* no error */
+	pcon.pc_badset = 0 ;			/* no bad set count */
+	pcon.pc_p = (void *) (smt + 1) ;	/* paras start here */
+
+	/*
+	 * check authoriziation and set count
+	 */
+	error = 0 ;
+	if (set) {
+		if (!local && smt_authorize(smc,req))
+			error = SMT_RDF_AUTHOR ;
+		else if (smt_check_set_count(smc,req))
+			pcon.pc_badset = SMT_RDF_BADSET ;
+	}
+	/*
+	 * add reason code and all mandatory parameters
+	 */
+	res = (struct smt_p_reason *) pcon.pc_p ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P_REASON,0,0) ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
+	/* update 1035 and 1036 later if set */
+	set_pcon = pcon ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1035,0,0) ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1036,0,0) ;
+
+	pcon.pc_err = error ;
+	len = req->smt_len ;
+	pa = (struct smt_para *) (req + 1) ;
+	/*
+	 * process list of paras
+	 */
+	while (!pcon.pc_err && len > 0 ) {
+		if (((u_short)len < pa->p_len + PARA_LEN) || (pa->p_len & 3)) {
+			pcon.pc_err = SMT_RDF_LENGTH ;
+			break ;
+		}
+
+		if (((range = (pa->p_type & 0xf000)) == 0x2000) ||
+			range == 0x3000 || range == 0x4000) {
+			/*
+			 * get index for PART,MAC ad PATH group
+			 */
+			index = *((u_char *)pa + PARA_LEN + 3) ;/* index */
+			idx_end = index ;
+			if (!set && (pa->p_len != 4)) {
+				pcon.pc_err = SMT_RDF_LENGTH ;
+				break ;
+			}
+			if (!index && !set) {
+				switch (range) {
+				case 0x2000 :
+					index = INDEX_MAC ;
+					idx_end = index - 1 + NUMMACS ;
+					break ;
+				case 0x3000 :
+					index = INDEX_PATH ;
+					idx_end = index - 1 + NUMPATHS ;
+					break ;
+				case 0x4000 :
+					index = INDEX_PORT ;
+					idx_end = index - 1 + NUMPHYS ;
+#ifndef	CONCENTRATOR
+					if (smc->s.sas == SMT_SAS)
+						idx_end = INDEX_PORT ;
+#endif
+					break ;
+				}
+			}
+		}
+		else {
+			/*
+			 * smt group has no index
+			 */
+			if (!set && (pa->p_len != 0)) {
+				pcon.pc_err = SMT_RDF_LENGTH ;
+				break ;
+			}
+			index = 0 ;
+			idx_end = 0 ;
+		}
+		while (index <= idx_end) {
+			/*
+			 * if group
+			 *	add all paras of group
+			 */
+			pt = smt_get_ptab(pa->p_type) ;
+			if (pt && pt->p_access == AC_GROUP && !set) {
+				pt++ ;
+				while (pt->p_access == AC_G ||
+					pt->p_access == AC_GR) {
+					smt_add_para(smc,&pcon,pt->p_num,
+						index,local);
+					pt++ ;
+				}
+			}
+			/*
+			 * ignore
+			 *	AUTHORIZATION in get/set
+			 *	SET COUNT in set
+			 */
+			else if (pa->p_type != SMT_P_AUTHOR &&
+				 (!set || (pa->p_type != SMT_P1035))) {
+				int	st ;
+				if (pcon.pc_badset) {
+					smt_add_para(smc,&pcon,pa->p_type,
+						index,local) ;
+				}
+				else if (set) {
+					st = smt_set_para(smc,pa,index,local,1);
+					/*
+					 * return para even if error
+					 */
+					smt_add_para(smc,&pcon,pa->p_type,
+						index,local) ;
+					pcon.pc_err = st ;
+				}
+				else {
+					if (pt && pt->p_access == AC_S) {
+						pcon.pc_err =
+							SMT_RDF_ILLEGAL ;
+					}
+					smt_add_para(smc,&pcon,pa->p_type,
+						index,local) ;
+				}
+			}
+			if (pcon.pc_err)
+				break ;
+			index++ ;
+		}
+		len -= pa->p_len + PARA_LEN ;
+		pa = (struct smt_para *) ((char *)pa + pa->p_len + PARA_LEN) ;
+	}
+	smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
+	mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
+
+	/* update reason code */
+	res->rdf_reason = pcon.pc_badset ? pcon.pc_badset :
+			pcon.pc_err ? pcon.pc_err : SMT_RDF_SUCCESS ;
+	if (set && (res->rdf_reason == SMT_RDF_SUCCESS)) {
+		/*
+		 * increment set count
+		 * set time stamp
+		 * store station id of last set
+		 */
+		smc->mib.fddiSMTSetCount.count++ ;
+		smt_set_timestamp(smc,smc->mib.fddiSMTSetCount.timestamp) ;
+		smc->mib.fddiSMTLastSetStationId = req->smt_sid ;
+		smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ;
+		smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ;
+	}
+	return(mb) ;
+}
+
+extern void *sm_to_para() ;
+
+static int smt_authorize(smc,sm)
+struct s_smc *smc ;
+struct smt_header *sm ;
+{
+	struct smt_para	*pa ;
+	int		i ;
+	char		*p ;
+
+	/*
+	 * check source station id if not zero
+	 */
+	p = (char *) &smc->mib.fddiPRPMFStation ;
+	for (i = 0 ; i < 8 && !p[i] ; i++)
+		;
+	if (i != 8) {
+		if (memcmp((char *) &sm->smt_sid,
+			(char *) &smc->mib.fddiPRPMFStation,8))
+			return(1) ;
+	}
+	/*
+	 * check authoriziation parameter if passwd not zero
+	 */
+	p = (char *) smc->mib.fddiPRPMFPasswd ;
+	for (i = 0 ; i < 8 && !p[i] ; i++)
+		;
+	if (i != 8) {
+		pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ;
+		if (!pa)
+			return(1) ;
+		if (pa->p_len != 8)
+			return(1) ;
+		if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8))
+			return(1) ;
+	}
+	return(0) ;
+}
+
+static int smt_check_set_count(smc,sm)
+struct s_smc *smc ;
+struct smt_header *sm ;
+{
+	struct smt_para	*pa ;
+	struct smt_p_setcount	*sc ;
+
+	pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P1035) ;
+	if (pa) {
+		sc = (struct smt_p_setcount *) pa ;
+		if ((smc->mib.fddiSMTSetCount.count != sc->count) ||
+			memcmp((char *) smc->mib.fddiSMTSetCount.timestamp,
+			(char *)sc->timestamp,8))
+			return(1) ;
+	}
+	return(0) ;
+}
+
+void smt_add_para(smc,pcon,para,index,local)
+struct s_smc *smc ;
+struct s_pcon *pcon ;
+u_short para ;
+int index ;
+int local ;
+{
+	struct smt_para	*pa ;
+	const struct s_p_tab	*pt ;
+	struct fddi_mib_m *mib_m = 0 ;
+	struct fddi_mib_p *mib_p = 0 ;
+	int		len ;
+	int		plen ;
+	char		*from ;
+	char		*to ;
+	const char	*swap ;
+	char		c ;
+	int		range ;
+	char		*mib_addr ;
+	int		mac ;
+	int		path ;
+	int		port ;
+	int		sp_len ;
+
+	/*
+	 * skip if errror
+	 */
+	if (pcon->pc_err)
+		return ;
+
+	/*
+	 * actions don't have a value
+	 */
+	pt = smt_get_ptab(para) ;
+	if (pt && pt->p_access == AC_S)
+		return ;
+
+	to = (char *) (pcon->pc_p) ;	/* destination pointer */
+	len = pcon->pc_len ;		/* free space */
+	plen = len ;			/* remember start length */
+	pa = (struct smt_para *) to ;	/* type/length pointer */
+	to += PARA_LEN ;		/* skip smt_para */
+	len -= PARA_LEN ;
+	/*
+	 * set index if required
+	 */
+	if (((range = (para & 0xf000)) == 0x2000) ||
+		range == 0x3000 || range == 0x4000) {
+		if (len < 4)
+			goto wrong_error ;
+		to[0] = 0 ;
+		to[1] = 0 ;
+		to[2] = 0 ;
+		to[3] = index ;
+		len -= 4 ;
+		to += 4 ;
+	}
+	mac = index - INDEX_MAC ;
+	path = index - INDEX_PATH ;
+	port = index - INDEX_PORT ;
+	/*
+	 * get pointer to mib
+	 */
+	switch (range) {
+	case 0x1000 :
+	default :
+		mib_addr = (char *) (&smc->mib) ;
+		break ;
+	case 0x2000 :
+		if (mac < 0 || mac >= NUMMACS) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		mib_addr = (char *) (&smc->mib.m[mac]) ;
+		mib_m = (struct fddi_mib_m *) mib_addr ;
+		break ;
+	case 0x3000 :
+		if (path < 0 || path >= NUMPATHS) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		mib_addr = (char *) (&smc->mib.a[path]) ;
+		break ;
+	case 0x4000 :
+		if (port < 0 || port >= smt_mib_phys(smc)) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ;
+		mib_p = (struct fddi_mib_p *) mib_addr ;
+		break ;
+	}
+	/*
+	 * check special paras
+	 */
+	swap = 0 ;
+	switch (para) {
+	case SMT_P10F0 :
+	case SMT_P10F1 :
+#ifdef	ESS
+	case SMT_P10F2 :
+	case SMT_P10F3 :
+	case SMT_P10F4 :
+	case SMT_P10F5 :
+	case SMT_P10F6 :
+	case SMT_P10F7 :
+#endif
+#ifdef	SBA
+	case SMT_P10F8 :
+	case SMT_P10F9 :
+#endif
+	case SMT_P20F1 :
+		if (!local) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		break ;
+	case SMT_P2034 :
+	case SMT_P2046 :
+	case SMT_P2047 :
+	case SMT_P204A :
+	case SMT_P2051 :
+	case SMT_P2052 :
+		mac_update_counter(smc) ;
+		break ;
+	case SMT_P4022:
+		mib_p->fddiPORTPC_LS = LS2MIB(
+			sm_pm_get_ls(smc,port_to_mib(smc,port))) ;
+		break ;
+	case SMT_P_REASON :
+		* (u_long *) to = 0 ;
+		sp_len = 4 ;
+		goto sp_done ;
+	case SMT_P1033 :			/* time stamp */
+		smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ;
+		break ;
+
+	case SMT_P1020:				/* port indexes */
+#if	NUMPHYS == 12
+		swap = "IIIIIIIIIIII" ;
+#else
+#if	NUMPHYS == 2
+		if (smc->s.sas == SMT_SAS)
+			swap = "I" ;
+		else
+			swap = "II" ;
+#else
+#if	NUMPHYS == 24
+		swap = "IIIIIIIIIIIIIIIIIIIIIIII" ;
+#else
+	????
+#endif
+#endif
+#endif
+		break ;
+	case SMT_P3212 :
+		{
+			sp_len = cem_build_path(smc,to,path) ;
+			goto sp_done ;
+		}
+	case SMT_P1048 :		/* peer wrap condition */
+		{
+			struct smt_p_1048	*sp ;
+			sp = (struct smt_p_1048 *) to ;
+			sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ;
+			sp->p1048_cf_state = smc->mib.fddiSMTCF_State ;
+			sp_len = sizeof(struct smt_p_1048) ;
+			goto sp_done ;
+		}
+	case SMT_P208C :
+		{
+			struct smt_p_208c	*sp ;
+			sp = (struct smt_p_208c *) to ;
+			sp->p208c_flag =
+				smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
+			sp->p208c_dupcondition =
+				(mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) |
+				(mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0);
+			sp->p208c_fddilong =
+				mib_m->fddiMACSMTAddress ;
+			sp->p208c_fddiunalong =
+				mib_m->fddiMACUpstreamNbr ;
+			sp->p208c_pad = 0 ;
+			sp_len = sizeof(struct smt_p_208c) ;
+			goto sp_done ;
+		}
+	case SMT_P208D :		/* frame error condition */
+		{
+			struct smt_p_208d	*sp ;
+			sp = (struct smt_p_208d *) to ;
+			sp->p208d_flag =
+				mib_m->fddiMACFrameErrorFlag ;
+			sp->p208d_frame_ct =
+				mib_m->fddiMACFrame_Ct ;
+			sp->p208d_error_ct =
+				mib_m->fddiMACError_Ct ;
+			sp->p208d_lost_ct =
+				mib_m->fddiMACLost_Ct ;
+			sp->p208d_ratio =
+				mib_m->fddiMACFrameErrorRatio ;
+			sp_len = sizeof(struct smt_p_208d) ;
+			goto sp_done ;
+		}
+	case SMT_P208E :		/* not copied condition */
+		{
+			struct smt_p_208e	*sp ;
+			sp = (struct smt_p_208e *) to ;
+			sp->p208e_flag =
+				mib_m->fddiMACNotCopiedFlag ;
+			sp->p208e_not_copied =
+				mib_m->fddiMACNotCopied_Ct ;
+			sp->p208e_copied =
+				mib_m->fddiMACCopied_Ct ;
+			sp->p208e_not_copied_ratio =
+				mib_m->fddiMACNotCopiedRatio ;
+			sp_len = sizeof(struct smt_p_208e) ;
+			goto sp_done ;
+		}
+	case SMT_P208F :	/* neighbor change event */
+		{
+			struct smt_p_208f	*sp ;
+			sp = (struct smt_p_208f *) to ;
+			sp->p208f_multiple =
+				mib_m->fddiMACMultiple_N ;
+			sp->p208f_nacondition =
+				mib_m->fddiMACDuplicateAddressCond ;
+			sp->p208f_old_una =
+				mib_m->fddiMACOldUpstreamNbr ;
+			sp->p208f_new_una =
+				mib_m->fddiMACUpstreamNbr ;
+			sp->p208f_old_dna =
+				mib_m->fddiMACOldDownstreamNbr ;
+			sp->p208f_new_dna =
+				mib_m->fddiMACDownstreamNbr ;
+			sp->p208f_curren_path =
+				mib_m->fddiMACCurrentPath ;
+			sp->p208f_smt_address =
+				mib_m->fddiMACSMTAddress ;
+			sp_len = sizeof(struct smt_p_208f) ;
+			goto sp_done ;
+		}
+	case SMT_P2090 :
+		{
+			struct smt_p_2090	*sp ;
+			sp = (struct smt_p_2090 *) to ;
+			sp->p2090_multiple =
+				mib_m->fddiMACMultiple_P ;
+			sp->p2090_availablepaths =
+				mib_m->fddiMACAvailablePaths ;
+			sp->p2090_currentpath =
+				mib_m->fddiMACCurrentPath ;
+			sp->p2090_requestedpaths =
+				mib_m->fddiMACRequestedPaths ;
+			sp_len = sizeof(struct smt_p_2090) ;
+			goto sp_done ;
+		}
+	case SMT_P4050 :
+		{
+			struct smt_p_4050	*sp ;
+			sp = (struct smt_p_4050 *) to ;
+			sp->p4050_flag =
+				mib_p->fddiPORTLerFlag ;
+			sp->p4050_pad = 0 ;
+			sp->p4050_cutoff =
+				mib_p->fddiPORTLer_Cutoff ; ;
+			sp->p4050_alarm =
+				mib_p->fddiPORTLer_Alarm ; ;
+			sp->p4050_estimate =
+				mib_p->fddiPORTLer_Estimate ;
+			sp->p4050_reject_ct =
+				mib_p->fddiPORTLem_Reject_Ct ;
+			sp->p4050_ct =
+				mib_p->fddiPORTLem_Ct ;
+			sp_len = sizeof(struct smt_p_4050) ;
+			goto sp_done ;
+		}
+
+	case SMT_P4051 :
+		{
+			struct smt_p_4051	*sp ;
+			sp = (struct smt_p_4051 *) to ;
+			sp->p4051_multiple =
+				mib_p->fddiPORTMultiple_U ;
+			sp->p4051_porttype =
+				mib_p->fddiPORTMy_Type ;
+			sp->p4051_connectstate =
+				mib_p->fddiPORTConnectState ; ;
+			sp->p4051_pc_neighbor =
+				mib_p->fddiPORTNeighborType ;
+			sp->p4051_pc_withhold =
+				mib_p->fddiPORTPC_Withhold ;
+			sp_len = sizeof(struct smt_p_4051) ;
+			goto sp_done ;
+		}
+	case SMT_P4052 :
+		{
+			struct smt_p_4052	*sp ;
+			sp = (struct smt_p_4052 *) to ;
+			sp->p4052_flag =
+				mib_p->fddiPORTEB_Condition ;
+			sp->p4052_eberrorcount =
+				mib_p->fddiPORTEBError_Ct ;
+			sp_len = sizeof(struct smt_p_4052) ;
+			goto sp_done ;
+		}
+	case SMT_P4053 :
+		{
+			struct smt_p_4053	*sp ;
+			sp = (struct smt_p_4053 *) to ;
+			sp->p4053_multiple =
+				mib_p->fddiPORTMultiple_P ; ;
+			sp->p4053_availablepaths =
+				mib_p->fddiPORTAvailablePaths ;
+			sp->p4053_currentpath =
+				mib_p->fddiPORTCurrentPath ;
+			memcpy(	(char *) &sp->p4053_requestedpaths,
+				(char *) mib_p->fddiPORTRequestedPaths,4) ;
+			sp->p4053_mytype =
+				mib_p->fddiPORTMy_Type ;
+			sp->p4053_neighbortype =
+				mib_p->fddiPORTNeighborType ;
+			sp_len = sizeof(struct smt_p_4053) ;
+			goto sp_done ;
+		}
+	default :
+		break ;
+	}
+	/*
+	 * in table ?
+	 */
+	if (!pt) {
+		pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM :
+						SMT_RDF_ILLEGAL ;
+		return ;
+	}
+	/*
+	 * check access rights
+	 */
+	switch (pt->p_access) {
+	case AC_G :
+	case AC_GR :
+		break ;
+	default :
+		pcon->pc_err = SMT_RDF_ILLEGAL ;
+		return ;
+	}
+	from = mib_addr + pt->p_offset ;
+	if (!swap)
+		swap = pt->p_swap ;		/* pointer to swap string */
+
+	/*
+	 * copy values
+	 */
+	while ((c = *swap++)) {
+		switch(c) {
+		case 'b' :
+		case 'w' :
+		case 'l' :
+			break ;
+		case 'S' :
+		case 'E' :
+		case 'R' :
+		case 'r' :
+			if (len < 4)
+				goto len_error ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+#ifdef	LITTLE_ENDIAN
+			if (c == 'r') {
+				to[2] = *from++ ;
+				to[3] = *from++ ;
+			}
+			else {
+				to[3] = *from++ ;
+				to[2] = *from++ ;
+			}
+#else
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+#endif
+			to += 4 ;
+			len -= 4 ;
+			break ;
+		case 'I' :		/* for SET of port indexes */
+			if (len < 2)
+				goto len_error ;
+#ifdef	LITTLE_ENDIAN
+			to[1] = *from++ ;
+			to[0] = *from++ ;
+#else
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+#endif
+			to += 2 ;
+			len -= 2 ;
+			break ;
+		case 'F' :
+		case 'B' :
+			if (len < 4)
+				goto len_error ;
+			len -= 4 ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+			to[2] = 0 ;
+			to[3] = *from++ ;
+			to += 4 ;
+			break ;
+		case 'C' :
+		case 'T' :
+		case 'L' :
+			if (len < 4)
+				goto len_error ;
+#ifdef	LITTLE_ENDIAN
+			to[3] = *from++ ;
+			to[2] = *from++ ;
+			to[1] = *from++ ;
+			to[0] = *from++ ;
+#else
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+#endif
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case '2' :		/* PortMacIndicated */
+			if (len < 4)
+				goto len_error ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case '4' :
+			if (len < 4)
+				goto len_error ;
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case 'A' :
+			if (len < 8)
+				goto len_error ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+			memcpy((char *) to+2,(char *) from,6) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case '8' :
+			if (len < 8)
+				goto len_error ;
+			memcpy((char *) to,(char *) from,8) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case 'D' :
+			if (len < 32)
+				goto len_error ;
+			memcpy((char *) to,(char *) from,32) ;
+			to += 32 ;
+			from += 32 ;
+			len -= 32 ;
+			break ;
+		case 'P' :		/* timestamp is NOT swapped */
+			if (len < 8)
+				goto len_error ;
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+			to[4] = *from++ ;
+			to[5] = *from++ ;
+			to[6] = *from++ ;
+			to[7] = *from++ ;
+			to += 8 ;
+			len -= 8 ;
+			break ;
+		default :
+			SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ;
+			break ;
+		}
+	}
+
+done:
+	/*
+	 * make it even (in case of 'I' encoding)
+	 * note: len is DECREMENTED
+	 */
+	if (len & 3) {
+		to[0] = 0 ;
+		to[1] = 0 ;
+		to += 4 - (len & 3 ) ;
+		len = len & ~ 3 ;
+	}
+
+	/* set type and length */
+	pa->p_type = para ;
+	pa->p_len = plen - len - PARA_LEN ;
+	/* return values */
+	pcon->pc_p = (void *) to ;
+	pcon->pc_len = len ;
+	return ;
+
+sp_done:
+	len -= sp_len ;
+	to += sp_len ;
+	goto done ;
+
+len_error:
+	/* parameter does not fit in frame */
+	pcon->pc_err = SMT_RDF_TOOLONG ;
+	return ;
+
+wrong_error:
+	pcon->pc_err = SMT_RDF_LENGTH ;
+}
+
+/*
+ * set parameter
+ */
+int smt_set_para(smc,pa,index,local,set)
+struct s_smc *smc ;
+struct smt_para	*pa ;
+int index ;
+int local ;
+int set ;
+{
+#define IFSET(x)	if (set) (x)
+
+	const struct s_p_tab	*pt ;
+	int		len ;
+	char		*from ;
+	char		*to ;
+	const char	*swap ;
+	char		c ;
+	char		*mib_addr ;
+	struct fddi_mib	*mib ;
+	struct fddi_mib_m	*mib_m = 0 ;
+	struct fddi_mib_a	*mib_a = 0 ;
+	struct fddi_mib_p	*mib_p = 0 ;
+	int		mac ;
+	int		path ;
+	int		port ;
+	SK_LOC_DECL(u_char,byte_val) ;
+	SK_LOC_DECL(u_short,word_val) ;
+	SK_LOC_DECL(u_long,long_val) ;
+
+	mac = index - INDEX_MAC ;
+	path = index - INDEX_PATH ;
+	port = index - INDEX_PORT ;
+	len = pa->p_len ;
+	from = (char *) (pa + 1 ) ;
+
+	mib = &smc->mib ;
+	switch (pa->p_type & 0xf000) {
+	case 0x1000 :
+	default :
+		mib_addr = (char *) mib ;
+		break ;
+	case 0x2000 :
+		if (mac < 0 || mac >= NUMMACS) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		mib_m = &smc->mib.m[mac] ;
+		mib_addr = (char *) mib_m ;
+		from += 4 ;		/* skip index */
+		len -= 4 ;
+		break ;
+	case 0x3000 :
+		if (path < 0 || path >= NUMPATHS) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		mib_a = &smc->mib.a[path] ;
+		mib_addr = (char *) mib_a ;
+		from += 4 ;		/* skip index */
+		len -= 4 ;
+		break ;
+	case 0x4000 :
+		if (port < 0 || port >= smt_mib_phys(smc)) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		mib_p = &smc->mib.p[port_to_mib(smc,port)] ;
+		mib_addr = (char *) mib_p ;
+		from += 4 ;		/* skip index */
+		len -= 4 ;
+		break ;
+	}
+	switch (pa->p_type) {
+	case SMT_P10F0 :
+	case SMT_P10F1 :
+#ifdef	ESS
+	case SMT_P10F2 :
+	case SMT_P10F3 :
+	case SMT_P10F4 :
+	case SMT_P10F5 :
+	case SMT_P10F6 :
+	case SMT_P10F7 :
+#endif
+#ifdef	SBA
+	case SMT_P10F8 :
+	case SMT_P10F9 :
+#endif
+	case SMT_P20F1 :
+		if (!local) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		break ;
+	}
+	pt = smt_get_ptab(pa->p_type) ;
+	if (!pt) {
+		return( (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM :
+						SMT_RDF_ILLEGAL ) ;
+	}
+	switch (pt->p_access) {
+	case AC_GR :
+	case AC_S :
+		break ;
+	default :
+		return(SMT_RDF_ILLEGAL) ;
+	}
+	to = mib_addr + pt->p_offset ;
+	swap = pt->p_swap ;		/* pointer to swap string */
+
+	while (swap && (c = *swap++)) {
+		switch(c) {
+		case 'b' :
+			to = (char *) &byte_val ;
+			break ;
+		case 'w' :
+			to = (char *) &word_val ;
+			break ;
+		case 'l' :
+			to = (char *) &long_val ;
+			break ;
+		case 'S' :
+		case 'E' :
+		case 'R' :
+		case 'r' :
+			if (len < 4) {
+				goto len_error ;
+			}
+			if (from[0] | from[1])
+				goto val_error ;
+#ifdef	LITTLE_ENDIAN
+			if (c == 'r') {
+				to[0] = from[2] ;
+				to[1] = from[3] ;
+			}
+			else {
+				to[1] = from[2] ;
+				to[0] = from[3] ;
+			}
+#else
+			to[0] = from[2] ;
+			to[1] = from[3] ;
+#endif
+			from += 4 ;
+			to += 2 ;
+			len -= 4 ;
+			break ;
+		case 'F' :
+		case 'B' :
+			if (len < 4) {
+				goto len_error ;
+			}
+			if (from[0] | from[1] | from[2])
+				goto val_error ;
+			to[0] = from[3] ;
+			len -= 4 ;
+			from += 4 ;
+			to += 4 ;
+			break ;
+		case 'C' :
+		case 'T' :
+		case 'L' :
+			if (len < 4) {
+				goto len_error ;
+			}
+#ifdef	LITTLE_ENDIAN
+			to[3] = *from++ ;
+			to[2] = *from++ ;
+			to[1] = *from++ ;
+			to[0] = *from++ ;
+#else
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+#endif
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case 'A' :
+			if (len < 8)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from+2,6) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case '4' :
+			if (len < 4)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from,4) ;
+			to += 4 ;
+			from += 4 ;
+			len -= 4 ;
+			break ;
+		case '8' :
+			if (len < 8)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from,8) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case 'D' :
+			if (len < 32)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from,32) ;
+			to += 32 ;
+			from += 32 ;
+			len -= 32 ;
+			break ;
+		case 'P' :		/* timestamp is NOT swapped */
+			if (set) {
+				to[0] = *from++ ;
+				to[1] = *from++ ;
+				to[2] = *from++ ;
+				to[3] = *from++ ;
+				to[4] = *from++ ;
+				to[5] = *from++ ;
+				to[6] = *from++ ;
+				to[7] = *from++ ;
+			}
+			to += 8 ;
+			len -= 8 ;
+			break ;
+		default :
+			SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ;
+			return(SMT_RDF_ILLEGAL) ;
+		}
+	}
+	/*
+	 * actions and internal updates
+	 */
+	switch (pa->p_type) {
+	case SMT_P101A:			/* fddiSMTConfigPolicy */
+		if (word_val & ~1)
+			goto val_error ;
+		IFSET(mib->fddiSMTConfigPolicy = word_val) ;
+		break ;
+	case SMT_P101B :		/* fddiSMTConnectionPolicy */
+		if (!(word_val & POLICY_MM))
+			goto val_error ;
+		IFSET(mib->fddiSMTConnectionPolicy = word_val) ;
+		break ;
+	case SMT_P101D : 		/* fddiSMTTT_Notify */
+		if (word_val < 2 || word_val > 30)
+			goto val_error ;
+		IFSET(mib->fddiSMTTT_Notify = word_val) ;
+		break ;
+	case SMT_P101E :		/* fddiSMTStatRptPolicy */
+		if (byte_val & ~1)
+			goto val_error ;
+		IFSET(mib->fddiSMTStatRptPolicy = byte_val) ;
+		break ;
+	case SMT_P101F :		/* fddiSMTTrace_MaxExpiration */
+		/*
+		 * note: lower limit trace_max = 6.001773... s
+		 * NO upper limit
+		 */
+		if (long_val < (long)0x478bf51L)
+			goto val_error ;
+		IFSET(mib->fddiSMTTrace_MaxExpiration = long_val) ;
+		break ;
+#ifdef	ESS
+	case SMT_P10F2 :		/* fddiESSPayload */
+		if (long_val > 1562)
+			goto val_error ;
+		if (set && smc->mib.fddiESSPayload != long_val) {
+			smc->ess.raf_act_timer_poll = TRUE ;
+			smc->mib.fddiESSPayload = long_val ;
+		}
+		break ;
+	case SMT_P10F3 :		/* fddiESSOverhead */
+		if (long_val < 50 || long_val > 5000)
+			goto val_error ;
+		if (set && smc->mib.fddiESSPayload &&
+			smc->mib.fddiESSOverhead != long_val) {
+			smc->ess.raf_act_timer_poll = TRUE ;
+			smc->mib.fddiESSOverhead = long_val ;
+		}
+		break ;
+	case SMT_P10F4 :		/* fddiESSMaxTNeg */
+		if (long_val > -MS2BCLK(5) || long_val < -MS2BCLK(165))
+			goto val_error ;
+		IFSET(mib->fddiESSMaxTNeg = long_val) ;
+		break ;
+	case SMT_P10F5 :		/* fddiESSMinSegmentSize */
+		if (long_val < 1 || long_val > 4478)
+			goto val_error ;
+		IFSET(mib->fddiESSMinSegmentSize = long_val) ;
+		break ;
+	case SMT_P10F6 :		/* fddiESSCategory */
+		if ((long_val & 0xffff) != 1)
+			goto val_error ;
+		IFSET(mib->fddiESSCategory = long_val) ;
+		break ;
+	case SMT_P10F7 :		/* fddiESSSyncTxMode */
+		if (word_val > 1)
+			goto val_error ;
+		IFSET(mib->fddiESSSynchTxMode = word_val) ;
+		break ;
+#endif
+#ifdef	SBA
+	case SMT_P10F8 :		/* fddiSBACommand */
+		if (byte_val != SB_STOP && byte_val != SB_START)
+			goto val_error ;
+		IFSET(mib->fddiSBACommand = byte_val) ;
+		break ;
+	case SMT_P10F9 :		/* fddiSBAAvailable */
+		if (byte_val > 100)
+			goto val_error ;
+		IFSET(mib->fddiSBAAvailable = byte_val) ;
+		break ;
+#endif
+	case SMT_P2020 :		/* fddiMACRequestedPaths */
+		if ((word_val & (MIB_P_PATH_PRIM_PREFER |
+			MIB_P_PATH_PRIM_ALTER)) == 0 )
+			goto val_error ;
+		IFSET(mib_m->fddiMACRequestedPaths = word_val) ;
+		break ;
+	case SMT_P205F :		/* fddiMACFrameErrorThreshold */
+		/* 0 .. ffff acceptable */
+		IFSET(mib_m->fddiMACFrameErrorThreshold = word_val) ;
+		break ;
+	case SMT_P2067 :		/* fddiMACNotCopiedThreshold */
+		/* 0 .. ffff acceptable */
+		IFSET(mib_m->fddiMACNotCopiedThreshold = word_val) ;
+		break ;
+	case SMT_P2076:			/* fddiMACMA_UnitdataEnable */
+		if (byte_val & ~1)
+			goto val_error ;
+		if (set) {
+			mib_m->fddiMACMA_UnitdataEnable = byte_val ;
+			queue_event(smc,EVENT_RMT,RM_ENABLE_FLAG) ;
+		}
+		break ;
+	case SMT_P20F1 :		/* fddiMACT_Min */
+		IFSET(mib_m->fddiMACT_Min = long_val) ;
+		break ;
+	case SMT_P320F :
+		if (long_val > 1562)
+			goto val_error ;
+		IFSET(mib_a->fddiPATHSbaPayload = long_val) ;
+#ifdef	ESS
+		if (set)
+			ess_para_change(smc) ;
+#endif
+		break ;
+	case SMT_P3210 :
+		if (long_val > 5000)
+			goto val_error ;
+		
+		if (long_val != 0 && mib_a->fddiPATHSbaPayload == 0)
+			goto val_error ;
+
+		IFSET(mib_a->fddiPATHSbaOverhead = long_val) ;
+#ifdef	ESS
+		if (set)
+			ess_para_change(smc) ;
+#endif
+		break ;
+	case SMT_P3213:			/* fddiPATHT_Rmode */
+		/* no limit :
+		 * 0 .. 343.597 => 0 .. 2e32 * 80nS
+		 */
+		if (set) {
+			mib_a->fddiPATHT_Rmode = long_val ;
+			rtm_set_timer(smc) ;
+		}
+		break ;
+	case SMT_P3214 :		/* fddiPATHSbaAvailable */
+		if (long_val > 0x00BEBC20L)
+			goto val_error ;
+#ifdef SBA 
+		if (set && mib->fddiSBACommand == SB_STOP)
+			goto val_error ;
+#endif
+		IFSET(mib_a->fddiPATHSbaAvailable = long_val) ;
+		break ;
+	case SMT_P3215 :		/* fddiPATHTVXLowerBound */
+		IFSET(mib_a->fddiPATHTVXLowerBound = long_val) ;
+		goto change_mac_para ;
+	case SMT_P3216 :		/* fddiPATHT_MaxLowerBound */
+		IFSET(mib_a->fddiPATHT_MaxLowerBound = long_val) ;
+		goto change_mac_para ;
+	case SMT_P3217 :		/* fddiPATHMaxT_Req */
+		IFSET(mib_a->fddiPATHMaxT_Req = long_val) ;
+
+change_mac_para:
+		if (set && smt_set_mac_opvalues(smc)) {
+			RS_SET(smc,RS_EVENT) ;
+			smc->sm.please_reconnect = 1 ;
+			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+		}
+		break ;
+	case SMT_P400E :		/* fddiPORTConnectionPolicies */
+		if (byte_val > 1)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTConnectionPolicies = byte_val) ;
+		break ;
+	case SMT_P4011 :		/* fddiPORTRequestedPaths */
+		/* all 3*8 bits allowed */
+		IFSET(memcpy((char *)mib_p->fddiPORTRequestedPaths,
+			(char *)&long_val,4)) ;
+		break ;
+	case SMT_P401F:			/* fddiPORTMaint_LS */
+		if (word_val > 4)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTMaint_LS = word_val) ;
+		break ;
+	case SMT_P403A :		/* fddiPORTLer_Cutoff */
+		if (byte_val < 4 || byte_val > 15)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTLer_Cutoff = byte_val) ;
+		break ;
+	case SMT_P403B :		/* fddiPORTLer_Alarm */
+		if (byte_val < 4 || byte_val > 15)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTLer_Alarm = byte_val) ;
+		break ;
+
+	/*
+	 * Actions
+	 */
+	case SMT_P103C :		/* fddiSMTStationAction */
+		if (smt_action(smc,SMT_STATION_ACTION, (int) word_val, 0))
+			goto val_error ;
+		break ;
+	case SMT_P4046:			/* fddiPORTAction */
+		if (smt_action(smc,SMT_PORT_ACTION, (int) word_val,
+			port_to_mib(smc,port)))
+			goto val_error ;
+		break ;
+	default :
+		break ;
+	}
+	return(0) ;
+
+val_error:
+	/* parameter value in frame is out of range */
+	return(SMT_RDF_RANGE) ;
+
+len_error:
+	/* parameter value in frame is too short */
+	return(SMT_RDF_LENGTH) ;
+
+#if	0
+no_author_error:
+	/* parameter not setable, because the SBA is not active
+	 * Please note: we give the return code 'not authorizeed
+	 *  because SBA denied is not a valid return code in the
+	 * PMF protocol.
+	 */
+	return(SMT_RDF_AUTHOR) ;
+#endif
+}
+
+static const struct s_p_tab *smt_get_ptab(para)
+u_short para ;
+{
+	const struct s_p_tab	*pt ;
+	for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++)
+		;
+	return(pt->p_num ? pt : 0) ;
+}
+
+static int smt_mib_phys(smc)
+struct s_smc *smc ;
+{
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+
+	return(NUMPHYS) ;
+#else
+	if (smc->s.sas == SMT_SAS)
+		return(1) ;
+	return(NUMPHYS) ;
+#endif
+}
+
+int port_to_mib(smc,p)
+struct s_smc *smc ;
+int p ;
+{
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+
+	return(p) ;
+#else
+	if (smc->s.sas == SMT_SAS)
+		return(PS) ;
+	return(p) ;
+#endif
+}
+
+
+#ifdef	DEBUG
+#ifndef	BOOT
+void dump_smt(smc,sm,text)
+struct s_smc *smc ;
+struct smt_header *sm ;
+char *text ;
+{
+	int	len ;
+	struct smt_para	*pa ;
+	char	*c ;
+	int	n ;
+	int	nn ;
+#ifdef	LITTLE_ENDIAN
+	int	smtlen ;
+#endif
+
+	SK_UNUSED(smc) ;
+
+#ifdef	DEBUG_BRD
+	if (smc->debug.d_smtf < 2)
+#else
+	if (debug.d_smtf < 2)
+#endif
+		return ;
+#ifdef	LITTLE_ENDIAN
+	smtlen = sm->smt_len + sizeof(struct smt_header) ;
+#endif
+	printf("SMT Frame [%s]:\nDA  ",text) ;
+	dump_hex((char *) &sm->smt_dest,6) ;
+	printf("\tSA ") ;
+	dump_hex((char *) &sm->smt_source,6) ;
+	printf(" Class %x Type %x Version %x\n",
+		sm->smt_class,sm->smt_type,sm->smt_version)  ;
+	printf("TID %lx\t\tSID ",sm->smt_tid) ;
+	dump_hex((char *) &sm->smt_sid,8) ;
+	printf(" LEN %x\n",sm->smt_len) ;
+
+	len = sm->smt_len ;
+	pa = (struct smt_para *) (sm + 1) ;
+	while (len > 0 ) {
+		int	plen ;
+#ifdef UNIX
+		printf("TYPE %x LEN %x VALUE\t",pa->p_type,pa->p_len) ;
+#else
+		printf("TYPE %04x LEN %2x VALUE\t",pa->p_type,pa->p_len) ;
+#endif
+		n = pa->p_len ;
+		if ( (n < 0 ) || (n > (int)(len - PARA_LEN))) {
+			n = len - PARA_LEN ;
+			printf(" BAD LENGTH\n") ;
+			break ;
+		}
+#ifdef	LITTLE_ENDIAN
+		smt_swap_para(sm,smtlen,0) ;
+#endif
+		if (n < 24) {
+			dump_hex((char *)(pa+1),(int) n) ;
+			printf("\n") ;
+		}
+		else {
+			int	first = 0 ;
+			c = (char *)(pa+1) ;
+			dump_hex(c,16) ;
+			printf("\n") ;
+			n -= 16 ;
+			c += 16 ;
+			while (n > 0) {
+				nn = (n > 16) ? 16 : n ;
+				if (n > 64) {
+					if (first == 0)
+						printf("\t\t\t...\n") ;
+					first = 1 ;
+				}
+				else {
+					printf("\t\t\t") ;
+					dump_hex(c,nn) ;
+					printf("\n") ;
+				}
+				n -= nn ;
+				c += 16 ;
+			}
+		}
+#ifdef	LITTLE_ENDIAN
+		smt_swap_para(sm,smtlen,1) ;
+#endif
+		plen = (pa->p_len + PARA_LEN + 3) & ~3 ;
+		len -= plen ;
+		pa = (struct smt_para *)((char *)pa + plen) ;
+	}
+	printf("-------------------------------------------------\n\n") ;
+}
+
+void dump_hex(p,len)
+char *p ;
+int len ;
+{
+	int	n = 0 ;
+	while (len--) {
+		n++ ;
+#ifdef UNIX
+		printf("%x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ;
+#else
+		printf("%02x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ;
+#endif
+	}
+}
+#endif	/* no BOOT */
+#endif	/* DEBUG */
+
+
+#endif	/* no SLIM_SMT */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/queue.c linux/drivers/net/skfp/queue.c
--- v2.3.46/linux/drivers/net/skfp/queue.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/queue.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT Event Queue Management
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)queue.c	2.9 97/08/04 (C) SK " ;
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ */
+void ev_init(smc)
+struct s_smc *smc ;
+{
+	smc->q.ev_put = smc->q.ev_get = smc->q.ev_queue ;
+}
+
+/*
+ * add event to queue
+ */
+void queue_event(smc,class,event)
+struct s_smc *smc ;
+int class ;
+int event ;
+{
+	PRINTF("queue class %d event %d\n",class,event) ;
+	smc->q.ev_put->class = class ;
+	smc->q.ev_put->event = event ;
+	if (++smc->q.ev_put == &smc->q.ev_queue[MAX_EVENT])
+		smc->q.ev_put = smc->q.ev_queue ;
+
+	if (smc->q.ev_put == smc->q.ev_get) {
+		SMT_ERR_LOG(smc,SMT_E0137, SMT_E0137_MSG) ;
+	}
+}
+
+/*
+ * timer_event is called from HW timer package.
+ */
+void timer_event(smc,token)
+struct s_smc *smc ;
+u_long token ;
+{
+	PRINTF("timer event class %d token %d\n",
+		EV_T_CLASS(token),
+		EV_T_EVENT(token)) ;
+	queue_event(smc,EV_T_CLASS(token),EV_T_EVENT(token));
+}
+
+/*
+ * event dispatcher
+ *	while event queue is not empty
+ *		get event from queue
+ *		send command to state machine
+ *	end
+ */
+void ev_dispatcher(smc)
+struct s_smc *smc ;
+{
+	struct event_queue *ev ;	/* pointer into queue */
+	int		class ;
+
+	ev = smc->q.ev_get ;
+	PRINTF("dispatch get %x put %x\n",ev,smc->q.ev_put) ;
+	while (ev != smc->q.ev_put) {
+		PRINTF("dispatch class %d event %d\n",ev->class,ev->event) ;
+		switch(class = ev->class) {
+		case EVENT_ECM :		/* Entity Corordination  Man. */
+			ecm(smc,(int)ev->event) ;
+			break ;
+		case EVENT_CFM :		/* Configuration Man. */
+			cfm(smc,(int)ev->event) ;
+			break ;
+		case EVENT_RMT :		/* Ring Man. */
+			rmt(smc,(int)ev->event) ;
+			break ;
+		case EVENT_SMT :
+			smt_event(smc,(int)ev->event) ;
+			break ;
+#ifdef	CONCENTRATOR
+		case 99 :
+			timer_test_event(smc,(int)ev->event) ;
+			break ;
+#endif
+		case EVENT_PCMA :		/* PHY A */
+		case EVENT_PCMB :		/* PHY B */
+		default :
+			if (class >= EVENT_PCMA &&
+			    class < EVENT_PCMA + NUMPHYS) {
+				pcm(smc,class - EVENT_PCMA,(int)ev->event) ;
+				break ;
+			}
+			SMT_PANIC(smc,SMT_E0121, SMT_E0121_MSG) ;
+			return ;
+		}
+
+		if (++ev == &smc->q.ev_queue[MAX_EVENT])
+			ev = smc->q.ev_queue ;
+
+		/* Renew get: it is used in queue_events to detect overruns */
+		smc->q.ev_get = ev;
+	}
+}
+
+/*
+ * smt_online connects to or disconnects from the ring
+ * MUST be called to initiate connection establishment
+ *
+ *	on	0	disconnect
+ *	on	1	connect
+ */
+u_short smt_online(smc,on)
+struct s_smc *smc ;
+int on ;
+{
+	queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ;
+	ev_dispatcher(smc) ;
+	return(smc->mib.fddiSMTCF_State) ;
+}
+
+/*
+ * set SMT flag to value
+ *	flag		flag name
+ *	value		flag value
+ * dump current flag setting
+ */
+#ifdef	CONCENTRATOR
+void do_smt_flag(smc,flag,value)
+struct s_smc *smc ;
+char *flag ;
+int value ;
+{
+#ifdef	DEBUG
+	struct smt_debug	*deb;
+
+	SK_UNUSED(smc) ;
+
+#ifdef	DEBUG_BRD
+	deb = &smc->debug;
+#else
+	deb = &debug;
+#endif
+	if (!strcmp(flag,"smt"))
+		deb->d_smt = value ;
+	else if (!strcmp(flag,"smtf"))
+		deb->d_smtf = value ;
+	else if (!strcmp(flag,"pcm"))
+		deb->d_pcm = value ;
+	else if (!strcmp(flag,"rmt"))
+		deb->d_rmt = value ;
+	else if (!strcmp(flag,"cfm"))
+		deb->d_cfm = value ;
+	else if (!strcmp(flag,"ecm"))
+		deb->d_ecm = value ;
+	printf("smt	%d\n",deb->d_smt) ;
+	printf("smtf	%d\n",deb->d_smtf) ;
+	printf("pcm	%d\n",deb->d_pcm) ;
+	printf("rmt	%d\n",deb->d_rmt) ;
+	printf("cfm	%d\n",deb->d_cfm) ;
+	printf("ecm	%d\n",deb->d_ecm) ;
+#endif	/* DEBUG */
+}
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/rmt.c linux/drivers/net/skfp/rmt.c
--- v2.3.46/linux/drivers/net/skfp/rmt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/rmt.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,674 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT RMT
+	Ring Management
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * 		queue_event()
+ * 		smt_timer_start()
+ * 		smt_timer_stop()
+ *
+ * 	The following external HW dependant functions are referenced :
+ *		sm_ma_control()
+ *		sm_mac_check_beacon_claim()
+ *
+ * 	The following HW dependant events are required :
+ *		RM_RING_OP
+ *		RM_RING_NON_OP
+ *		RM_MY_BEACON
+ *		RM_OTHER_BEACON
+ *		RM_MY_CLAIM
+ *		RM_TRT_EXP
+ *		RM_VALID_CLAIM
+ *
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)rmt.c	2.13 99/07/02 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG	0x10
+#define GO_STATE(x)	(smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
+#define ACTIONS_DONE()	(smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+#define RM0_ISOLATED	0
+#define RM1_NON_OP	1		/* not operational */
+#define RM2_RING_OP	2		/* ring operational */
+#define RM3_DETECT	3		/* detect dupl addresses */
+#define RM4_NON_OP_DUP	4		/* dupl. addr detected */
+#define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */
+#define RM6_DIRECTED	6		/* sending directed beacons */
+#define RM7_TRACE	7		/* trace initiated */
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const rmt_states[] = {
+	"RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
+	"RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
+	"RM7_TRACE"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const rmt_events[] = {
+	"NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
+	"RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
+	"RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
+	"RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
+	"RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
+	"RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
+} ;
+#endif
+
+/*
+ * Globals
+ * in struct s_rmt
+ */
+
+
+/*
+ * function declarations
+ */
+static void rmt_fsm() ;
+static void start_rmt_timer0() ;
+static void start_rmt_timer1() ;
+static void start_rmt_timer2() ;
+static void stop_rmt_timer0() ;
+static void stop_rmt_timer1() ;
+static void stop_rmt_timer2() ;
+static void rmt_dup_actions() ;
+static void rmt_reinsert_actions() ;
+static void rmt_leave_actions() ;
+static void rmt_new_dup_actions() ;
+
+#ifndef SUPERNET_3
+extern void restart_trt_for_dbcn() ;
+#endif /*SUPERNET_3*/
+
+/*
+	init RMT state machine
+	clear all RMT vars and flags
+*/
+void rmt_init(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
+	smc->r.dup_addr_test = DA_NONE ;
+	smc->r.da_flag = 0 ;
+	smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+	smc->r.sm_ma_avail = FALSE ;
+	smc->r.loop_avail = 0 ;
+	smc->r.bn_flag = 0 ;
+	smc->r.jm_flag = 0 ;
+	smc->r.no_flag = TRUE ;
+}
+
+/*
+	RMT state machine
+	called by dispatcher
+
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void rmt(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	int	state ;
+
+	do {
+		DB_RMT("RMT : state %s%s",
+			(smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "",
+			rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ;
+		DB_RMT(" event %s\n",rmt_events[event],0) ;
+		state = smc->mib.m[MAC0].fddiMACRMTState ;
+		rmt_fsm(smc,event) ;
+		event = 0 ;
+	} while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
+	rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
+}
+
+/*
+	process RMT event
+*/
+static void rmt_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+	/*
+	 * RM00-RM70 : from all states
+	 */
+	if (!smc->r.rm_join && !smc->r.rm_loop &&
+		smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
+		smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
+		RS_SET(smc,RS_NORINGOP) ;
+		rmt_indication(smc,0) ;
+		GO_STATE(RM0_ISOLATED) ;
+		return ;
+	}
+
+	switch(smc->mib.m[MAC0].fddiMACRMTState) {
+	case ACTIONS(RM0_ISOLATED) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+
+		/*
+		 * Disable MAC.
+		 */
+		sm_ma_control(smc,MA_OFFLINE) ;
+		smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+		smc->r.loop_avail = FALSE ;
+		smc->r.sm_ma_avail = FALSE ;
+		smc->r.no_flag = TRUE ;
+		DB_RMTN(1,"RMT : ISOLATED\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM0_ISOLATED :
+		/*RM01*/
+		if (smc->r.rm_join || smc->r.rm_loop) {
+			/*
+			 * According to the standard the MAC must be reset
+			 * here. The FORMAC will be initialized and Claim
+			 * and Beacon Frames will be uploaded to the MAC.
+			 * So any change of Treq will take effect NOW.
+			 */
+			sm_ma_control(smc,MA_RESET) ;
+			GO_STATE(RM1_NON_OP) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM1_NON_OP) :
+		start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		sm_ma_control(smc,MA_BEACON) ;
+		DB_RMTN(1,"RMT : RING DOWN\n",0,0) ;
+		RS_SET(smc,RS_NORINGOP) ;
+		smc->r.sm_ma_avail = FALSE ;
+		rmt_indication(smc,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM1_NON_OP :
+		/*RM12*/
+		if (cmd == RM_RING_OP) {
+			RS_SET(smc,RS_RINGOPCHANGE) ;
+			GO_STATE(RM2_RING_OP) ;
+			break ;
+		}
+		/*RM13*/
+		else if (cmd == RM_TIMEOUT_NON_OP) {
+			smc->r.bn_flag = FALSE ;
+			smc->r.no_flag = TRUE ;
+			GO_STATE(RM3_DETECT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM2_RING_OP) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		smc->r.no_flag = FALSE ;
+		if (smc->r.rm_loop)
+			smc->r.loop_avail = TRUE ;
+		if (smc->r.rm_join) {
+			smc->r.sm_ma_avail = TRUE ;
+			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
+				else
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+		}
+		DB_RMTN(1,"RMT : RING UP\n",0,0) ;
+		RS_CLEAR(smc,RS_NORINGOP) ;
+		RS_SET(smc,RS_RINGOPCHANGE) ;
+		rmt_indication(smc,1) ;
+		smt_stat_counter(smc,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM2_RING_OP :
+		/*RM21*/
+		if (cmd == RM_RING_NON_OP) {
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+			smc->r.loop_avail = FALSE ;
+			RS_SET(smc,RS_RINGOPCHANGE) ;
+			GO_STATE(RM1_NON_OP) ;
+			break ;
+		}
+		/*RM22a*/
+		else if (cmd == RM_ENABLE_FLAG) {
+			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
+				else
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+		}
+		/*RM25*/
+		else if (smc->r.dup_addr_test == DA_FAILED) {
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+			smc->r.loop_avail = FALSE ;
+			smc->r.da_flag = TRUE ;
+			GO_STATE(RM5_RING_OP_DUP) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM3_DETECT) :
+		start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
+		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
+		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+		sm_mac_check_beacon_claim(smc) ;
+		DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM3_DETECT :
+		if (cmd == RM_TIMEOUT_POLL) {
+			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+			sm_mac_check_beacon_claim(smc) ;
+			break ;
+		}
+		if (cmd == RM_TIMEOUT_D_MAX) {
+			smc->r.timer0_exp = TRUE ;
+		}
+		/*
+		 *jd(22-Feb-1999)
+		 * We need a time ">= 2*mac_d_max" since we had finished
+		 * Claim or Beacon state. So we will restart timer0 at
+		 * every state change.
+		 */
+		if (cmd == RM_TX_STATE_CHANGE) {
+			start_rmt_timer0(smc,
+					 smc->s.mac_d_max*2,
+					 RM_TIMEOUT_D_MAX) ;
+		}
+		/*RM32*/
+		if (cmd == RM_RING_OP) {
+			GO_STATE(RM2_RING_OP) ;
+			break ;
+		}
+		/*RM33a*/
+		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
+			&& smc->r.bn_flag) {
+			smc->r.bn_flag = FALSE ;
+		}
+		/*RM33b*/
+		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
+			int	tx ;
+			/*
+			 * set bn_flag only if in state T4 or T5:
+			 * only if we're the beaconer should we start the
+			 * trace !
+			 */
+			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
+			DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0);
+				smc->r.bn_flag = TRUE ;
+				/*
+				 * If one of the upstream stations beaconed
+				 * and the link to the upstream neighbor is
+				 * lost we need to restart the stuck timer to
+				 * check the "stuck beacon" condition.
+				 */
+				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
+					RM_TIMEOUT_T_STUCK) ;
+			}
+			/*
+			 * We do NOT need to clear smc->r.bn_flag in case of
+			 * not being in state T4 or T5, because the flag
+			 * must be cleared in order to get in this condition.
+			 */
+
+			DB_RMTN(2,
+			"RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
+			tx,smc->r.bn_flag) ;
+		}
+		/*RM34a*/
+		else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
+			rmt_new_dup_actions(smc) ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM34b*/
+		else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
+			rmt_new_dup_actions(smc) ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM34c*/
+		else if (cmd == RM_VALID_CLAIM) {
+			rmt_new_dup_actions(smc) ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM36*/
+		else if (cmd == RM_TIMEOUT_T_STUCK &&
+			smc->r.rm_join && smc->r.bn_flag) {
+			GO_STATE(RM6_DIRECTED) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM4_NON_OP_DUP) :
+		start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
+		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
+		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+		sm_mac_check_beacon_claim(smc) ;
+		DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM4_NON_OP_DUP :
+		if (cmd == RM_TIMEOUT_POLL) {
+			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+			sm_mac_check_beacon_claim(smc) ;
+			break ;
+		}
+		/*RM41*/
+		if (!smc->r.da_flag) {
+			GO_STATE(RM1_NON_OP) ;
+			break ;
+		}
+		/*RM44a*/
+		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+			smc->r.bn_flag) {
+			smc->r.bn_flag = FALSE ;
+		}
+		/*RM44b*/
+		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
+			int	tx ;
+			/*
+			 * set bn_flag only if in state T4 or T5:
+			 * only if we're the beaconer should we start the
+			 * trace !
+			 */
+			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
+			DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0);
+				smc->r.bn_flag = TRUE ;
+				/*
+				 * If one of the upstream stations beaconed
+				 * and the link to the upstream neighbor is
+				 * lost we need to restart the stuck timer to
+				 * check the "stuck beacon" condition.
+				 */
+				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
+					RM_TIMEOUT_T_STUCK) ;
+			}
+			/*
+			 * We do NOT need to clear smc->r.bn_flag in case of
+			 * not being in state T4 or T5, because the flag
+			 * must be cleared in order to get in this condition.
+			 */
+
+			DB_RMTN(2,
+			"RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
+			tx,smc->r.bn_flag) ;
+		}
+		/*RM44c*/
+		else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
+			rmt_dup_actions(smc) ;
+		}
+		/*RM45*/
+		else if (cmd == RM_RING_OP) {
+			smc->r.no_flag = FALSE ;
+			GO_STATE(RM5_RING_OP_DUP) ;
+			break ;
+		}
+		/*RM46*/
+		else if (cmd == RM_TIMEOUT_T_STUCK &&
+			smc->r.rm_join && smc->r.bn_flag) {
+			GO_STATE(RM6_DIRECTED) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM5_RING_OP_DUP) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ;
+		ACTIONS_DONE() ;
+		break;
+	case RM5_RING_OP_DUP :
+		/*RM52*/
+		if (smc->r.dup_addr_test == DA_PASSED) {
+			smc->r.da_flag = FALSE ;
+			GO_STATE(RM2_RING_OP) ;
+			break ;
+		}
+		/*RM54*/
+		else if (cmd == RM_RING_NON_OP) {
+			smc->r.jm_flag = FALSE ;
+			smc->r.bn_flag = FALSE ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM6_DIRECTED) :
+		start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
+		stop_rmt_timer1(smc) ;
+		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+		sm_ma_control(smc,MA_DIRECTED) ;
+		RS_SET(smc,RS_BEACON) ;
+		DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM6_DIRECTED :
+		/*RM63*/
+		if (cmd == RM_TIMEOUT_POLL) {
+			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+			sm_mac_check_beacon_claim(smc) ;
+#ifndef SUPERNET_3
+			/* Because of problems with the Supernet II chip set
+			 * sending of Directed Beacon will stop after 165ms
+			 * therefore restart_trt_for_dbcn(smc) will be called
+			 * to prevent this.
+			 */
+			restart_trt_for_dbcn(smc) ;
+#endif /*SUPERNET_3*/
+			break ;
+		}
+		if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+			!smc->r.da_flag) {
+			smc->r.bn_flag = FALSE ;
+			GO_STATE(RM3_DETECT) ;
+			break ;
+		}
+		/*RM64*/
+		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+			smc->r.da_flag) {
+			smc->r.bn_flag = FALSE ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM67*/
+		else if (cmd == RM_TIMEOUT_T_DIRECT) {
+			GO_STATE(RM7_TRACE) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM7_TRACE) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
+		queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
+		DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM7_TRACE :
+		break ;
+	default:
+		SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
+		break;
+	}
+}
+
+/*
+ * (jd) RMT duplicate address actions
+ * leave the ring or reinsert just as configured
+ */
+static void rmt_dup_actions(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.jm_flag) {
+	}
+	else {
+		if (smc->s.rmt_dup_mac_behavior) {
+			SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
+                        rmt_reinsert_actions(smc) ;
+		}
+		else {
+			SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
+			rmt_leave_actions(smc) ;
+		}
+	}
+}
+
+/*
+ * Reconnect to the Ring
+ */
+static void rmt_reinsert_actions(smc)
+struct s_smc *smc ;
+{
+	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+	queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+}
+
+/*
+ * duplicate address detected
+ */
+static void rmt_new_dup_actions(smc)
+struct s_smc *smc ;
+{
+	smc->r.da_flag = TRUE ;
+	smc->r.bn_flag = FALSE ;
+	smc->r.jm_flag = FALSE ;
+	/*
+	 * we have three options : change address, jam or leave
+	 * we leave the ring as default 
+	 * Optionally it's possible to reinsert after leaving the Ring
+	 * but this will not conform with SMT Spec.
+	 */
+	if (smc->s.rmt_dup_mac_behavior) {
+		SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
+		rmt_reinsert_actions(smc) ;
+	}
+	else {
+		SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
+		rmt_leave_actions(smc) ;
+	}
+}
+
+
+/*
+ * leave the ring
+ */
+static void rmt_leave_actions(smc)
+struct s_smc *smc ;
+{
+	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+	/*
+	 * Note: Do NOT try again later. (with please reconnect)
+	 * The station must be left from the ring!
+	 */
+}
+
+/*
+ * SMT timer interface
+ *	start RMT timer 0
+ */
+static void start_rmt_timer0(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+	smc->r.timer0_exp = FALSE ;		/* clear timer event flag */
+	smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ *	start RMT timer 1
+ */
+static void start_rmt_timer1(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+	smc->r.timer1_exp = FALSE ;	/* clear timer event flag */
+	smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ *	start RMT timer 2
+ */
+static void start_rmt_timer2(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+	smc->r.timer2_exp = FALSE ;		/* clear timer event flag */
+	smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ *	stop RMT timer 0
+ */
+static void stop_rmt_timer0(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.rmt_timer0.tm_active)
+		smt_timer_stop(smc,&smc->r.rmt_timer0) ;
+}
+
+/*
+ * SMT timer interface
+ *	stop RMT timer 1
+ */
+static void stop_rmt_timer1(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.rmt_timer1.tm_active)
+		smt_timer_stop(smc,&smc->r.rmt_timer1) ;
+}
+
+/*
+ * SMT timer interface
+ *	stop RMT timer 2
+ */
+static void stop_rmt_timer2(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.rmt_timer2.tm_active)
+		smt_timer_stop(smc,&smc->r.rmt_timer2) ;
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c
--- v2.3.46/linux/drivers/net/skfp/skfddi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/skfddi.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,2495 @@
+/*
+ * File Name:
+ *   skfddi.c
+ *
+ * Copyright Information:
+ *   Copyright SysKonnect 1998,1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ * Abstract:
+ *   A Linux device driver supporting the SysKonnect FDDI PCI controller
+ *   familie.
+ *
+ * Maintainers:
+ *   CG    Christoph Goos (cgoos@syskonnect.de)
+ *
+ * Address all question to:
+ *   linux@syskonnect.de
+ *
+ * The technical manual for the adapters is available from SysKonnect's
+ * web pages: www.syskonnect.com
+ * Goto "Support" and search Knowledge Base for "manual".
+ *
+ * Driver Architecture:
+ *   The driver architecture is based on the DEC FDDI driver by
+ *   Lawrence V. Stefani and several ethernet drivers.
+ *   I also used an existing Windows NT miniport driver.
+ *   All hardware dependant fuctions are handled by the SysKonnect
+ *   Hardware Module.
+ *   The only headerfiles that are directly related to this source
+ *   are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h.
+ *   The others belong to the SysKonnect FDDI Hardware Module and
+ *   should better not be changed.
+ * NOTE:
+ *   Compiling this driver produces some warnings, but I did not fix
+ *   this, because the Hardware Module source is used for different
+ *   drivers, and fixing it for Linux might bring problems on other
+ *   projects. To keep the source common for all those drivers (and
+ *   thus simplify fixes to it), please do not clean it up!
+ *
+ * Modification History:
+ *              Date            Name    Description
+ *              02-Mar-98       CG	Created.
+ *
+ *		10-Mar-99	CG	Support for 2.2.x added.
+ *		25-Mar-99	CG	Corrected IRQ routing for SMP (APIC)
+ *		26-Oct-99	CG	Fixed compilation error on 2.2.13
+ *		12-Nov-99	CG	Source code release
+ *		22-Nov-99	CG	Included in kernel source.
+ *
+ * Compilation options (-Dxxx):
+ *              DRIVERDEBUG     print lots of messages to log file
+ *              DUMPPACKETS     print received/transmitted packets to logfile
+ * 
+ * Limitations:
+ *	I changed the driver to support memory mapped I/O, so it
+ *	might run on non-x86 architectures (not tested).
+ *	But the hardware module does not yet support 64 bit OS'es.
+ */
+
+/* Version information string - should be updated prior to */
+/* each new release!!! */
+#define VERSION		"2.05"
+
+static const char *boot_msg = 
+	"SysKonnect FDDI PCI Adapter driver v" VERSION " for\n"
+	"  SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)";
+
+/* Include files */
+
+#include <linux/module.h>
+
+#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/delay.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>	// isdigit
+
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+
+#include	"h/types.h"
+#undef ADDR			// undo Linux definition
+#include	"h/skfbi.h"
+#include	"h/fddi.h"
+#include	"h/smc.h"
+#include	"h/smtstate.h"
+
+
+// Define global routines
+int skfp_probe(struct net_device *dev);
+
+
+// Define module-wide (static) routines
+static struct net_device *alloc_device(struct net_device *dev, u_long iobase);
+static struct net_device *insert_device(struct net_device *dev,
+				    int (*init) (struct net_device *));
+static int fddi_dev_index(unsigned char *s);
+static void init_dev(struct net_device *dev, u_long iobase);
+static void link_modules(struct net_device *dev, struct net_device *tmp);
+static int skfp_driver_init(struct net_device *dev);
+static int skfp_open(struct net_device *dev);
+static int skfp_close(struct net_device *dev);
+static void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct enet_statistics *skfp_ctl_get_stats(struct net_device *dev);
+static void skfp_ctl_set_multicast_list(struct net_device *dev);
+static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev);
+static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr);
+static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev);
+static void send_queued_packets(struct s_smc *smc);
+static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr);
+static void ResetAdapter(struct s_smc *smc);
+
+
+// Functions needed by the hardware module
+void *mac_drv_get_space(struct s_smc *smc, u_int size);
+void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size);
+unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt);
+unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag);
+void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr,
+		  int flag);
+void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd);
+void llc_restart_tx(struct s_smc *smc);
+void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count, int len);
+void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count);
+void mac_drv_fill_rxd(struct s_smc *smc);
+void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+		       int frag_count);
+int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
+		    int la_len);
+void smt_timer_poll(struct s_smc *smc);
+void ring_status_indication(struct s_smc *smc, u_long status);
+unsigned long smt_get_time(void);
+void smt_stat_counter(struct s_smc *smc, int stat);
+void cfm_state_change(struct s_smc *smc, int c_state);
+void ecm_state_change(struct s_smc *smc, int e_state);
+void pcm_state_change(struct s_smc *smc, int plc, int p_state);
+void rmt_state_change(struct s_smc *smc, int r_state);
+void drv_reset_indication(struct s_smc *smc);
+void dump_data(unsigned char *Data, int length);
+
+
+// External functions from the hardware module
+extern u_int mac_drv_check_space();
+extern void read_address(struct s_smc *smc, u_char * mac_addr);
+extern void card_stop(struct s_smc *smc);
+extern int mac_drv_init(struct s_smc *smc);
+extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys,
+			int len, int frame_status);
+extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count,
+		       int frame_len, int frame_status);
+extern int init_smt(struct s_smc *smc, u_char * mac_addr);
+extern void fddi_isr(struct s_smc *smc);
+extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
+			int len, int frame_status);
+extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
+extern void mac_drv_clear_tx_queue(struct s_smc *smc);
+extern void mac_drv_clear_rx_queue(struct s_smc *smc);
+extern void mac_clear_multicast(struct s_smc *smc);
+extern void enable_tx_irq(struct s_smc *smc, u_short queue);
+extern void mac_drv_clear_txd(struct s_smc *smc);
+
+
+// Define module-wide (static) variables
+
+static int num_boards = 0;	/* total number of adapters configured */
+static int num_fddi = 0;
+static int autoprobed = 0;
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static struct net_device *unlink_modules(struct net_device *p);
+static int loading_module = 1;
+#else
+static int loading_module = 0;
+#endif				// MODULE
+
+#ifdef DRIVERDEBUG
+#define PRINTK(s, args...) printk(s, ## args)
+#else
+#define PRINTK(s, args...)
+#endif				// DRIVERDEBUG
+
+#define PRIV(dev) (&(((struct s_smc *)dev->priv)->os))
+
+/*
+ * ==============
+ * = skfp_probe =
+ * ==============
+ *   
+ * Overview:
+ *   Probes for supported FDDI PCI controllers
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This routine is called by the OS for each FDDI device name (fddi0,
+ *   fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c.
+ *   If loaded as a module, it will detect and initialize all 
+ *   adapters the first time it is called.
+ *
+ *   Let's say that skfp_probe() is getting called to initialize fddi0.
+ *   Furthermore, let's say there are three supported controllers in the
+ *   system.  Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2
+ *   will be initialized and a global flag will be set to indicate that
+ *   skfp_probe() has already been called.
+ *
+ *   However...the OS doesn't know that we've already initialized
+ *   devices fddi1 and fddi2 so skfp_probe() gets called again and again
+ *   until it reaches the end of the device list for FDDI (presently,
+ *   fddi7).  It's important that the driver "pretend" to probe for
+ *   devices fddi1 and fddi2 and return success.  Devices fddi3
+ *   through fddi7 will return failure since they weren't initialized.
+ *
+ *   This algorithm seems to work for the time being.  As other FDDI
+ *   drivers are written for Linux, a more generic approach (perhaps
+ *   similar to the Ethernet card approach) may need to be implemented.
+ *   
+ * Return Codes:
+ *   0           - This device (fddi0, fddi1, etc) configured successfully
+ *   -ENODEV - No devices present, or no SysKonnect FDDI PCI device
+ *                         present for this device name
+ *
+ *
+ * Side Effects:
+ *   Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ *   initialized and the board resources are read and stored in
+ *   the device structure.
+ */
+int skfp_probe(struct net_device *dev)
+{
+	int i;			/* used in for loops */
+	struct pci_dev *pdev = NULL;	/* PCI device structure */
+#ifndef MEM_MAPPED_IO
+	u16 port;		/* temporary I/O (port) address */
+	int port_len;		/* length of port address range (in bytes) */
+#else
+	unsigned long port;
+#endif
+	u16 command;	/* PCI Configuration space Command register val */
+	struct s_smc *smc;	/* board pointer */
+	struct net_device *tmp = dev;
+	u8 first_dev_used = 0;
+	u16 SubSysId;
+
+	PRINTK(KERN_INFO "entering skfp_probe\n");
+
+	/*
+	 * Verify whether we're going through skfp_probe() again
+	 *
+	 * If so, see if we're going through for a subsequent fddi device that
+	 * we've already initialized.  If we are, return success (0).  If not,
+	 * return failure (-ENODEV).
+	 */
+
+	if (autoprobed) {
+		PRINTK(KERN_INFO "Already entered skfp_probe\n");
+		if (dev != NULL) {
+			if ((strncmp(dev->name, "fddi", 4) == 0) &&
+			    (dev->base_addr != 0)) {
+				return (0);
+			}
+			return (-ENODEV);
+		}
+	}
+	autoprobed = 1;		/* set global flag */
+
+	printk("%s\n", boot_msg);
+
+	/* Scan for Syskonnect FDDI PCI controllers */
+	if (!pci_present()) {	/* is PCI BIOS even present? */
+		printk("no PCI BIOS present\n");
+		return (-ENODEV);
+	}
+	for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) {	// scan for PCI cards
+		PRINTK(KERN_INFO "Check device %d\n", i);
+		if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP,
+			pdev)) == 0) {
+			break;
+		}
+
+#ifndef MEM_MAPPED_IO
+		/* Verify that I/O enable bit is set (PCI slot is enabled) */
+		pci_read_config_word(pdev, PCI_COMMAND, &command);
+		if ((command & PCI_COMMAND_IO) == 0) {
+			PRINTK("I/O enable bit not set!");
+			PRINTK(" Verify that slot is enabled\n");
+			continue;
+		}
+
+		/* Turn off memory mapped space and enable mastering */
+
+		PRINTK(KERN_INFO "Command Reg: %04x\n", command);
+		command |= PCI_COMMAND_MASTER;
+		command &= ~PCI_COMMAND_MEMORY;
+		pci_write_config_word(pdev, PCI_COMMAND, command);
+
+		/* Read I/O base address from PCI Configuration Space */
+
+		pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port);
+		port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0)
+
+		/* Verify port address range is not already being used */
+
+		port_len = FP_IO_LEN;
+		if (check_region(port, port_len) != 0) {
+			printk("I/O range allocated to adapter");
+			printk(" (0x%X-0x%X) is already being used!\n", port,
+			       (port + port_len - 1));
+			continue;
+		}
+#else
+		/* Verify that MEM enable bit is set (PCI slot is enabled) */
+		pci_read_config_word(pdev, PCI_COMMAND, &command);
+		if ((command & PCI_COMMAND_MEMORY) == 0) {
+			PRINTK("MEMORY-I/O enable bit not set!");
+			PRINTK(" Verify that slot is enabled\n");
+			continue;
+		}
+
+		/* Turn off IO mapped space and enable mastering */
+
+		PRINTK(KERN_INFO "Command Reg: %04x\n", command);
+		command |= PCI_COMMAND_MASTER;
+		command &= ~PCI_COMMAND_IO;
+		pci_write_config_word(pdev, PCI_COMMAND, command);
+
+		port = pdev->resource[0].start;
+
+		port = (unsigned long)ioremap(port, 0x4000);
+		if (!port){
+			printk("skfp:  Unable to map MEMORY register, "
+			"FDDI adapter will be disabled.\n");
+			break;
+		}
+#endif
+
+		if ((!loading_module) || first_dev_used) {
+			/* Allocate a device structure for this adapter */
+			tmp = alloc_device(dev, port);
+		}
+		first_dev_used = 1;	// only significant first time
+
+		pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId);
+
+		if (tmp != NULL) {
+			if (loading_module)
+				link_modules(dev, tmp);
+			dev = tmp;
+			init_dev(dev, port);
+			dev->irq = pdev->irq;
+
+			/* Initialize board structure with bus-specific info */
+
+			smc = (struct s_smc *) dev->priv;
+			smc->os.dev = dev;
+			smc->os.bus_type = SK_BUS_TYPE_PCI;
+			smc->os.pdev = *pdev;
+			smc->os.QueueSkb = MAX_TX_QUEUE_LEN;
+			smc->os.MaxFrameSize = MAX_FRAME_SIZE;
+			smc->os.dev = dev;
+			smc->hw.slot = -1;
+			smc->os.ResetRequested = FALSE;
+			skb_queue_head_init(&smc->os.SendSkbQueue);
+
+			if (skfp_driver_init(dev) == 0) {
+				// only increment global board 
+				// count on success
+				num_boards++;
+				request_region(dev->base_addr,
+					       FP_IO_LEN, dev->name);
+				if ((SubSysId & 0xff00) == 0x5500 ||
+					(SubSysId & 0xff00) == 0x5800) {
+				printk("%s: SysKonnect FDDI PCI adapter"
+				       " found (SK-%04X)\n", dev->name,
+					SubSysId);
+				} else {
+				printk("%s: FDDI PCI adapter found\n",
+					dev->name);
+				}
+			} else {
+				kfree(dev);
+				i = SKFP_MAX_NUM_BOARDS;	// stop search
+
+			}
+
+		}		// if (dev != NULL)
+
+	}			// for SKFP_MAX_NUM_BOARDS
+
+	/*
+	 * If we're at this point we're going through skfp_probe() for the
+	 * first time. Return success (0) if we've initialized 1 or more
+	 * boards. Otherwise, return failure (-ENODEV).
+	 */
+
+	if (num_boards > 0)
+		return (0);
+	else {
+		printk("no SysKonnect FDDI adapter found\n");
+		return (-ENODEV);
+	}
+}				// skfp_probe
+
+
+/************************
+ *
+ * Search the entire 'fddi' 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.
+ *
+ ************************/
+static struct net_device *alloc_device(struct net_device *dev, u_long iobase)
+{
+	struct net_device *adev = NULL;
+	int fixed = 0, new_dev = 0;
+
+	PRINTK(KERN_INFO "entering alloc_device\n");
+	if (!dev)
+		return dev;
+
+	num_fddi = fddi_dev_index(dev->name);
+	if (loading_module) {
+		num_fddi++;
+		dev = insert_device(dev, skfp_probe);
+		return dev;
+	}
+	while (1) {
+		if (((dev->base_addr == NO_ADDRESS) ||
+		     (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, "fddi", 4) != 0) {
+				new_dev = 1;
+			}
+		}
+		if ((dev->next == NULL) || new_dev || fixed)
+			break;
+		dev = dev->next;
+		num_fddi++;
+	}			// while (1)
+
+	if (adev && !fixed) {
+		dev = adev;
+		num_fddi = fddi_dev_index(dev->name);
+		new_dev = 0;
+	}
+	if (((dev->next == NULL) && ((dev->base_addr != NO_ADDRESS) &&
+				     (dev->base_addr != 0)) && !fixed) ||
+	    new_dev) {
+		num_fddi++;	/* New device */
+		dev = insert_device(dev, skfp_probe);
+	}
+	if (dev) {
+		if (!dev->priv) {
+			/* Allocate space for private board structure */
+			dev->priv = (void *) kmalloc(sizeof(struct s_smc),
+						     GFP_KERNEL);
+			if (dev->priv == NULL) {
+				printk("%s: Could not allocate memory for",
+					dev->name);
+				printk(" private board structure!\n");
+				return (NULL);
+			}
+			/* clear structure */
+			memset(dev->priv, 0, sizeof(struct s_smc));
+		}
+	}
+	return dev;
+}				// alloc_device
+
+
+
+/************************
+ *
+ * Initialize device structure
+ *
+ ************************/
+static void init_dev(struct net_device *dev, u_long iobase)
+{
+	/* Initialize new device structure */
+
+	dev->rmem_end = 0;	/* shared memory isn't used */
+	dev->rmem_start = 0;	/* shared memory isn't used */
+	dev->mem_end = 0;	/* shared memory isn't used */
+	dev->mem_start = 0;	/* shared memory isn't used */
+	dev->base_addr = iobase;	/* save port (I/O) base address */
+	dev->if_port = 0;	/* not applicable to FDDI adapters */
+	dev->dma = 0;		/* Bus Master DMA doesn't require channel */
+	dev->irq = 0;
+
+	netif_start_queue(dev);
+
+	dev->get_stats = &skfp_ctl_get_stats;
+	dev->open = &skfp_open;
+	dev->stop = &skfp_close;
+	dev->hard_start_xmit = &skfp_send_pkt;
+	dev->hard_header = NULL;	/* set in fddi_setup() */
+	dev->rebuild_header = NULL;	/* set in fddi_setup() */
+	dev->set_multicast_list = &skfp_ctl_set_multicast_list;
+	dev->set_mac_address = &skfp_ctl_set_mac_address;
+	dev->do_ioctl = &skfp_ioctl;
+	dev->set_config = NULL;	/* not supported for now &&& */
+	dev->header_cache_update = NULL;	/* not supported */
+	dev->change_mtu = NULL;	/* set in fddi_setup() */
+
+	/* Initialize remaining device structure information */
+	fddi_setup(dev);
+}				// init_device
+
+
+/************************
+ *
+ * If at end of fddi device list and can't use current entry, malloc
+ * one up. If memory could not be allocated, print an error message.
+ *
+************************/
+static struct net_device *insert_device(struct net_device *dev,
+				    int (*init) (struct net_device *))
+{
+	struct net_device *new;
+	int len;
+
+	PRINTK(KERN_INFO "entering insert_device\n");
+	len = sizeof(struct net_device) + 8 + sizeof(struct s_smc);
+	new = (struct net_device *) kmalloc(len, GFP_KERNEL);
+	if (new == NULL) {
+		printk("fddi%d: Device not initialised, insufficient memory\n",
+		       num_fddi);
+		return NULL;
+	} else {
+		memset((char *) new, 0, len);
+		new->name = (char *) (new + 1);
+		new->priv = (struct s_smc *) (new->name + 8);
+		new->init = init;	/* initialisation routine */
+		if (!loading_module) {
+			new->next = dev->next;
+			dev->next = new;
+		}
+		/* create new device name */
+		if (num_fddi > 999) {
+			sprintf(new->name, "fddi????");
+		} else {
+			sprintf(new->name, "fddi%d", num_fddi);
+		}
+	}
+	return new;
+}				// insert_device
+
+
+/************************
+ *
+ * Get the number of a "fddiX" string
+ *
+ ************************/
+static int fddi_dev_index(unsigned 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;
+}				// fddi_dev_index
+
+
+/************************
+ *
+ * Used if loaded as module only. Link the device structures
+ * together. Needed to release them all at unload.
+ *
+************************/
+static void link_modules(struct net_device *dev, struct net_device *tmp)
+{
+	struct net_device *p = dev;
+
+	if (p) {
+		while (((struct s_smc *) (p->priv))->os.next_module) {
+			p = ((struct s_smc *) (p->priv))->os.next_module;
+		}
+
+		if (dev != tmp) {
+			((struct s_smc *) (p->priv))->os.next_module = tmp;
+		} else {
+			((struct s_smc *) (p->priv))->os.next_module = NULL;
+		}
+	}
+	return;
+}				// link_modules
+
+
+
+/*
+ * ====================
+ * = skfp_driver_init =
+ * ====================
+ *   
+ * Overview:
+ *   Initializes remaining adapter board structure information
+ *   and makes sure adapter is in a safe state prior to skfp_open().
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function allocates additional resources such as the host memory
+ *   blocks needed by the adapter.
+ *   The adapter is also reset. The OS must call skfp_open() to open 
+ *   the adapter and bring it on-line.
+ *
+ * Return Codes:
+ *    0 - initialization succeeded
+ *   -1 - initialization failed
+ */
+static int skfp_driver_init(struct net_device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	skfddi_priv *bp = PRIV(dev);
+	u8 val;			/* used for I/O read/writes */
+
+	PRINTK(KERN_INFO "entering skfp_driver_init\n");
+
+	// set the io address in private structures
+	bp->base_addr = dev->base_addr;
+	smc->hw.iop = dev->base_addr;
+
+	// Get the interrupt level from the PCI Configuration Table
+	val = dev->irq;
+
+	smc->hw.irq = val;
+
+	spin_lock_init(&bp->DriverLock);
+	
+	// Determine the required size of the 'shared' memory area.
+	bp->SharedMemSize = mac_drv_check_space();
+	PRINTK(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize);
+	if (bp->SharedMemSize > 0) {
+		bp->SharedMemSize += 16;	// for descriptor alignment
+
+		bp->SharedMemAddr = kmalloc(bp->SharedMemSize, GFP_KERNEL);
+		if (!bp->SharedMemSize) {
+			printk("could not allocate mem for ");
+			printk("hardware module: %ld byte\n",
+			       bp->SharedMemSize);
+			return (-1);
+		}
+		bp->SharedMemHeap = 0;	// Nothing used yet.
+
+	} else {
+		bp->SharedMemAddr = NULL;
+		bp->SharedMemHeap = 0;
+	}			// SharedMemSize > 0
+
+	memset(bp->SharedMemAddr, 0, bp->SharedMemSize);
+
+	card_stop(smc);		// Reset adapter.
+
+	PRINTK(KERN_INFO "mac_drv_init()..\n");
+	if (mac_drv_init(smc) != 0) {
+		PRINTK(KERN_INFO "mac_drv_init() failed.\n");
+		return (-1);
+	}
+	read_address(smc, NULL);
+	PRINTK(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n",
+	       smc->hw.fddi_canon_addr.a[0],
+	       smc->hw.fddi_canon_addr.a[1],
+	       smc->hw.fddi_canon_addr.a[2],
+	       smc->hw.fddi_canon_addr.a[3],
+	       smc->hw.fddi_canon_addr.a[4],
+	       smc->hw.fddi_canon_addr.a[5]);
+	memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
+
+	smt_reset_defaults(smc, 0);
+
+	return (0);
+}				// skfp_driver_init
+
+
+/*
+ * =============
+ * = skfp_open =
+ * =============
+ *   
+ * Overview:
+ *   Opens the adapter
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function brings the adapter to an operational state.
+ *
+ * Return Codes:
+ *   0           - Adapter was successfully opened
+ *   -EAGAIN - Could not register IRQ
+ */
+static int skfp_open(struct net_device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+
+	PRINTK(KERN_INFO "entering skfp_open\n");
+	/* Register IRQ - support shared interrupts by passing device ptr */
+	if (request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ,
+			dev->name, dev)) {
+		printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
+		return (-EAGAIN);
+	}
+	/*
+	 * Set current address to factory MAC address
+	 *
+	 * Note: We've already done this step in skfp_driver_init.
+	 *       However, it's possible that a user has set a node
+	 *               address override, then closed and reopened the
+	 *               adapter.  Unless we reset the device address field
+	 *               now, we'll continue to use the existing modified
+	 *               address.
+	 */
+	read_address(smc, NULL);
+	memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
+
+	init_smt(smc, NULL);
+	smt_online(smc, 1);
+	STI_FBI();
+
+	MOD_INC_USE_COUNT;
+
+	/* Clear local multicast address tables */
+	mac_clear_multicast(smc);
+
+	/* Disable promiscuous filter settings */
+	mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
+
+	return (0);
+}				// skfp_open
+
+
+/*
+ * ==============
+ * = skfp_close =
+ * ==============
+ *   
+ * Overview:
+ *   Closes the device/module.
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This routine closes the adapter and brings it to a safe state.
+ *   The interrupt service routine is deregistered with the OS.
+ *   The adapter can be opened again with another call to skfp_open().
+ *
+ * Return Codes:
+ *   Always return 0.
+ *
+ * Assumptions:
+ *   No further requests for this adapter are made after this routine is
+ *   called.  skfp_open() can be called to reset and reinitialize the
+ *   adapter.
+ */
+static int skfp_close(struct net_device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	struct sk_buff *skb;
+	skfddi_priv *bp = PRIV(dev);
+
+	CLI_FBI();
+	smt_reset_defaults(smc, 1);
+	card_stop(smc);
+	mac_drv_clear_tx_queue(smc);
+	mac_drv_clear_rx_queue(smc);
+
+	netif_stop_queue(dev);
+	/* Deregister (free) IRQ */
+	free_irq(dev->irq, dev);
+
+	for (;;) {
+		skb = skb_dequeue(&bp->SendSkbQueue);
+		if (skb == NULL)
+			break;
+		bp->QueueSkb++;
+		dev_kfree_skb(skb);
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return (0);
+}				// skfp_close
+
+
+/*
+ * ==================
+ * = skfp_interrupt =
+ * ==================
+ *   
+ * Overview:
+ *   Interrupt processing routine
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   irq        - interrupt vector
+ *   dev_id     - pointer to device information
+ *       regs   - pointer to registers structure
+ *
+ * Functional Description:
+ *   This routine calls the interrupt processing routine for this adapter.  It
+ *   disables and reenables adapter interrupts, as appropriate.  We can support
+ *   shared interrupts since the incoming dev_id pointer provides our device
+ *   structure context. All the real work is done in the hardware module.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   The interrupt acknowledgement at the hardware level (eg. ACKing the PIC
+ *   on Intel-based systems) is done by the operating system outside this
+ *   routine.
+ *
+ *       System interrupts are enabled through this call.
+ *
+ * Side Effects:
+ *   Interrupts are disabled, then reenabled at the adapter.
+ */
+
+void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct s_smc *smc;	/* private board structure pointer */
+	skfddi_priv *bp = PRIV(dev);
+
+
+	if (dev == NULL) {
+		printk("%s: irq %d for unknown device\n", dev->name, irq);
+		return;
+	}
+
+	smc = (struct s_smc *) dev->priv;
+
+	// IRQs enabled or disabled ?
+	if (inpd(ADDR(B0_IMSK)) == 0) {
+		// IRQs are disabled: must be shared interrupt
+		return;
+	}
+	// Note: At this point, IRQs are enabled.
+	if ((inpd(ISR_A) & smc->hw.is_imask) == 0) {	// IRQ?
+		// Adapter did not issue an IRQ: must be shared interrupt
+		return;
+	}
+	CLI_FBI();		// Disable IRQs from our adapter.
+	spin_lock(&bp->DriverLock);
+
+	// Call interrupt handler in hardware module (HWM).
+	fddi_isr(smc);
+
+	if (smc->os.ResetRequested) {
+		ResetAdapter(smc);
+		smc->os.ResetRequested = FALSE;
+	}
+	spin_unlock(&bp->DriverLock);
+	STI_FBI();		// Enable IRQs from our adapter.
+
+	return;
+}				// skfp_interrupt
+
+
+/*
+ * ======================
+ * = skfp_ctl_get_stats =
+ * ======================
+ *   
+ * Overview:
+ *   Get statistics for FDDI adapter
+ *  
+ * Returns:
+ *   Pointer to FDDI statistics structure
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Gets current MIB objects from adapter, then
+ *   returns FDDI statistics structure as defined
+ *   in if_fddi.h.
+ *
+ *   Note: Since the FDDI statistics structure is
+ *   still new and the device structure doesn't
+ *   have an FDDI-specific get statistics handler,
+ *   we'll return the FDDI statistics structure as
+ *   a pointer to an Ethernet statistics structure.
+ *   That way, at least the first part of the statistics
+ *   structure can be decoded properly.
+ *   We'll have to pay attention to this routine as the
+ *   device structure becomes more mature and LAN media
+ *   independent.
+ *
+ */
+struct enet_statistics *skfp_ctl_get_stats(struct net_device *dev)
+{
+	struct s_smc *bp = (struct s_smc *) dev->priv;
+
+	/* Fill the bp->stats structure with driver-maintained counters */
+
+	bp->os.MacStat.port_bs_flag[0] = 0x1234;
+	bp->os.MacStat.port_bs_flag[1] = 0x5678;
+// goos: need to fill out fddi statistic
+#if 0
+	/* Get FDDI SMT MIB objects */
+
+/* Fill the bp->stats structure with the SMT MIB object values */
+
+	memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id));
+	bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id;
+	bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id;
+	bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id;
+	memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data));
+	bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id;
+	bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct;
+	bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct;
+	bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct;
+	bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths;
+	bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities;
+	bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy;
+	bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy;
+	bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify;
+	bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy;
+	bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration;
+	bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present;
+	bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state;
+	bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state;
+	bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag;
+	bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status;
+	bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag;
+	bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls;
+	bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls;
+	bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions;
+	bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability;
+	bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability;
+	bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths;
+	bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path;
+	memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN);
+	bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test;
+	bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths;
+	bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type;
+	memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN);
+	bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req;
+	bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg;
+	bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max;
+	bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value;
+	bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold;
+	bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio;
+	bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state;
+	bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag;
+	bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag;
+	bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag;
+	bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available;
+	bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present;
+	bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable;
+	bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound;
+	bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound;
+	bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req;
+	memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration));
+	bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0];
+	bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1];
+	bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0];
+	bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1];
+	bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0];
+	bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1];
+	bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0];
+	bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1];
+	bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0];
+	bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1];
+	memcpy(&bp->stats.port_requested_paths[0 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3);
+	memcpy(&bp->stats.port_requested_paths[1 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3);
+	bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0];
+	bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1];
+	bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0];
+	bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1];
+	bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0];
+	bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1];
+	bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0];
+	bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1];
+	bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0];
+	bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1];
+	bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0];
+	bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1];
+	bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0];
+	bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1];
+	bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0];
+	bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1];
+	bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0];
+	bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1];
+	bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0];
+	bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1];
+	bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0];
+	bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1];
+	bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0];
+	bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1];
+	bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0];
+	bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1];
+
+
+	/* Fill the bp->stats structure with the FDDI counter values */
+
+	bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls;
+	bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls;
+	bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls;
+	bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls;
+	bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls;
+	bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls;
+	bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls;
+	bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls;
+	bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls;
+	bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls;
+	bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
+
+#endif
+	return ((struct enet_statistics *) &bp->os.MacStat);
+}				// ctl_get_stat
+
+
+/*
+ * ==============================
+ * = skfp_ctl_set_multicast_list =
+ * ==============================
+ *   
+ * Overview:
+ *   Enable/Disable LLC frame promiscuous mode reception
+ *   on the adapter and/or update multicast address table.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function aquires the driver lock and only calls
+ *   skfp_ctl_set_multicast_list_wo_lock then.
+ *   This routine follows a fairly simple algorithm for setting the
+ *   adapter filters and CAM:
+ *
+ *      if IFF_PROMISC flag is set
+ *              enable promiscuous mode
+ *      else
+ *              disable promiscuous mode
+ *              if number of multicast addresses <= max. multicast number
+ *                      add mc addresses to adapter table
+ *              else
+ *                      enable promiscuous mode
+ *              update adapter filters
+ *
+ * Assumptions:
+ *   Multicast addresses are presented in canonical (LSB) format.
+ *
+ * Side Effects:
+ *   On-board adapter filters are updated.
+ */
+static void skfp_ctl_set_multicast_list(struct net_device *dev)
+{
+	skfddi_priv *bp = PRIV(dev);
+	unsigned long Flags;
+
+	spin_lock_irqsave(&bp->DriverLock, Flags);
+	skfp_ctl_set_multicast_list_wo_lock(dev);
+	spin_unlock_irqrestore(&bp->DriverLock, Flags);
+	return;
+}				// skfp_ctl_set_multicast_list
+
+
+
+static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	struct dev_mc_list *dmi;	/* ptr to multicast addr entry */
+	int i;
+
+	/* Enable promiscuous mode, if necessary */
+	if (dev->flags & IFF_PROMISC) {
+		mac_drv_rx_mode(smc, RX_ENABLE_PROMISC);
+		PRINTK(KERN_INFO "PROMISCUOUS MODE ENABLED\n");
+	}
+	/* Else, update multicast address table */
+	else {
+		mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
+		PRINTK(KERN_INFO "PROMISCUOUS MODE DISABLED\n");
+
+		// Reset all MC addresses
+		mac_clear_multicast(smc);
+		mac_drv_rx_mode(smc, RX_DISABLE_ALLMULTI);
+
+		if (dev->flags & IFF_ALLMULTI) {
+			mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
+			PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+		} else if (dev->mc_count > 0) {
+			if (dev->mc_count <= FPMAX_MULTICAST) {
+				/* use exact filtering */
+
+				// point to first multicast addr
+				dmi = dev->mc_list;
+
+				for (i = 0; i < dev->mc_count; i++) {
+					mac_add_multicast(smc,
+							  dmi->dmi_addr, 1);
+					PRINTK(KERN_INFO "ENABLE MC ADDRESS:");
+					PRINTK(" %02x %02x %02x ",
+					       dmi->dmi_addr[0],
+					       dmi->dmi_addr[1],
+					       dmi->dmi_addr[2]);
+					PRINTK("%02x %02x %02x\n",
+					       dmi->dmi_addr[3],
+					       dmi->dmi_addr[4],
+					       dmi->dmi_addr[5]);
+					dmi = dmi->next;
+				}	// for
+
+			} else {	// more MC addresses than HW supports
+
+				mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
+				PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+			}
+		} else {	// no MC addresses
+
+			PRINTK(KERN_INFO "DISABLE ALL MC ADDRESSES\n");
+		}
+
+		/* Update adapter filters */
+		mac_update_multicast(smc);
+	}
+	return;
+}				// skfp_ctl_set_multicast_list_wo_lock
+
+
+/*
+ * ===========================
+ * = skfp_ctl_set_mac_address =
+ * ===========================
+ *   
+ * Overview:
+ *   set new mac address on adapter and update dev_addr field in device table.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   dev  - pointer to device information
+ *   addr - pointer to sockaddr structure containing unicast address to set
+ *
+ * Assumptions:
+ *   The address pointed to by addr->sa_data is a valid unicast
+ *   address and is presented in canonical (LSB) format.
+ */
+static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+	unsigned long Flags;
+
+
+	memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN);
+	spin_lock_irqsave(&bp->DriverLock, Flags);
+	ResetAdapter(smc);
+	spin_unlock_irqrestore(&bp->DriverLock, Flags);
+
+	return (0);		/* always return zero */
+}				// skfp_ctl_set_mac_address
+
+
+/*
+ * ==============
+ * = skfp_ioctl =
+ * ==============
+ *   
+ * Overview:
+ *
+ * Perform IOCTL call functions here. Some are privileged operations and the
+ * effective uid is checked in those cases.
+ *  
+ * Returns:
+ *   status value
+ *   0 - success
+ *   other - failure
+ *       
+ * Arguments:
+ *   dev  - pointer to device information
+ *   rq - pointer to ioctl request structure
+ *   cmd - ?
+ *
+ */
+
+
+static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	skfddi_priv *lp = PRIV(dev);
+	struct s_skfp_ioctl ioc;
+	int status = 0;
+
+	copy_from_user(&ioc, rq->ifr_data, sizeof(struct s_skfp_ioctl));
+	switch (ioc.cmd) {
+	case SKFP_GET_STATS:	/* Get the driver statistics */
+		ioc.len = sizeof(lp->MacStat);
+		copy_to_user(ioc.data, skfp_ctl_get_stats(dev), ioc.len);
+		break;
+	case SKFP_CLR_STATS:	/* Zero out the driver statistics */
+		if (suser()) {
+			memset(&lp->MacStat, 0, sizeof(lp->MacStat));
+		} else {
+			status = -EPERM;
+		}
+		break;
+	default:
+		printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd);
+	}			// switch
+
+	return status;
+}				// skfp_ioctl
+
+
+/*
+ * =====================
+ * = skfp_send_pkt     =
+ * =====================
+ *   
+ * Overview:
+ *   Queues a packet for transmission and try to transmit it.
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   skb - pointer to sk_buff to queue for transmission
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Here we assume that an incoming skb transmit request
+ *   is contained in a single physically contiguous buffer
+ *   in which the virtual address of the start of packet
+ *   (skb->data) can be converted to a physical address
+ *   by using virt_to_bus().
+ *
+ *   We have an internal queue for packets we can not send 
+ *   immediately. Packets in this queue can be given to the 
+ *   adapter if transmit buffers are freed.
+ *
+ *   We can't free the skb until after it's been DMA'd
+ *   out by the adapter, so we'll keep it in the driver and
+ *   return it in mac_drv_tx_complete.
+ *
+ * Return Codes:
+ *   0 - driver has queued and/or sent packet
+ *       1 - caller should requeue the sk_buff for later transmission
+ *
+ * Assumptions:
+ *   The entire packet is stored in one physically
+ *   contiguous buffer which is not cached and whose
+ *   32-bit physical address can be determined.
+ *
+ *   It's vital that this routine is NOT reentered for the
+ *   same board and that the OS is not in another section of
+ *   code (eg. skfp_interrupt) for the same board on a
+ *   different thread.
+ *
+ * Side Effects:
+ *   None
+ */
+static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+	skfddi_priv *bp = PRIV(dev);
+
+	PRINTK(KERN_INFO "skfp_send_pkt\n");
+
+	/*
+	 * Verify that incoming transmit request is OK
+	 *
+	 * Note: The packet size check is consistent with other
+	 *               Linux device drivers, although the correct packet
+	 *               size should be verified before calling the
+	 *               transmit routine.
+	 */
+
+	if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) {
+		bp->MacStat.tx_errors++;	/* bump error counter */
+		// dequeue packets from xmt queue and send them
+		netif_start_queue(dev);
+		dev_kfree_skb(skb);
+		return (0);	/* return "success" */
+	}
+	if (bp->QueueSkb == 0) {	// return with tbusy set: queue full
+
+		netif_stop_queue(dev);
+		return 1;
+	}
+	bp->QueueSkb--;
+	skb_queue_tail(&bp->SendSkbQueue, skb);
+	send_queued_packets((struct s_smc *) dev->priv);
+	if (bp->QueueSkb == 0) {
+		netif_stop_queue(dev);
+	}
+	dev->trans_start = jiffies;
+	return 0;
+
+}				// skfp_send_pkt
+
+
+/*
+ * =======================
+ * = send_queued_packets =
+ * =======================
+ *   
+ * Overview:
+ *   Send packets from the driver queue as long as there are some and
+ *   transmit resources are available.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   smc - pointer to smc (adapter) structure
+ *
+ * Functional Description:
+ *   Take a packet from queue if there is any. If not, then we are done.
+ *   Check if there are resources to send the packet. If not, requeue it
+ *   and exit. 
+ *   Set packet descriptor flags and give packet to adapter.
+ *   Check if any send resources can be freed (we do not use the
+ *   transmit complete interrupt).
+ */
+static void send_queued_packets(struct s_smc *smc)
+{
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+	struct sk_buff *skb;
+	unsigned char fc;
+	int queue;
+	struct s_smt_fp_txd *txd;	// Current TxD.
+	unsigned long Flags;
+
+	int frame_status;	// HWM tx frame status.
+
+	PRINTK(KERN_INFO "send queued packets\n");
+	for (;;) {
+		// send first buffer from queue
+		skb = skb_dequeue(&bp->SendSkbQueue);
+
+		if (!skb) {
+			PRINTK(KERN_INFO "queue empty\n");
+			return;
+		}		// queue empty !
+
+		spin_lock_irqsave(&bp->DriverLock, Flags);
+		fc = skb->data[0];
+		queue = (fc & FC_SYNC_BIT) ? QUEUE_S : QUEUE_A0;
+#ifdef ESS
+		// Check if the frame may/must be sent as a synchronous frame.
+
+		if ((fc & ~(FC_SYNC_BIT | FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
+			// It's an LLC frame.
+			if (!smc->ess.sync_bw_available)
+				fc &= ~FC_SYNC_BIT; // No bandwidth available.
+
+			else {	// Bandwidth is available.
+
+				if (smc->mib.fddiESSSynchTxMode) {
+					// Send as sync. frame.
+					fc |= FC_SYNC_BIT;
+				}
+			}
+		}
+#endif				// ESS
+		frame_status = hwm_tx_init(smc, fc, 1, skb->len, queue);
+
+		if ((frame_status & (LOC_TX | LAN_TX)) == 0) {
+			// Unable to send the frame.
+
+			if ((frame_status & RING_DOWN) != 0) {
+				// Ring is down.
+				PRINTK("Tx attempt while ring down.\n");
+			} else if ((frame_status & OUT_OF_TXD) != 0) {
+				PRINTK("%s: out of TXDs.\n", bp->dev->name);
+			} else {
+				PRINTK("%s: out of transmit resources",
+					bp->dev->name);
+			}
+
+			// Note: We will retry the operation as soon as
+			// transmit resources become available.
+			skb_queue_head(&bp->SendSkbQueue, skb);
+			spin_unlock_irqrestore(&bp->DriverLock, Flags);
+			return;	// Packet has been queued.
+
+		}		// if (unable to send frame)
+
+		bp->QueueSkb++;	// one packet less in local queue
+
+		// source address in packet ?
+		CheckSourceAddress(skb->data, smc->hw.fddi_canon_addr.a);
+
+		txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue);
+
+		if (frame_status & LAN_TX) {
+			txd->txd_os.skb = skb;	// save skb
+		}
+		hwm_tx_frag(smc, skb->data, virt_to_bus(skb->data), skb->len,
+                      frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF);
+
+		if (!(frame_status & LAN_TX)) {		// local only frame
+			dev_kfree_skb_irq(skb);
+		}
+		spin_unlock_irqrestore(&bp->DriverLock, Flags);
+	}			// for
+
+	return;			// never reached
+
+}				// send_queued_packets
+
+
+/************************
+ * 
+ * CheckSourceAddress
+ *
+ * Verify if the source address is set. Insert it if necessary.
+ *
+ ************************/
+void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr)
+{
+	unsigned char SRBit;
+
+	if ((((unsigned long) frame[1 + 6]) & ~0x01) != 0) // source routing bit
+
+		return;
+	if ((unsigned short) frame[1 + 10] != 0)
+		return;
+	SRBit = frame[1 + 6] & 0x01;
+	memcpy(&frame[1 + 6], hw_addr, 6);
+	frame[8] |= SRBit;
+}				// CheckSourceAddress
+
+
+/************************
+ *
+ *	ResetAdapter
+ *
+ *	Reset the adapter and bring it back to operational mode.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+static void ResetAdapter(struct s_smc *smc)
+{
+
+	PRINTK(KERN_INFO "[fddi: ResetAdapter]\n");
+
+	// Stop the adapter.
+
+	card_stop(smc);		// Stop all activity.
+
+	// Clear the transmit and receive descriptor queues.
+	mac_drv_clear_tx_queue(smc);
+	mac_drv_clear_rx_queue(smc);
+
+	// Restart the adapter.
+
+	smt_reset_defaults(smc, 1);	// Initialize the SMT module.
+
+	init_smt(smc, (smc->os.dev)->dev_addr);	// Initialize the hardware.
+
+	smt_online(smc, 1);	// Insert into the ring again.
+	STI_FBI();
+
+	// Restore original receive mode (multicasts, promiscuous, etc.).
+	skfp_ctl_set_multicast_list_wo_lock(smc->os.dev);
+}				// ResetAdapter
+
+
+//--------------- functions called by hardware module ----------------
+
+/************************
+ *
+ *	llc_restart_tx
+ *
+ *	The hardware driver calls this routine when the transmit complete
+ *	interrupt bits (end of frame) for the synchronous or asynchronous
+ *	queue is set.
+ *
+ * NOTE The hardware driver calls this function also if no packets are queued.
+ *	The routine must be able to handle this case.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void llc_restart_tx(struct s_smc *smc)
+{
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+
+	PRINTK(KERN_INFO "[llc_restart_tx]\n");
+
+	// Try to send queued packets
+	spin_unlock(&bp->DriverLock);
+	send_queued_packets(smc);
+	spin_lock(&bp->DriverLock);
+	netif_start_queue(bp->dev);// system may send again if it was blocked
+
+}				// llc_restart_tx
+
+
+/************************
+ *
+ *	mac_drv_get_space
+ *
+ *	The hardware module calls this function to allocate the memory
+ *	for the SMT MBufs if the define MB_OUTSIDE_SMC is specified.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	size - Size of memory in bytes to allocate.
+ * Out
+ *	!= 0	A pointer to the virtual address of the allocated memory.
+ *	== 0	Allocation error.
+ *
+ ************************/
+void *mac_drv_get_space(struct s_smc *smc, unsigned int size)
+{
+	void *virt;
+
+	PRINTK(KERN_INFO "mac_drv_get_space\n");
+	virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap);
+
+	if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) {
+		printk("Unexpected SMT memory size requested: %d\n", size);
+		return (NULL);
+	}
+	smc->os.SharedMemHeap += size;	// Move heap pointer.
+
+	PRINTK(KERN_INFO "mac_drv_get_space end\n");
+	PRINTK(KERN_INFO "virt addr: %08lx\n", (ulong) virt);
+	PRINTK(KERN_INFO "bus  addr: %08lx\n", (ulong) virt_to_bus(virt));
+	return (virt);
+}				// mac_drv_get_space
+
+
+/************************
+ *
+ *	mac_drv_get_desc_mem
+ *
+ *	This function is called by the hardware dependent module.
+ *	It allocates the memory for the RxD and TxD descriptors.
+ *
+ *	This memory must be non-cached, non-movable and non-swapable.
+ *	This memory should start at a physical page boundary.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	size - Size of memory in bytes to allocate.
+ * Out
+ *	!= 0	A pointer to the virtual address of the allocated memory.
+ *	== 0	Allocation error.
+ *
+ ************************/
+void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size)
+{
+
+	char *virt;
+
+	PRINTK(KERN_INFO "mac_drv_get_desc_mem\n");
+
+	// Descriptor memory must be aligned on 16-byte boundary.
+
+	virt = mac_drv_get_space(smc, size);
+
+	size = (u_int) ((0 - (unsigned int) virt) & 15);
+
+	PRINTK("Allocate %u bytes alignment gap ", size);
+	PRINTK("for descriptor memory.\n");
+
+	if (!mac_drv_get_space(smc, size)) {
+		printk("fddi: Unable to align descriptor memory.\n");
+		return (NULL);
+	}
+	return (virt + size);
+}				// mac_drv_get_desc_mem
+
+
+/************************
+ *
+ *	mac_drv_virt2phys
+ *
+ *	Get the physical address of a given virtual address.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	virt - A (virtual) pointer into our 'shared' memory area.
+ * Out
+ *	Physical address of the given virtual address.
+ *
+ ************************/
+unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt)
+{
+	return virt_to_bus(virt);
+}				// mac_drv_virt2phys
+
+
+/************************
+ *
+ *	dma_master
+ *
+ *	The HWM calls this function, when the driver leads through a DMA
+ *	transfer. If the OS-specific module must prepare the system hardware
+ *	for the DMA transfer, it should do it in this function.
+ *
+ *	The hardware module calls this dma_master if it wants to send an SMT
+ *	frame.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	virt - The virtual address of the data.
+ *
+ *	len - The length in bytes of the data.
+ *
+ *	flag - Indicates the transmit direction and the buffer type:
+ *		DMA_RD	(0x01)	system RAM ==> adapter buffer memory
+ *		DMA_WR	(0x02)	adapter buffer memory ==> system RAM
+ *		SMT_BUF (0x80)	SMT buffer
+ *
+ *	>> NOTE: SMT_BUF and DMA_RD are always set for PCI. <<
+ * Out
+ *	Returns the pyhsical address for the DMA transfer.
+ *
+ ************************/
+u_long dma_master(struct s_smc * smc, void *virt, int len, int flag)
+{
+	return (virt_to_bus(virt));
+}				// dma_master
+
+
+/************************
+ *
+ *	dma_complete
+ *
+ *	The hardware module calls this routine when it has completed a DMA
+ *	transfer. If the operating system dependant module has set up the DMA
+ *	channel via dma_master() (e.g. Windows NT or AIX) it should clean up
+ *	the DMA channel.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	descr - A pointer to a TxD or RxD, respectively.
+ *
+ *	flag - Indicates the DMA transfer direction / SMT buffer:
+ *		DMA_RD	(0x01)	system RAM ==> adapter buffer memory
+ *		DMA_WR	(0x02)	adapter buffer memory ==> system RAM
+ *		SMT_BUF (0x80)	SMT buffer (managed by HWM)
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag)
+{
+	return;
+}				// dma_complete
+
+
+/************************
+ *
+ *	mac_drv_tx_complete
+ *
+ *	Transmit of a packet is complete. Release the tx staging buffer.
+ *
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	txd - A pointer to the last TxD which is used by the frame.
+ * Out
+ *	Returns nothing.
+ *
+ ************************/
+void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd)
+{
+	struct sk_buff *skb;
+
+	PRINTK(KERN_INFO "entering mac_drv_tx_complete\n");
+	// Check if this TxD points to a skb
+
+	if (!(skb = txd->txd_os.skb)) {
+		PRINTK("TXD with no skb assigned.\n");
+		return;
+	}
+	txd->txd_os.skb = NULL;
+
+	smc->os.MacStat.tx_packets++;	// Count transmitted packets.
+	smc->os.MacStat.tx_bytes+=skb->len;	// Count bytes
+
+	// free the skb
+	dev_kfree_skb_irq(skb);
+
+	PRINTK(KERN_INFO "leaving mac_drv_tx_complete\n");
+}				// mac_drv_tx_complete
+
+
+/************************
+ *
+ * dump packets to logfile
+ *
+ ************************/
+#ifdef DUMPPACKETS
+void dump_data(unsigned char *Data, int length)
+{
+	int i, j;
+	unsigned char s[255], sh[10];
+	if (length > 64) {
+		length = 64;
+	}
+	printk(KERN_INFO "---Packet start---\n");
+	for (i = 0, j = 0; i < length / 8; i++, j += 8)
+		printk(KERN_INFO "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+		       Data[j + 0], Data[j + 1], Data[j + 2], Data[j + 3],
+		       Data[j + 4], Data[j + 5], Data[j + 6], Data[j + 7]);
+	strcpy(s, "");
+	for (i = 0; i < length % 8; i++) {
+		sprintf(sh, "%02x ", Data[j + i]);
+		strcat(s, sh);
+	}
+	printk(KERN_INFO "%s\n", s);
+	printk(KERN_INFO "------------------\n");
+}				// dump_data
+#else
+#define dump_data(data,len)
+#endif				// DUMPPACKETS
+
+/************************
+ *
+ *	mac_drv_rx_complete
+ *
+ *	The hardware module calls this function if an LLC frame is received
+ *	in a receive buffer. Also the SMT, NSA, and directed beacon frames
+ *	from the network will be passed to the LLC layer by this function
+ *	if passing is enabled.
+ *
+ *	mac_drv_rx_complete forwards the frame to the LLC layer if it should
+ *	be received. It also fills the RxD ring with new receive buffers if
+ *	some can be queued.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	rxd - A pointer to the first RxD which is used by the receive frame.
+ *
+ *	frag_count - Count of RxDs used by the received frame.
+ *
+ *	len - Frame length.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count, int len)
+{
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+	struct sk_buff *skb;
+	unsigned char *virt, *cp;
+	unsigned short ri;
+	u_int RifLength;
+
+	PRINTK(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len);
+	if (frag_count != 1) {	// This is not allowed to happen.
+
+		printk("fddi: Multi-fragment receive!\n");
+		goto RequeueRxd;	// Re-use the given RXD(s).
+
+	}
+	skb = rxd->rxd_os.skb;
+	if (!skb) {
+		PRINTK(KERN_INFO "No skb in rxd\n");
+		smc->os.MacStat.rx_errors++;
+		goto RequeueRxd;
+	}
+	virt = skb->data;
+
+	dump_data(skb->data, len);
+
+	/*
+	 * FDDI Frame format:
+	 * +-------+-------+-------+------------+--------+------------+
+	 * | FC[1] | DA[6] | SA[6] | RIF[0..18] | LLC[3] | Data[0..n] |
+	 * +-------+-------+-------+------------+--------+------------+
+	 *
+	 * FC = Frame Control
+	 * DA = Destination Address
+	 * SA = Source Address
+	 * RIF = Routing Information Field
+	 * LLC = Logical Link Control
+	 */
+
+	// Remove Routing Information Field (RIF), if present.
+
+	if ((virt[1 + 6] & FDDI_RII) == 0)
+		RifLength = 0;
+	else {
+		int n;
+// goos: RIF removal has still to be tested
+		PRINTK(KERN_INFO "RIF found\n");
+		// Get RIF length from Routing Control (RC) field.
+		cp = virt + FDDI_MAC_HDR_LEN;	// Point behind MAC header.
+
+		ri = ntohs(*((unsigned short *) cp));
+		RifLength = ri & FDDI_RCF_LEN_MASK;
+		if (len < (int) (FDDI_MAC_HDR_LEN + RifLength)) {
+			printk("fddi: Invalid RIF.\n");
+			goto RequeueRxd;	// Discard the frame.
+
+		}
+		virt[1 + 6] &= ~FDDI_RII;	// Clear RII bit.
+		// regions overlap
+
+		virt = cp + RifLength;
+		for (n = FDDI_MAC_HDR_LEN; n; n--)
+			*--virt = *--cp;
+		// adjust sbd->data pointer
+		skb_pull(skb, RifLength);
+		len -= RifLength;
+		RifLength = 0;
+	}
+
+	// Count statistics.
+	smc->os.MacStat.rx_packets++;	// Count indicated receive packets.
+	smc->os.MacStat.rx_bytes+=len;	// Count bytes
+
+	// virt points to header again
+	if (virt[1] & 0x01) {	// Check group (multicast) bit.
+
+		smc->os.MacStat.multicast++;
+	}
+
+	// deliver frame to system
+	rxd->rxd_os.skb = NULL;
+	skb_trim(skb, len);
+	skb->protocol = fddi_type_trans(skb, bp->dev);
+	skb->dev = bp->dev;	/* pass up device pointer */
+
+	netif_rx(skb);
+
+	HWM_RX_CHECK(smc, RX_LOW_WATERMARK);
+	return;
+
+      RequeueRxd:
+	PRINTK(KERN_INFO "Rx: re-queue RXD.\n");
+	mac_drv_requeue_rxd(smc, rxd, frag_count);
+	smc->os.MacStat.rx_errors++;	// Count receive packets not indicated.
+
+}				// mac_drv_rx_complete
+
+
+/************************
+ *
+ *	mac_drv_requeue_rxd
+ *
+ *	The hardware module calls this function to request the OS-specific
+ *	module to queue the receive buffer(s) represented by the pointer
+ *	to the RxD and the frag_count into the receive queue again. This
+ *	buffer was filled with an invalid frame or an SMT frame.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	rxd - A pointer to the first RxD which is used by the receive frame.
+ *
+ *	frag_count - Count of RxDs used by the received frame.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count)
+{
+	volatile struct s_smt_fp_rxd *next_rxd;
+	volatile struct s_smt_fp_rxd *src_rxd;
+	struct sk_buff *skb;
+	int MaxFrameSize;
+	unsigned char *v_addr;
+	unsigned long b_addr;
+
+	if (frag_count != 1)	// This is not allowed to happen.
+
+		printk("fddi: Multi-fragment requeue!\n");
+
+	MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize;
+	src_rxd = rxd;
+	for (; frag_count > 0; frag_count--) {
+		next_rxd = src_rxd->rxd_next;
+		rxd = HWM_GET_CURR_RXD(smc);
+
+		skb = src_rxd->rxd_os.skb;
+		if (skb == NULL) {	// this should not happen
+
+			PRINTK("Requeue with no skb in rxd!\n");
+			skb = alloc_skb(MaxFrameSize, GFP_ATOMIC);
+			if (skb) {
+				// we got a skb
+				rxd->rxd_os.skb = skb;
+				skb_put(skb, MaxFrameSize);
+				v_addr = skb->data;
+				b_addr = virt_to_bus(v_addr);
+			} else {
+				// no skb available, use local buffer
+				PRINTK("Queueing invalid buffer!\n");
+				rxd->rxd_os.skb = NULL;
+				v_addr = smc->os.LocalRxBuffer;
+				b_addr = virt_to_bus(v_addr);
+			}
+		} else {
+			// we use skb from old rxd
+			rxd->rxd_os.skb = skb;
+			v_addr = skb->data;
+			b_addr = virt_to_bus(v_addr);
+		}
+		hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
+			    FIRST_FRAG | LAST_FRAG);
+
+		src_rxd = next_rxd;
+	}
+}				// mac_drv_requeue_rxd
+
+
+/************************
+ *
+ *	mac_drv_fill_rxd
+ *
+ *	The hardware module calls this function at initialization time
+ *	to fill the RxD ring with receive buffers. It is also called by
+ *	mac_drv_rx_complete if rx_free is large enough to queue some new
+ *	receive buffers into the RxD ring. mac_drv_fill_rxd queues new
+ *	receive buffers as long as enough RxDs and receive buffers are
+ *	available.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_fill_rxd(struct s_smc *smc)
+{
+	int MaxFrameSize;
+	unsigned char *v_addr;
+	unsigned long b_addr;
+	struct sk_buff *skb;
+	volatile struct s_smt_fp_rxd *rxd;
+
+	PRINTK(KERN_INFO "entering mac_drv_fill_rxd\n");
+
+	// Walk through the list of free receive buffers, passing receive
+	// buffers to the HWM as long as RXDs are available.
+
+	MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize;
+	// Check if there is any RXD left.
+	while (HWM_GET_RX_FREE(smc) > 0) {
+		PRINTK(KERN_INFO ".\n");
+
+		rxd = HWM_GET_CURR_RXD(smc);
+		skb = alloc_skb(MaxFrameSize, GFP_ATOMIC);
+		if (skb) {
+			// we got a skb
+			skb_put(skb, MaxFrameSize);
+			v_addr = skb->data;
+			b_addr = virt_to_bus(v_addr);
+		} else {
+			// no skb available, use local buffer
+			// System has run out of buffer memory, but we want to
+			// keep the receiver running in hope of better times.
+			// Multiple descriptors may point to this local buffer,
+			// so data in it must be considered invalid.
+			PRINTK("Queueing invalid buffer!\n");
+			v_addr = smc->os.LocalRxBuffer;
+			b_addr = virt_to_bus(v_addr);
+		}
+
+		rxd->rxd_os.skb = skb;
+
+		// Pass receive buffer to HWM.
+		hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
+			    FIRST_FRAG | LAST_FRAG);
+	}
+	PRINTK(KERN_INFO "leaving mac_drv_fill_rxd\n");
+}				// mac_drv_fill_rxd
+
+
+/************************
+ *
+ *	mac_drv_clear_rxd
+ *
+ *	The hardware module calls this function to release unused
+ *	receive buffers.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	rxd - A pointer to the first RxD which is used by the receive buffer.
+ *
+ *	frag_count - Count of RxDs used by the receive buffer.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+		       int frag_count)
+{
+
+	struct sk_buff *skb;
+
+	PRINTK("entering mac_drv_clear_rxd\n");
+
+	if (frag_count != 1)	// This is not allowed to happen.
+
+		printk("fddi: Multi-fragment clear!\n");
+
+	for (; frag_count > 0; frag_count--) {
+		skb = rxd->rxd_os.skb;
+		if (skb != NULL) {
+			dev_kfree_skb(skb);
+			rxd->rxd_os.skb = NULL;
+		}
+		rxd = rxd->rxd_next;	// Next RXD.
+
+	}
+}				// mac_drv_clear_rxd
+
+
+/************************
+ *
+ *	mac_drv_rx_init
+ *
+ *	The hardware module calls this routine when an SMT or NSA frame of the
+ *	local SMT should be delivered to the LLC layer.
+ *
+ *	It is necessary to have this function, because there is no other way to
+ *	copy the contents of SMT MBufs into receive buffers.
+ *
+ *	mac_drv_rx_init allocates the required target memory for this frame,
+ *	and receives the frame fragment by fragment by calling mac_drv_rx_frag.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	len - The length (in bytes) of the received frame (FC, DA, SA, Data).
+ *
+ *	fc - The Frame Control field of the received frame.
+ *
+ *	look_ahead - A pointer to the lookahead data buffer (may be NULL).
+ *
+ *	la_len - The length of the lookahead data stored in the lookahead
+ *	buffer (may be zero).
+ * Out
+ *	Always returns zero (0).
+ *
+ ************************/
+int mac_drv_rx_init(struct s_smc *smc, int len, int fc,
+		    char *look_ahead, int la_len)
+{
+	struct sk_buff *skb;
+
+	PRINTK("entering mac_drv_rx_init(len=%d)\n", len);
+
+	// "Received" a SMT or NSA frame of the local SMT.
+
+	if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) {
+		PRINTK("fddi: Discard invalid local SMT frame\n");
+		PRINTK("  len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n",
+		       len, la_len, (unsigned long) look_ahead);
+		return (0);
+	}
+	skb = alloc_skb(len, GFP_ATOMIC);
+	if (!skb) {
+		PRINTK("fddi: Local SMT: skb memory exhausted.\n");
+		return (0);
+	}
+	skb_put(skb, len);
+	memcpy(skb->data, look_ahead, len);
+
+	// deliver frame to system
+	skb->protocol = fddi_type_trans(skb, ((skfddi_priv *) & smc->os)->dev);
+	netif_rx(skb);
+
+	return (0);
+}				// mac_drv_rx_init
+
+
+/************************
+ *
+ *	smt_timer_poll
+ *
+ *	This routine is called periodically by the SMT module to clean up the
+ *	driver.
+ *
+ *	Return any queued frames back to the upper protocol layers if the ring
+ *	is down.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void smt_timer_poll(struct s_smc *smc)
+{
+}				// smt_timer_poll
+
+
+/************************
+ *
+ *	ring_status_indication
+ *
+ *	This function indicates a change of the ring state.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	status - The current ring status.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void ring_status_indication(struct s_smc *smc, u_long status)
+{
+	PRINTK("ring_status_indication(%08lXh)\n", (unsigned long) status);
+}				// ring_status_indication
+
+
+/************************
+ *
+ *	smt_get_time
+ *
+ *	Gets the current time from the system.
+ * Args
+ *	None.
+ * Out
+ *	The current time in TICKS_PER_SECOND.
+ *
+ *	TICKS_PER_SECOND has the unit 'count of timer ticks per second'. It is
+ *	defined in "targetos.h". The definition of TICKS_PER_SECOND must comply
+ *	to the time returned by smt_get_time().
+ *
+ ************************/
+unsigned long smt_get_time(void)
+{
+	return jiffies;
+}				// smt_get_time
+
+
+/************************
+ *
+ *	smt_stat_counter
+ *
+ *	Status counter update (ring_op, fifo full).
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	stat -	= 0: A ring operational change occurred.
+ *		= 1: The FORMAC FIFO buffer is full / FIFO overflow.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void smt_stat_counter(struct s_smc *smc, int stat)
+{
+//      BOOLEAN RingIsUp ;
+
+	PRINTK(KERN_INFO "smt_stat_counter\n");
+	switch (stat) {
+	case 0:
+		PRINTK(KERN_INFO "Ring operational change.\n");
+		break;
+	case 1:
+		PRINTK(KERN_INFO "Receive fifo overflow.\n");
+		smc->os.MacStat.rx_errors++;
+		break;
+	default:
+		PRINTK(KERN_INFO "Unknown status (%d).\n", stat);
+		break;
+	}
+}				// smt_stat_counter
+
+
+/************************
+ *
+ *	cfm_state_change
+ *
+ *	Sets CFM state in custom statistics.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	c_state - Possible values are:
+ *
+ *		EC0_OUT, EC1_IN, EC2_TRACE, EC3_LEAVE, EC4_PATH_TEST,
+ *		EC5_INSERT, EC6_CHECK, EC7_DEINSERT
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void cfm_state_change(struct s_smc *smc, int c_state)
+{
+#ifdef DRIVERDEBUG
+	char *s;
+
+	switch (c_state) {
+	case SC0_ISOLATED:
+		s = "SC0_ISOLATED";
+		break;
+	case SC1_WRAP_A:
+		s = "SC1_WRAP_A";
+		break;
+	case SC2_WRAP_B:
+		s = "SC2_WRAP_B";
+		break;
+	case SC4_THRU_A:
+		s = "SC4_THRU_A";
+		break;
+	case SC5_THRU_B:
+		s = "SC5_THRU_B";
+		break;
+	case SC7_WRAP_S:
+		s = "SC7_WRAP_S";
+		break;
+	default:
+		s = "unknown";
+		break;
+	}
+	PRINTK(KERN_INFO "cfm_state_change: %s\n", s);
+#endif				// DRIVERDEBUG
+}				// cfm_state_change
+
+
+/************************
+ *
+ *	ecm_state_change
+ *
+ *	Sets ECM state in custom statistics.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	e_state - Possible values are:
+ *
+ *		SC0_ISOLATED, SC1_WRAP_A (5), SC2_WRAP_B (6), SC4_THRU_A (12),
+ *		SC5_THRU_B (7), SC7_WRAP_S (8)
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void ecm_state_change(struct s_smc *smc, int e_state)
+{
+#ifdef DRIVERDEBUG
+	char *s;
+
+	switch (e_state) {
+	case EC0_OUT:
+		s = "EC0_OUT";
+		break;
+	case EC1_IN:
+		s = "EC1_IN";
+		break;
+	case EC2_TRACE:
+		s = "EC2_TRACE";
+		break;
+	case EC3_LEAVE:
+		s = "EC3_LEAVE";
+		break;
+	case EC4_PATH_TEST:
+		s = "EC4_PATH_TEST";
+		break;
+	case EC5_INSERT:
+		s = "EC5_INSERT";
+		break;
+	case EC6_CHECK:
+		s = "EC6_CHECK";
+		break;
+	case EC7_DEINSERT:
+		s = "EC7_DEINSERT";
+		break;
+	default:
+		s = "unknown";
+		break;
+	}
+	PRINTK(KERN_INFO "ecm_state_change: %s\n", s);
+#endif				//DRIVERDEBUG
+}				// ecm_state_change
+
+
+/************************
+ *
+ *	rmt_state_change
+ *
+ *	Sets RMT state in custom statistics.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	r_state - Possible values are:
+ *
+ *		RM0_ISOLATED, RM1_NON_OP, RM2_RING_OP, RM3_DETECT,
+ *		RM4_NON_OP_DUP, RM5_RING_OP_DUP, RM6_DIRECTED, RM7_TRACE
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void rmt_state_change(struct s_smc *smc, int r_state)
+{
+#ifdef DRIVERDEBUG
+	char *s;
+
+	switch (r_state) {
+	case RM0_ISOLATED:
+		s = "RM0_ISOLATED";
+		break;
+	case RM1_NON_OP:
+		s = "RM1_NON_OP - not operational";
+		break;
+	case RM2_RING_OP:
+		s = "RM2_RING_OP - ring operational";
+		break;
+	case RM3_DETECT:
+		s = "RM3_DETECT - detect dupl addresses";
+		break;
+	case RM4_NON_OP_DUP:
+		s = "RM4_NON_OP_DUP - dupl. addr detected";
+		break;
+	case RM5_RING_OP_DUP:
+		s = "RM5_RING_OP_DUP - ring oper. with dupl. addr";
+		break;
+	case RM6_DIRECTED:
+		s = "RM6_DIRECTED - sending directed beacons";
+		break;
+	case RM7_TRACE:
+		s = "RM7_TRACE - trace initiated";
+		break;
+	default:
+		s = "unknown";
+		break;
+	}
+	PRINTK(KERN_INFO "[rmt_state_change: %s]\n", s);
+#endif				// DRIVERDEBUG
+}				// rmt_state_change
+
+
+/************************
+ *
+ *	drv_reset_indication
+ *
+ *	This function is called by the SMT when it has detected a severe
+ *	hardware problem. The driver should perform a reset on the adapter
+ *	as soon as possible, but not from within this function.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void drv_reset_indication(struct s_smc *smc)
+{
+	PRINTK(KERN_INFO "entering drv_reset_indication\n");
+
+	smc->os.ResetRequested = TRUE;	// Set flag.
+
+}				// drv_reset_indication
+
+
+
+//--------------- functions for use as a module ----------------
+
+#ifdef MODULE
+/************************
+ *
+ * Note now that module autoprobing is allowed under PCI. The
+ * IRQ lines will not be auto-detected; instead I'll rely on the BIOSes
+ * to "do the right thing".
+ *
+ ************************/
+#define LP(a) ((struct s_smc*)(a))
+static struct net_device *mdev = NULL;
+
+/************************
+ *
+ * init_module
+ *
+ *  If compiled as a module, find
+ *  adapters and initialize them.
+ *
+ ************************/
+int init_module(void)
+{
+	struct net_device *p;
+
+	PRINTK(KERN_INFO "FDDI init module\n");
+	if ((mdev = insert_device(NULL, skfp_probe)) == NULL)
+		return -ENOMEM;
+
+	for (p = mdev; p != NULL; p = LP(p->priv)->os.next_module) {
+		PRINTK(KERN_INFO "device to register: %s\n", p->name);
+		if (register_netdev(p) != 0) {
+			printk("skfddi init_module failed\n");
+			return -EIO;
+		}
+	}
+
+	PRINTK(KERN_INFO "+++++ exit with success +++++\n");
+	return 0;
+}				// init_module
+
+/************************
+ *
+ * cleanup_module
+ *
+ *  Release all resources claimed by this module.
+ *
+ ************************/
+void cleanup_module(void)
+{
+	PRINTK(KERN_INFO "cleanup_module\n");
+	while (mdev != NULL) {
+		mdev = unlink_modules(mdev);
+	}
+	return;
+}				// cleanup_module
+
+
+/************************
+ *
+ * unlink_modules
+ *
+ *  Unregister devices and release their memory.
+ *
+ ************************/
+static struct net_device *unlink_modules(struct net_device *p)
+{
+	struct net_device *next = NULL;
+
+	if (p->priv) {		/* Private areas allocated? */
+		struct s_smc *lp = (struct s_smc *) p->priv;
+
+		next = lp->os.next_module;
+
+		if (lp->os.SharedMemAddr) {
+			kfree(lp->os.SharedMemAddr);
+		}
+		release_region(p->base_addr, 
+			(lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0));
+	}
+	unregister_netdev(p);
+	printk("%s: unloaded\n", p->name);
+	kfree(p);		/* Free the device structure */
+
+	return next;
+}				// unlink_modules
+
+
+#endif				/* MODULE */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smt.c linux/drivers/net/skfp/smt.c
--- v2.3.46/linux/drivers/net/skfp/smt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/smt.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,2225 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smt.c	2.43 98/11/23 (C) SK " ;
+#endif
+
+extern const u_char canonical[256] ;
+
+/*
+ * FC in SMbuf
+ */
+#define m_fc(mb)	((mb)->sm_data[0])
+
+#define SMT_TID_MAGIC	0x1f0a7b3c
+
+#ifdef	DEBUG
+static const char *const smt_type_name[] = {
+	"SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??",
+	"SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??",
+	"SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??",
+	"SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA"
+} ;
+
+static const char *const smt_class_name[] = {
+	"UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF",
+	"SRF","PMF_GET","PMF_SET","ESF"
+} ;
+#endif
+#define LAST_CLASS	(SMT_PMF_SET)
+
+static const struct fddi_addr SMT_Unknown = {
+	0,0,0x1f,0,0,0
+} ;
+
+/*
+ * external variables
+ */
+extern const struct fddi_addr fddi_broadcast ;
+
+/*
+ * external functions
+ */
+int pcm_status_twisted() ;
+void pcm_status_state() ;
+int pcm_status_type() ;
+
+extern SMbuf *smt_get_mbuf() ;
+
+#define EXPORT_PMF
+/*
+ * function prototypes
+ */
+u_long smt_get_tid() ;
+EXPORT_PMF SMbuf *smt_build_frame() ;
+EXPORT_PMF void *sm_to_para() ;
+#ifdef	LITTLE_ENDIAN
+static int smt_swap_short() ;
+#endif
+static int mac_index() ;
+static int phy_index() ;
+static int mac_con_resource_index() ;
+static int phy_con_resource_index() ;
+EXPORT_PMF void smt_send_frame() ;
+EXPORT_PMF void smt_set_timestamp() ;
+static void smt_send_rdf() ;
+static void smt_send_nif() ;
+static void smt_send_ecf() ;
+static void smt_echo_test() ;
+static void smt_send_sif_config() ;
+static void smt_send_sif_operation() ;
+EXPORT_PMF void smt_swap_para() ;
+#ifdef LITTLE_ENDIAN
+static void smt_string_swap() ;
+#endif
+static void smt_add_frame_len() ;
+static void smt_fill_una() ;
+static void smt_fill_sde() ;
+static void smt_fill_state() ;
+static void smt_fill_timestamp() ;
+static void smt_fill_policy() ;
+static void smt_fill_latency() ;
+static void smt_fill_neighbor() ;
+static int  smt_fill_path() ;
+static void smt_fill_mac_status() ;
+static void smt_fill_lem() ;
+static void smt_fill_version() ;
+static void smt_fill_fsc() ;
+static void smt_fill_mac_counter() ;
+static void smt_fill_mac_fnc() ;
+static void smt_fill_manufacturer() ;
+static void smt_fill_user() ;
+static void smt_fill_setcount() ;
+static void smt_fill_echo() ;
+int smt_check_para() ;
+
+void smt_clear_una_dna() ;
+static void smt_clear_old_una_dna() ;
+#ifdef	CONCENTRATOR
+static int entity_to_index() ;
+#endif
+static void update_dac() ;
+static int div_ratio() ;
+#ifdef  USE_CAN_ADDR
+void	hwm_conv_can() ;
+#else
+#define		hwm_conv_can(smc,data,len)
+#endif
+
+/*
+ * list of mandatory paras in frames
+ */
+static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ;
+
+/*
+ * init SMT agent
+ */
+void smt_agent_init(smc)
+struct s_smc *smc ;
+{
+	int		i ;
+
+	/*
+	 * get MAC address
+	 */
+	smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ;
+
+	/*
+	 * get OUI address from driver (bia == built-in-address)
+	 */
+	smc->mib.fddiSMTStationId.sid_oem[0] = 0 ;
+	smc->mib.fddiSMTStationId.sid_oem[1] = 0 ;
+	driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
+	for (i = 0 ; i < 6 ; i ++) {
+		smc->mib.fddiSMTStationId.sid_node.a[i] =
+			canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+	}
+	smc->mib.fddiSMTManufacturerData[0] =
+		smc->mib.fddiSMTStationId.sid_node.a[0] ;
+	smc->mib.fddiSMTManufacturerData[1] =
+		smc->mib.fddiSMTStationId.sid_node.a[1] ;
+	smc->mib.fddiSMTManufacturerData[2] =
+		smc->mib.fddiSMTStationId.sid_node.a[2] ;
+	smc->sm.smt_tid = 0 ;
+	smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ;
+	smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
+#ifndef	SLIM_SMT
+	smt_clear_una_dna(smc) ;
+	smt_clear_old_una_dna(smc) ;
+#endif
+	for (i = 0 ; i < SMT_MAX_TEST ; i++)
+		smc->sm.pend[i] = 0 ;
+	smc->sm.please_reconnect = 0 ;
+	smc->sm.uniq_ticks = 0 ;
+}
+
+/*
+ * SMT task
+ * forever
+ *	delay 30 seconds
+ *	send NIF
+ *	check tvu & tvd
+ * end
+ */
+void smt_agent_task(smc)
+struct s_smc *smc ;
+{
+	smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
+		EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
+	DB_SMT("SMT agent task\n",0,0) ;
+}
+
+void smt_please_reconnect(smc,reconn_time)
+struct s_smc	*smc ;		/* Pointer to SMT context */
+int		reconn_time ;	/* Wait for reconnect time in seconds */
+{
+	/*
+	 * The please reconnect variable is used as a timer.
+	 * It is decremented each time smt_event is called.
+	 * This happens every second or when smt_force_irq is called.
+	 * Note: smt_force_irq () is called on some packet receives and
+	 *       when a multicast address is changed. Since nothing
+	 *       is received during the disconnect and the multicast
+	 *       address changes can be viewed as not very often and
+	 *       the timer runs out close to its given value
+	 *       (reconn_time).
+	 */
+	smc->sm.please_reconnect = reconn_time ;
+}
+
+#ifndef SMT_REAL_TOKEN_CT
+void smt_emulate_token_ct(smc, mac_index)
+struct s_smc	*smc;
+int		mac_index;
+{
+	u_long	count;
+	u_long	time;
+
+
+	time = smt_get_time();
+	count =	((time - smc->sm.last_tok_time[mac_index]) *
+					100)/TICKS_PER_SECOND;
+
+	/*
+	 * Only when ring is up we will have a token count. The
+	 * flag is unfortunatly a single instance value. This
+	 * doesn't matter now, because we currently have only
+	 * one MAC instance.
+	 */
+	if (smc->hw.mac_ring_is_up){
+		smc->mib.m[mac_index].fddiMACToken_Ct += count;
+	}
+
+	/* Remember current time */
+	smc->sm.last_tok_time[mac_index] = time;
+
+}
+#endif
+
+/*ARGSUSED1*/
+void smt_event(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	u_long		time ;
+#ifndef SMT_REAL_TOKEN_CT
+	int		i ;
+#endif
+
+
+	if (smc->sm.please_reconnect) {
+		smc->sm.please_reconnect -- ;
+		if (smc->sm.please_reconnect == 0) {
+			/* Counted down */
+			queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+		}
+	}
+
+	if (event == SM_FAST)
+		return ;
+
+	/*
+	 * timer for periodic cleanup in driver
+	 * reset and start the watchdog (FM2)
+	 * ESS timer
+	 * SBA timer
+	 */
+	smt_timer_poll(smc) ;
+	smt_start_watchdog(smc) ;
+#ifndef	SLIM_SMT
+#ifndef BOOT
+#ifdef	ESS
+	ess_timer_poll(smc) ;
+#endif
+#endif
+#ifdef	SBA
+	sba_timer_poll(smc) ;
+#endif
+
+	smt_srf_event(smc,0,0,0) ;
+
+#endif	/* no SLIM_SMT */
+
+	time = smt_get_time() ;
+
+	if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) {
+		/*
+		 * Use 8 sec. for the time intervall, it simplifies the
+		 * LER estimation.
+		 */
+		struct fddi_mib_m	*mib ;
+		u_long			upper ;
+		u_long			lower ;
+		int			cond ;
+		int			port;
+		struct s_phy		*phy ;
+		/*
+		 * calculate LEM bit error rate
+		 */
+		sm_lem_evaluate(smc) ;
+		smc->sm.smt_last_lem = time ;
+
+		/*
+		 * check conditions
+		 */
+#ifndef	SLIM_SMT
+		mac_update_counter(smc) ;
+		mib = smc->mib.m ;
+		upper =
+		(mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) +
+		(mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ;
+		lower =
+		(mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) +
+		(mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ;
+		mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ;
+
+		cond =
+			((!mib->fddiMACFrameErrorThreshold &&
+			mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) ||
+			(mib->fddiMACFrameErrorRatio >
+			mib->fddiMACFrameErrorThreshold)) ;
+
+		if (cond != mib->fddiMACFrameErrorFlag)
+			smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR,
+				INDEX_MAC,cond) ;
+
+		upper =
+		(mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ;
+		lower =
+		upper +
+		(mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ;
+		mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ;
+
+		cond =
+			((!mib->fddiMACNotCopiedThreshold &&
+			mib->fddiMACNotCopied_Ct !=
+				mib->fddiMACOld_NotCopied_Ct)||
+			(mib->fddiMACNotCopiedRatio >
+			mib->fddiMACNotCopiedThreshold)) ;
+
+		if (cond != mib->fddiMACNotCopiedFlag)
+			smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED,
+				INDEX_MAC,cond) ;
+
+		/*
+		 * set old values
+		 */
+		mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ;
+		mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ;
+		mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ;
+		mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ;
+		mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ;
+
+		/*
+		 * Check port EBError Condition
+		 */
+		for (port = 0; port < NUMPHYS; port ++) {
+			phy = &smc->y[port] ;
+
+			if (!phy->mib->fddiPORTHardwarePresent) {
+				continue;
+			}
+
+			cond = (phy->mib->fddiPORTEBError_Ct -
+				phy->mib->fddiPORTOldEBError_Ct > 5) ;
+
+			/* If ratio is more than 5 in 8 seconds
+			 * Set the condition.
+			 */
+			smt_srf_event(smc,SMT_COND_PORT_EB_ERROR,
+				(int) (INDEX_PORT+ phy->np) ,cond) ;
+
+			/*
+			 * set old values
+			 */
+			phy->mib->fddiPORTOldEBError_Ct =
+				phy->mib->fddiPORTEBError_Ct ;
+		}
+
+#endif	/* no SLIM_SMT */
+	}
+
+#ifndef	SLIM_SMT
+
+	if (time - smc->sm.smt_last_notify >= (u_long)
+		(smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) {
+		/*
+		 * we can either send an announcement or a request
+		 * a request will trigger a reply so that we can update
+		 * our dna
+		 * note: same tid must be used until reply is received
+		 */
+		if (!smc->sm.pend[SMT_TID_NIF])
+			smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ;
+		smt_send_nif(smc,&fddi_broadcast,FC_SMT_NSA,
+			smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ;
+		smc->sm.smt_last_notify = time ;
+	}
+
+	/*
+	 * check timer
+	 */
+	if (smc->sm.smt_tvu &&
+	    time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) {
+		DB_SMT("SMT : UNA expired\n",0,0) ;
+		smc->sm.smt_tvu = 0 ;
+
+		if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr,
+			&SMT_Unknown)){
+			/* Do not update unknown address */
+			smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
+				smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+		}
+		smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
+		smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
+		/*
+		 * Make sure the fddiMACUNDA_Flag = FALSE is
+		 * included in the SRF so we don't generate
+		 * a seperate SRF for the deassertion of this
+		 * condition
+		 */
+		update_dac(smc,0) ;
+		smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+			INDEX_MAC,0) ;
+	}
+	if (smc->sm.smt_tvd &&
+	    time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) {
+		DB_SMT("SMT : DNA expired\n",0,0) ;
+		smc->sm.smt_tvd = 0 ;
+		if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr,
+			&SMT_Unknown)){
+			/* Do not update unknown address */
+			smc->mib.m[MAC0].fddiMACOldDownstreamNbr=
+				smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+		}
+		smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
+		smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+			INDEX_MAC,0) ;
+	}
+
+#endif	/* no SLIM_SMT */
+
+#ifndef SMT_REAL_TOKEN_CT
+	/*
+	 * Token counter emulation section. If hardware supports the token
+	 * count, the token counter will be updated in mac_update_counter.
+	 */
+	for (i = MAC0; i < NUMMACS; i++ ){
+		if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){
+			smt_emulate_token_ct( smc, i );
+		}
+	}
+#endif
+
+	smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
+		EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
+}
+
+static int div_ratio(upper,lower)
+u_long upper ;
+u_long lower ;
+{
+	if ((upper<<16L) < upper)
+		upper = 0xffff0000L ;
+	else
+		upper <<= 16L ;
+	if (!lower)
+		return(0) ;
+	return((int)(upper/lower)) ;
+}
+
+#ifndef	SLIM_SMT
+
+/*
+ * receive packet handler
+ */
+void smt_received_pack(smc,mb,fs)
+struct s_smc *smc ;
+SMbuf *mb ;
+int fs ;			/* frame status */
+{
+	struct smt_header	*sm ;
+	int			local ;
+
+	int			illegal = 0 ;
+
+	switch (m_fc(mb)) {
+	case FC_SMT_INFO :
+	case FC_SMT_LAN_LOC :
+	case FC_SMT_LOC :
+	case FC_SMT_NSA :
+		break ;
+	default :
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+
+	smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ;
+	sm = smtod(mb,struct smt_header *) ;
+	local = ((fs & L_INDICATOR) != 0) ;
+	hwm_conv_can(smc,(char *)sm,12) ;
+
+	/* check destination address */
+	if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+#if	0		/* for DUP recognition, do NOT filter them */
+	/* ignore loop back packets */
+	if (is_my_addr(smc,&sm->smt_source) && !local) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+#endif
+
+	smt_swap_para(sm,(int) mb->sm_len,1) ;
+	DB_SMT("SMT : received packet [%s] at 0x%x\n",
+		smt_type_name[m_fc(mb) & 0xf],sm) ;
+	DB_SMT("SMT : version %d, class %s\n",sm->smt_version,
+		smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ;
+
+#ifdef	SBA
+	/*
+	 * check if NSA frame
+	 */
+	if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF &&
+		(sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) {
+			smc->sba.sm = sm ;
+			sba(smc,NIF) ;
+	}
+#endif
+
+	/*
+	 * ignore any packet with NSA and A-indicator set
+	 */
+	if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) {
+		DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+
+	/*
+	 * ignore frames with illegal length
+	 */
+	if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) ||
+	    ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+
+	/*
+	 * check SMT version
+	 */
+	switch (sm->smt_class) {
+	case SMT_NIF :
+	case SMT_SIF_CONFIG :
+	case SMT_SIF_OPER :
+	case SMT_ECF :
+		if (sm->smt_version != SMT_VID)
+			illegal = 1;
+		break ;
+	default :
+		if (sm->smt_version != SMT_VID_2)
+			illegal = 1;
+		break ;
+	}
+	if (illegal) {
+		DB_SMT("SMT : version = %d, dest = %s\n",
+			sm->smt_version,addr_to_string(&sm->smt_source)) ;
+		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ;
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+	if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) ||
+	    ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) {
+		DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ;
+		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ;
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+	switch (sm->smt_class) {
+	case SMT_NIF :
+		if (smt_check_para(smc,sm,plist_nif)) {
+			DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ;
+			break ;
+		} ;
+		switch (sm->smt_type) {
+		case SMT_ANNOUNCE :
+		case SMT_REQUEST :
+			if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA
+				&& is_broadcast(&sm->smt_dest)) {
+				struct smt_p_state	*st ;
+
+				/* set my UNA */
+				if (!is_equal(
+					&smc->mib.m[MAC0].fddiMACUpstreamNbr,
+					&sm->smt_source)) {
+					DB_SMT("SMT : updated my UNA = %s\n",
+					addr_to_string(&sm->smt_source),0) ;
+					if (!is_equal(&smc->mib.m[MAC0].
+					    fddiMACUpstreamNbr,&SMT_Unknown)){
+					 /* Do not update unknown address */
+					 smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
+					 smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+					}
+
+					smc->mib.m[MAC0].fddiMACUpstreamNbr =
+						sm->smt_source ;
+					smt_srf_event(smc,
+						SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+						INDEX_MAC,0) ;
+					smt_echo_test(smc,0) ;
+				}
+				smc->sm.smt_tvu = smt_get_time() ;
+				st = (struct smt_p_state *)
+					sm_to_para(smc,sm,SMT_P_STATE) ;
+				if (st) {
+					smc->mib.m[MAC0].fddiMACUNDA_Flag =
+					(st->st_dupl_addr & SMT_ST_MY_DUPA) ?
+					TRUE : FALSE ;
+					update_dac(smc,1) ;
+				}
+			}
+			if ((sm->smt_type == SMT_REQUEST) &&
+			    is_individual(&sm->smt_source) &&
+			    ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) ||
+			     (m_fc(mb) != FC_SMT_NSA))) {
+				DB_SMT("SMT : replying to NIF request %s\n",
+					addr_to_string(&sm->smt_source),0) ;
+				smt_send_nif(smc,&sm->smt_source,
+					FC_SMT_INFO,
+					sm->smt_tid,
+					SMT_REPLY,local) ;
+			}
+			break ;
+		case SMT_REPLY :
+			DB_SMT("SMT : received NIF response from %s\n",
+				addr_to_string(&sm->smt_source),0) ;
+			if (fs & A_INDICATOR) {
+				smc->sm.pend[SMT_TID_NIF] = 0 ;
+				DB_SMT("SMT : duplicate address\n",0,0) ;
+				smc->mib.m[MAC0].fddiMACDupAddressTest =
+					DA_FAILED ;
+				smc->r.dup_addr_test = DA_FAILED ;
+				queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+				smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ;
+				update_dac(smc,1) ;
+				break ;
+			}
+			if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) {
+				smc->sm.pend[SMT_TID_NIF] = 0 ;
+				/* set my DNA */
+				if (!is_equal(
+					&smc->mib.m[MAC0].fddiMACDownstreamNbr,
+					&sm->smt_source)) {
+					DB_SMT("SMT : updated my DNA\n",0,0) ;
+					if (!is_equal(&smc->mib.m[MAC0].
+					 fddiMACDownstreamNbr, &SMT_Unknown)){
+					 /* Do not update unknown address */
+				smc->mib.m[MAC0].fddiMACOldDownstreamNbr =
+					 smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+					}
+
+					smc->mib.m[MAC0].fddiMACDownstreamNbr =
+						sm->smt_source ;
+					smt_srf_event(smc,
+						SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+						INDEX_MAC,0) ;
+					smt_echo_test(smc,1) ;
+				}
+				smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ;
+				update_dac(smc,1) ;
+				smc->sm.smt_tvd = smt_get_time() ;
+				smc->mib.m[MAC0].fddiMACDupAddressTest =
+					DA_PASSED ;
+				if (smc->r.dup_addr_test != DA_PASSED) {
+					smc->r.dup_addr_test = DA_PASSED ;
+					queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+				}
+			}
+			else if (sm->smt_tid ==
+				smc->sm.pend[SMT_TID_NIF_TEST]) {
+				DB_SMT("SMT : NIF test TID ok\n",0,0) ;
+			}
+			else {
+				DB_SMT("SMT : expected TID %lx, got %lx\n",
+				smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ;
+			}
+			break ;
+		default :
+			illegal = 2 ;
+			break ;
+		}
+		break ;
+	case SMT_SIF_CONFIG :	/* station information */
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		DB_SMT("SMT : replying to SIF Config request from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ;
+		break ;
+	case SMT_SIF_OPER :	/* station information */
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		DB_SMT("SMT : replying to SIF Operation request from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ;
+		break ;
+	case SMT_ECF :		/* echo frame */
+		switch (sm->smt_type) {
+		case SMT_REPLY :
+			smc->mib.priv.fddiPRIVECF_Reply_Rx++ ;
+			DB_SMT("SMT: received ECF reply from %s\n",
+				addr_to_string(&sm->smt_source),0) ;
+			if (sm_to_para(smc,sm,SMT_P_ECHODATA) == 0) {
+				DB_SMT("SMT: ECHODATA missing\n",0,0) ;
+				break ;
+			}
+			if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) {
+				DB_SMT("SMT : ECF test TID ok\n",0,0) ;
+			}
+			else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) {
+				DB_SMT("SMT : ECF test UNA ok\n",0,0) ;
+			}
+			else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) {
+				DB_SMT("SMT : ECF test DNA ok\n",0,0) ;
+			}
+			else {
+				DB_SMT("SMT : expected TID %lx, got %lx\n",
+					smc->sm.pend[SMT_TID_ECF],
+					sm->smt_tid) ;
+			}
+			break ;
+		case SMT_REQUEST :
+			smc->mib.priv.fddiPRIVECF_Req_Rx++ ;
+			{
+			if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) {
+			DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ;
+				smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,
+					local) ;
+				break ;
+			}
+			DB_SMT("SMT - sending ECF reply to %s\n",
+				addr_to_string(&sm->smt_source),0) ;
+
+			/* set destination addr.  & reply */
+			sm->smt_dest = sm->smt_source ;
+			sm->smt_type = SMT_REPLY ;
+			dump_smt(smc,sm,"ECF REPLY") ;
+			smc->mib.priv.fddiPRIVECF_Reply_Tx++ ;
+			smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+			return ;		/* DON'T free mbuf */
+			}
+		default :
+			illegal = 1 ;
+			break ;
+		}
+		break ;
+#ifndef	BOOT
+	case SMT_RAF :		/* resource allocation */
+#ifdef	ESS
+		DB_ESSN(2,"ESS: RAF frame received\n",0,0) ;
+		fs = ess_raf_received_pack(smc,mb,sm,fs) ;
+#endif
+
+#ifdef	SBA
+		DB_SBAN(2,"SBA: RAF frame received\n",0,0) ;
+		sba_raf_received_pack(smc,sm,fs) ;
+#endif
+		break ;
+	case SMT_RDF :		/* request denied */
+		smc->mib.priv.fddiPRIVRDF_Rx++ ;
+		break ;
+	case SMT_ESF :		/* extended service - not supported */
+		if (sm->smt_type == SMT_REQUEST) {
+			DB_SMT("SMT - received ESF, sending RDF\n",0,0) ;
+			smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
+		}
+		break ;
+	case SMT_PMF_GET :
+	case SMT_PMF_SET :
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		/* update statistics */
+		if (sm->smt_class == SMT_PMF_GET)
+			smc->mib.priv.fddiPRIVPMF_Get_Rx++ ;
+		else
+			smc->mib.priv.fddiPRIVPMF_Set_Rx++ ;
+		/*
+		 * ignore PMF SET with I/G set
+		 */
+		if ((sm->smt_class == SMT_PMF_SET) &&
+			!is_individual(&sm->smt_dest)) {
+			DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ;
+			break ;
+		}
+		smt_pmf_received_pack(smc,mb, local) ;
+		break ;
+	case SMT_SRF :
+		dump_smt(smc,sm,"SRF received") ;
+		break ;
+	default :
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		/*
+		 * For frames with unknown class:
+		 * we need to send a RDF frame according to 8.1.3.1.1,
+		 * only if it is a REQUEST.
+		 */
+		DB_SMT("SMT : class = %d, send RDF to %s\n",
+			sm->smt_class, addr_to_string(&sm->smt_source)) ;
+
+		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
+		break ;
+#endif
+	}
+	if (illegal) {
+		DB_SMT("SMT: discarding illegal frame, reason = %d\n",
+			illegal,0) ;
+	}
+	smt_free_mbuf(smc,mb) ;
+}
+
+static void update_dac(smc,report)
+struct s_smc *smc ;
+int report ;
+{
+	int	cond ;
+
+	cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag |
+		smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ;
+	if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond))
+		smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ;
+	else
+		smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ;
+}
+
+/*
+ * send SMT frame
+ *	set source address
+ *	set station ID
+ *	send frame
+ */
+EXPORT_PMF void smt_send_frame(smc,mb,fc,local)
+struct s_smc *smc ;
+SMbuf *mb ;			/* buffer to send */
+int fc ;			/* FC value */
+int local ;
+{
+	struct smt_header	*sm ;
+
+	if (!smc->r.sm_ma_avail && !local) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+	sm = smtod(mb,struct smt_header *) ;
+	sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
+	sm->smt_sid = smc->mib.fddiSMTStationId ;
+
+	smt_swap_para(sm,(int) mb->sm_len,0) ;		/* swap para & header */
+	hwm_conv_can(smc,(char *)sm,12) ;		/* convert SA and DA */
+	smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ;
+	smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ;
+}
+
+/*
+ * generate and send RDF
+ */
+static void smt_send_rdf(smc,rej,fc,reason,local)
+struct s_smc *smc ;
+SMbuf	*rej ;			/* mbuf of offending frame */
+int	fc ;			/* FC of denied frame */
+int reason ;			/* reason code */
+int local ;
+{
+	SMbuf	*mb ;
+	struct smt_header	*sm ;	/* header of offending frame */
+	struct smt_rdf	*rdf ;
+	int		len ;
+	int		frame_len ;
+
+	sm = smtod(rej,struct smt_header *) ;
+	if (sm->smt_type != SMT_REQUEST)
+		return ;
+
+	DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n",
+		addr_to_string(&sm->smt_source),reason) ;
+
+
+	/*
+	 * note: get framelength from MAC length, NOT from SMT header
+	 * smt header length is included in sm_len
+	 */
+	frame_len = rej->sm_len ;
+
+	if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf))))
+		return ;
+	rdf = smtod(mb,struct smt_rdf *) ;
+	rdf->smt.smt_tid = sm->smt_tid ;		/* use TID from sm */
+	rdf->smt.smt_dest = sm->smt_source ;		/* set dest = source */
+
+	/* set P12 */
+	rdf->reason.para.p_type = SMT_P_REASON ;
+	rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ;
+	rdf->reason.rdf_reason = reason ;
+
+	/* set P14 */
+	rdf->version.para.p_type = SMT_P_VERSION ;
+	rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ;
+	rdf->version.v_pad = 0 ;
+	rdf->version.v_n = 1 ;
+	rdf->version.v_index = 1 ;
+	rdf->version.v_version[0] = SMT_VID_2 ;
+	rdf->version.v_pad2 = 0 ;
+
+	/* set P13 */
+	if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) +
+		2*sizeof(struct smt_header))
+		len = frame_len ;
+	else
+		len = SMT_MAX_INFO_LEN - sizeof(*rdf) +
+			2*sizeof(struct smt_header) ;
+	/* make length multiple of 4 */
+	len &= ~3 ;
+	rdf->refused.para.p_type = SMT_P_REFUSED ;
+	/* length of para is smt_frame + ref_fc */
+	rdf->refused.para.p_len = len + 4 ;
+	rdf->refused.ref_fc = fc ;
+
+	/* swap it back */
+	smt_swap_para(sm,frame_len,0) ;
+
+	memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ;
+
+	len -= sizeof(struct smt_header) ;
+	mb->sm_len += len ;
+	rdf->smt.smt_len += len ;
+
+	dump_smt(smc,(struct smt_header *)rdf,"RDF") ;
+	smc->mib.priv.fddiPRIVRDF_Tx++ ;
+	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * generate and send NIF
+ */
+static void smt_send_nif(smc,dest,fc,tid,type,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+int fc ;				/* frame control */
+u_long tid ;				/* transaction id */
+int type ;				/* frame type */
+int local ;
+{
+	struct smt_nif	*nif ;
+	SMbuf		*mb ;
+
+	if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif))))
+		return ;
+	nif = smtod(mb, struct smt_nif *) ;
+	smt_fill_una(smc,&nif->una) ;	/* set UNA */
+	smt_fill_sde(smc,&nif->sde) ;	/* set station descriptor */
+	smt_fill_state(smc,&nif->state) ;	/* set state information */
+#ifdef	SMT6_10
+	smt_fill_fsc(smc,&nif->fsc) ;	/* set frame status cap. */
+#endif
+	nif->smt.smt_dest = *dest ;	/* destination address */
+	nif->smt.smt_tid = tid ;	/* transaction ID */
+	dump_smt(smc,(struct smt_header *)nif,"NIF") ;
+	smt_send_frame(smc,mb,fc,local) ;
+}
+
+#ifdef	DEBUG
+/*
+ * send NIF request (test purpose)
+ */
+static void smt_send_nif_request(smc,dest)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+{
+	smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ;
+	smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST],
+		SMT_REQUEST,0) ;
+}
+
+/*
+ * send ECF request (test purpose)
+ */
+static void smt_send_ecf_request(smc,dest,len)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+int len ;
+{
+	smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ;
+	smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF],
+		SMT_REQUEST,len) ;
+}
+#endif
+
+/*
+ * echo test
+ */
+static void smt_echo_test(smc,dna)
+struct s_smc *smc ;
+int dna ;
+{
+	u_long	tid ;
+
+	smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] =
+		tid = smt_get_tid(smc) ;
+	smt_send_ecf(smc, dna ?
+		&smc->mib.m[MAC0].fddiMACDownstreamNbr :
+		&smc->mib.m[MAC0].fddiMACUpstreamNbr,
+		FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ;
+}
+
+/*
+ * generate and send ECF
+ */
+static void smt_send_ecf(smc,dest,fc,tid,type,len)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+int fc ;				/* frame control */
+u_long tid ;				/* transaction id */
+int type ;				/* frame type */
+int len ;				/* frame length */
+{
+	struct smt_ecf	*ecf ;
+	SMbuf		*mb ;
+
+	if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len)))
+		return ;
+	ecf = smtod(mb, struct smt_ecf *) ;
+
+	smt_fill_echo(smc,&ecf->ec_echo,tid,len) ;	/* set ECHO */
+	ecf->smt.smt_dest = *dest ;	/* destination address */
+	ecf->smt.smt_tid = tid ;	/* transaction ID */
+	smc->mib.priv.fddiPRIVECF_Req_Tx++ ;
+	smt_send_frame(smc,mb,fc,0) ;
+}
+
+/*
+ * generate and send SIF config response
+ */
+
+static void smt_send_sif_config(smc,dest,tid,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+u_long tid ;				/* transaction id */
+int local ;
+{
+	struct smt_sif_config	*sif ;
+	SMbuf			*mb ;
+	int			len ;
+	if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY,
+		SIZEOF_SMT_SIF_CONFIG)))
+		return ;
+
+	sif = smtod(mb, struct smt_sif_config *) ;
+	smt_fill_timestamp(smc,&sif->ts) ;	/* set time stamp */
+	smt_fill_sde(smc,&sif->sde) ;		/* set station descriptor */
+	smt_fill_version(smc,&sif->version) ;	/* set version information */
+	smt_fill_state(smc,&sif->state) ;	/* set state information */
+	smt_fill_policy(smc,&sif->policy) ;	/* set station policy */
+	smt_fill_latency(smc,&sif->latency);	/* set station latency */
+	smt_fill_neighbor(smc,&sif->neighbor);	/* set station neighbor */
+	smt_fill_setcount(smc,&sif->setcount) ;	/* set count */
+	len = smt_fill_path(smc,&sif->path);	/* set station path descriptor*/
+	sif->smt.smt_dest = *dest ;		/* destination address */
+	sif->smt.smt_tid = tid ;		/* transaction ID */
+	smt_add_frame_len(mb,len) ;		/* adjust length fields */
+	dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ;
+	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * generate and send SIF operation response
+ */
+
+static void smt_send_sif_operation(smc,dest,tid,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+u_long tid ;				/* transaction id */
+int local ;
+{
+	struct smt_sif_operation *sif ;
+	SMbuf			*mb ;
+	int			ports ;
+	int			i ;
+
+	ports = NUMPHYS ;
+#ifndef	CONCENTRATOR
+	if (smc->s.sas == SMT_SAS)
+		ports = 1 ;
+#endif
+
+	if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY,
+		SIZEOF_SMT_SIF_OPERATION+ports*sizeof(struct smt_p_lem))))
+		return ;
+	sif = smtod(mb, struct smt_sif_operation *) ;
+	smt_fill_timestamp(smc,&sif->ts) ;	/* set time stamp */
+	smt_fill_mac_status(smc,&sif->status) ; /* set mac status */
+	smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */
+	smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */
+	smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */
+	smt_fill_user(smc,&sif->user) ;		/* set user field */
+	smt_fill_setcount(smc,&sif->setcount) ;	/* set count */
+	/*
+	 * set link error mon information
+	 */
+	if (ports == 1) {
+		smt_fill_lem(smc,sif->lem,PS) ;
+	}
+	else {
+		for (i = 0 ; i < ports ; i++) {
+			smt_fill_lem(smc,&sif->lem[i],i) ;
+		}
+	}
+
+	sif->smt.smt_dest = *dest ;	/* destination address */
+	sif->smt.smt_tid = tid ;	/* transaction ID */
+	dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ;
+	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * get and initialize SMT frame
+ */
+EXPORT_PMF SMbuf *smt_build_frame(smc,class,type,length)
+struct s_smc *smc ;
+int class ;
+int type ;
+int length ;
+{
+	SMbuf			*mb ;
+	struct smt_header	*smt ;
+
+#if	0
+	if (!smc->r.sm_ma_avail) {
+		return(0) ;
+	}
+#endif
+	if (!(mb = smt_get_mbuf(smc)))
+		return(mb) ;
+
+	mb->sm_len = length ;
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */
+	smt->smt_class = class ;
+	smt->smt_type = type ;
+	switch (class) {
+	case SMT_NIF :
+	case SMT_SIF_CONFIG :
+	case SMT_SIF_OPER :
+	case SMT_ECF :
+		smt->smt_version = SMT_VID ;
+		break ;
+	default :
+		smt->smt_version = SMT_VID_2 ;
+		break ;
+	}
+	smt->smt_tid = smt_get_tid(smc) ;	/* set transaction ID */
+	smt->smt_pad = 0 ;
+	smt->smt_len = length - sizeof(struct smt_header) ;
+	return(mb) ;
+}
+
+static void smt_add_frame_len(mb,len)
+SMbuf *mb ;
+int len ;
+{
+	struct smt_header	*smt ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_len += len ;
+	mb->sm_len += len ;
+}
+
+
+
+/*
+ * fill values in UNA parameter
+ */
+static void smt_fill_una(smc,una)
+struct s_smc *smc ;
+struct smt_p_una *una ;
+{
+	SMTSETPARA(una,SMT_P_UNA) ;
+	una->una_pad = 0 ;
+	una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+}
+
+/*
+ * fill values in SDE parameter
+ */
+static void smt_fill_sde(smc,sde)
+struct s_smc *smc ;
+struct smt_p_sde *sde ;
+{
+	SMTSETPARA(sde,SMT_P_SDE) ;
+	sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ;
+	sde->sde_master = smc->mib.fddiSMTMaster_Ct ;
+	sde->sde_mac_count = NUMMACS ;		/* only 1 MAC */
+#ifdef	CONCENTRATOR
+	sde->sde_type = SMT_SDE_CONCENTRATOR ;
+#else
+	sde->sde_type = SMT_SDE_STATION ;
+#endif
+}
+
+/*
+ * fill in values in station state parameter
+ */
+static void smt_fill_state(smc,state)
+struct s_smc *smc ;
+struct smt_p_state *state ;
+{
+	int	top ;
+	int	twist ;
+
+	SMTSETPARA(state,SMT_P_STATE) ;
+	state->st_pad = 0 ;
+
+	/* determine topology */
+	top = 0 ;
+	if (smc->mib.fddiSMTPeerWrapFlag) {
+		top |= SMT_ST_WRAPPED ;		/* state wrapped */
+	}
+#ifdef	CONCENTRATOR
+	if (cfm_status_unattached(smc)) {
+		top |= SMT_ST_UNATTACHED ;	/* unattached concentrator */
+	}
+#endif
+	if ((twist = pcm_status_twisted(smc)) & 1) {
+		top |= SMT_ST_TWISTED_A ;	/* twisted cable */
+	}
+	if (twist & 2) {
+		top |= SMT_ST_TWISTED_B ;	/* twisted cable */
+	}
+#ifdef	OPT_SRF
+	top |= SMT_ST_SRF ;
+#endif
+	if (pcm_rooted_station(smc))
+		top |= SMT_ST_ROOTED_S ;
+	if (smc->mib.a[0].fddiPATHSbaPayload != 0)
+		top |= SMT_ST_SYNC_SERVICE ;
+	state->st_topology = top ;
+	state->st_dupl_addr =
+		((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) |
+		 (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ;
+}
+
+/*
+ * fill values in timestamp parameter
+ */
+static void smt_fill_timestamp(smc,ts)
+struct s_smc *smc ;
+struct smt_p_timestamp *ts ;
+{
+
+	SMTSETPARA(ts,SMT_P_TIMESTAMP) ;
+	smt_set_timestamp(smc,ts->ts_time) ;
+}
+
+EXPORT_PMF void smt_set_timestamp(smc,p)
+struct s_smc *smc ;
+u_char *p ;
+{
+	u_long	time ;
+	u_long	utime ;
+
+	/*
+	 * timestamp is 64 bits long ; resolution is 80 nS
+	 * our clock resolution is 10mS
+	 * 10mS/80ns = 125000 ~ 2^17 = 131072
+	 */
+	utime = smt_get_time() ;
+	time = utime * 100 ;
+	time /= TICKS_PER_SECOND ;
+	p[0] = 0 ;
+	p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ;
+	p[2] = (u_char)(time>>(8+8+8-1)) ;
+	p[3] = (u_char)(time>>(8+8-1)) ;
+	p[4] = (u_char)(time>>(8-1)) ;
+	p[5] = (u_char)(time<<1) ;
+	p[6] = (u_char)(smc->sm.uniq_ticks>>8) ;
+	p[7] = (u_char)smc->sm.uniq_ticks ;
+	/*
+	 * make sure we don't wrap: restart whenever the upper digits change
+	 */
+	if (utime != smc->sm.uniq_time) {
+		smc->sm.uniq_ticks = 0 ;
+	}
+	smc->sm.uniq_ticks++ ;
+	smc->sm.uniq_time = utime ;
+}
+
+/*
+ * fill values in station policy parameter
+ */
+static void smt_fill_policy(smc,policy)
+struct s_smc *smc ;
+struct smt_p_policy *policy ;
+{
+	int	i ;
+	u_char	*map ;
+	u_short	in ;
+	u_short	out ;
+
+	/*
+	 * MIB para 101b (fddiSMTConnectionPolicy) coding
+	 * is different from 0005 coding
+	 */
+	static u_char	ansi_weirdness[16] = {
+		0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15
+	} ;
+	SMTSETPARA(policy,SMT_P_POLICY) ;
+
+	out = 0 ;
+	in = smc->mib.fddiSMTConnectionPolicy ;
+	for (i = 0, map = ansi_weirdness ; i < 16 ; i++) {
+		if (in & 1)
+			out |= (1<<*map) ;
+		in >>= 1 ;
+		map++ ;
+	}
+	policy->pl_config = smc->mib.fddiSMTConfigPolicy ;
+	policy->pl_connect = out ;
+}
+
+/*
+ * fill values in latency equivalent parameter
+ */
+static void smt_fill_latency(smc,latency)
+struct s_smc *smc ;
+struct smt_p_latency *latency ;
+{
+	SMTSETPARA(latency,SMT_P_LATENCY) ;
+
+	latency->lt_phyout_idx1 = phy_index(smc,0) ;
+	latency->lt_latency1 = 10 ;	/* in octets (byte clock) */
+	/*
+	 * note: latency has two phy entries by definition
+	 * for a SAS, the 2nd one is null
+	 */
+	if (smc->s.sas == SMT_DAS) {
+		latency->lt_phyout_idx2 = phy_index(smc,1) ;
+		latency->lt_latency2 = 10 ;	/* in octets (byte clock) */
+	}
+	else {
+		latency->lt_phyout_idx2 = 0 ;
+		latency->lt_latency2 = 0 ;
+	}
+}
+
+/*
+ * fill values in MAC neighbors parameter
+ */
+static void smt_fill_neighbor(smc,neighbor)
+struct s_smc *smc ;
+struct smt_p_neighbor *neighbor ;
+{
+	SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ;
+
+	neighbor->nb_mib_index = INDEX_MAC ;
+	neighbor->nb_mac_index = mac_index(smc,1) ;
+	neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+	neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+}
+
+/*
+ * fill values in path descriptor
+ */
+#ifdef	CONCENTRATOR
+#define ALLPHYS	NUMPHYS
+#else
+#define ALLPHYS	((smc->s.sas == SMT_SAS) ? 1 : 2)
+#endif
+
+static int smt_fill_path(smc,path)
+struct s_smc *smc ;
+struct smt_p_path *path ;
+{
+	SK_LOC_DECL(int,type) ;
+	SK_LOC_DECL(int,state) ;
+	SK_LOC_DECL(int,remote) ;
+	SK_LOC_DECL(int,mac) ;
+	int	len ;
+	int	p ;
+	int	physp ;
+	struct smt_phy_rec	*phy ;
+	struct smt_mac_rec	*pd_mac ;
+
+	len =	PARA_LEN +
+		sizeof(struct smt_mac_rec) * NUMMACS +
+		sizeof(struct smt_phy_rec) * ALLPHYS ;
+	path->para.p_type = SMT_P_PATH ;
+	path->para.p_len = len - PARA_LEN ;
+
+	/* PHYs */
+	for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) {
+		physp = p ;
+#ifndef	CONCENTRATOR
+		if (smc->s.sas == SMT_SAS)
+			physp = PS ;
+#endif
+		pcm_status_state(smc,physp,&type,&state,&remote,&mac) ;
+#ifdef	LITTLE_ENDIAN
+		phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ;
+#else
+		phy->phy_mib_index = p+INDEX_PORT ;
+#endif
+		phy->phy_type = type ;
+		phy->phy_connect_state = state ;
+		phy->phy_remote_type = remote ;
+		phy->phy_remote_mac = mac ;
+		phy->phy_resource_idx = phy_con_resource_index(smc,p) ;
+	}
+
+	/* MAC */
+	pd_mac = (struct smt_mac_rec *) phy ;
+	pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ;
+	pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ;
+	return(len) ;
+}
+
+/*
+ * fill values in mac status
+ */
+static void smt_fill_mac_status(smc,st)
+struct s_smc *smc ;
+struct smt_p_mac_status *st ;
+{
+	SMTSETPARA(st,SMT_P_MAC_STATUS) ;
+
+	st->st_mib_index = INDEX_MAC ;
+	st->st_mac_index = mac_index(smc,1) ;
+
+	mac_update_counter(smc) ;
+	/*
+	 * timer values are represented in SMT as 2's complement numbers
+	 * units :	internal :  2's complement BCLK
+	 */
+	st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ;
+	st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ;
+	st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ;
+	st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ;
+	st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ;
+
+	st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+	st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ;
+	st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ;
+	st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ;
+}
+
+/*
+ * fill values in LEM status
+ */
+
+static void smt_fill_lem(smc,lem,phy)
+struct s_smc *smc ;
+struct smt_p_lem *lem ;
+int phy ;
+{
+	struct fddi_mib_p	*mib ;
+
+	mib = smc->y[phy].mib ;
+
+	SMTSETPARA(lem,SMT_P_LEM) ;
+	lem->lem_mib_index = phy+INDEX_PORT ;
+	lem->lem_phy_index = phy_index(smc,phy) ;
+	lem->lem_pad2 = 0 ;
+	lem->lem_cutoff = mib->fddiPORTLer_Cutoff ;
+	lem->lem_alarm = mib->fddiPORTLer_Alarm ;
+	/* long term bit error rate */
+	lem->lem_estimate = mib->fddiPORTLer_Estimate ;
+	/* # of rejected connections */
+	lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ;
+	lem->lem_ct = mib->fddiPORTLem_Ct ;	/* total number of errors */
+}
+
+/*
+ * fill version parameter
+ */
+static void smt_fill_version(smc,vers)
+struct s_smc *smc ;
+struct smt_p_version *vers ;
+{
+	SK_UNUSED(smc) ;
+	SMTSETPARA(vers,SMT_P_VERSION) ;
+	vers->v_pad = 0 ;
+	vers->v_n = 1 ;				/* one version is enough .. */
+	vers->v_index = 1 ;
+	vers->v_version[0] = SMT_VID_2 ;
+	vers->v_pad2 = 0 ;
+}
+
+#ifdef	SMT6_10
+/*
+ * fill frame status capabilities
+ */
+/*
+ * note: this para 200B is NOT in swap table, because it's also set in
+ * PMF add_para
+ */
+static void smt_fill_fsc(smc,fsc)
+struct s_smc *smc ;
+struct smt_p_fsc *fsc ;
+{
+	SK_UNUSED(smc) ;
+	SMTSETPARA(fsc,SMT_P_FSC) ;
+	fsc->fsc_pad0 = 0 ;
+	fsc->fsc_mac_index = INDEX_MAC ;	/* this is MIB ; MIB is NOT
+						 * mac_index ()i !
+						 */
+	fsc->fsc_pad1 = 0 ;
+	fsc->fsc_value = FSC_TYPE0 ;		/* "normal" node */
+#ifdef	LITTLE_ENDIAN
+	fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ;
+	fsc->fsc_value = smt_swap_short(FSC_TYPE0) ;
+#endif
+}
+#endif
+
+/*
+ * fill mac counter field
+ */
+static void smt_fill_mac_counter(smc,mc)
+struct s_smc *smc ;
+struct smt_p_mac_counter *mc ;
+{
+	SMTSETPARA(mc,SMT_P_MAC_COUNTER) ;
+	mc->mc_mib_index = INDEX_MAC ;
+	mc->mc_index = mac_index(smc,1) ;
+	mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ;
+	mc->mc_transmit_ct =  smc->mib.m[MAC0].fddiMACTransmit_Ct ;
+}
+
+/*
+ * fill mac frame not copied counter
+ */
+static void smt_fill_mac_fnc(smc,fnc)
+struct s_smc *smc ;
+struct smt_p_mac_fnc *fnc ;
+{
+	SMTSETPARA(fnc,SMT_P_MAC_FNC) ;
+	fnc->nc_mib_index = INDEX_MAC ;
+	fnc->nc_index = mac_index(smc,1) ;
+	fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ;
+}
+
+
+/*
+ * fill manufacturer field
+ */
+static void smt_fill_manufacturer(smc,man)
+struct s_smc *smc ;
+struct smp_p_manufacturer *man ;
+{
+	SMTSETPARA(man,SMT_P_MANUFACTURER) ;
+	memcpy((char *) man->mf_data,
+		(char *) smc->mib.fddiSMTManufacturerData,
+		sizeof(man->mf_data)) ;
+}
+
+/*
+ * fill user field
+ */
+static void smt_fill_user(smc,user)
+struct s_smc *smc ;
+struct smp_p_user *user ;
+{
+	SMTSETPARA(user,SMT_P_USER) ;
+	memcpy((char *) user->us_data,
+		(char *) smc->mib.fddiSMTUserData,
+		sizeof(user->us_data)) ;
+}
+
+
+
+/*
+ * fill set count
+ */
+static void smt_fill_setcount(smc,setcount)
+struct s_smc *smc ;
+struct smt_p_setcount *setcount ;
+{
+	SK_UNUSED(smc) ;
+	SMTSETPARA(setcount,SMT_P_SETCOUNT) ;
+	setcount->count = smc->mib.fddiSMTSetCount.count ;
+	memcpy((char *)setcount->timestamp,
+		(char *)smc->mib.fddiSMTSetCount.timestamp,8) ;
+}
+
+/*
+ * fill echo data
+ */
+static void smt_fill_echo(smc,echo,seed,len)
+struct s_smc *smc ;
+struct smt_p_echo *echo ;
+u_long seed ;
+int len ;
+{
+
+	u_char	*p ;
+
+	SK_UNUSED(smc) ;
+	SMTSETPARA(echo,SMT_P_ECHODATA) ;
+	echo->para.p_len = len ;
+	for (p = echo->ec_data ; len ; len--) {
+		*p++ = (u_char) seed ;
+		seed += 13 ;
+	}
+}
+
+/*
+ * clear DNA and UNA
+ * called from CFM if configuration changes
+ */
+void smt_clear_una_dna(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
+	smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
+}
+
+static void smt_clear_old_una_dna(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ;
+	smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ;
+}
+
+u_long smt_get_tid(smc)
+struct s_smc *smc ;
+{
+	u_long	tid ;
+	while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0)
+		;
+	return(tid & 0x3fffffffL) ;
+}
+
+
+/*
+ * table of parameter lengths
+ */
+static const struct smt_pdef {
+	int	ptype ;
+	int	plen ;
+	const char	*pswap ;
+} smt_pdef[] = {
+	{ SMT_P_UNA,	sizeof(struct smt_p_una) ,
+		SWAP_SMT_P_UNA					} ,
+	{ SMT_P_SDE,	sizeof(struct smt_p_sde) ,
+		SWAP_SMT_P_SDE					} ,
+	{ SMT_P_STATE,	sizeof(struct smt_p_state) ,
+		SWAP_SMT_P_STATE				} ,
+	{ SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) ,
+		SWAP_SMT_P_TIMESTAMP				} ,
+	{ SMT_P_POLICY,	sizeof(struct smt_p_policy) ,
+		SWAP_SMT_P_POLICY				} ,
+	{ SMT_P_LATENCY,	sizeof(struct smt_p_latency) ,
+		SWAP_SMT_P_LATENCY				} ,
+	{ SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) ,
+		SWAP_SMT_P_NEIGHBORS				} ,
+	{ SMT_P_PATH,	sizeof(struct smt_p_path) ,
+		SWAP_SMT_P_PATH					} ,
+	{ SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) ,
+		SWAP_SMT_P_MAC_STATUS				} ,
+	{ SMT_P_LEM,	sizeof(struct smt_p_lem) ,
+		SWAP_SMT_P_LEM					} ,
+	{ SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) ,
+		SWAP_SMT_P_MAC_COUNTER				} ,
+	{ SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) ,
+		SWAP_SMT_P_MAC_FNC				} ,
+	{ SMT_P_PRIORITY,sizeof(struct smt_p_priority) ,
+		SWAP_SMT_P_PRIORITY				} ,
+	{ SMT_P_EB,sizeof(struct smt_p_eb) ,
+		SWAP_SMT_P_EB					} ,
+	{ SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) ,
+		SWAP_SMT_P_MANUFACTURER				} ,
+	{ SMT_P_REASON,	sizeof(struct smt_p_reason) ,
+		SWAP_SMT_P_REASON				} ,
+	{ SMT_P_REFUSED, sizeof(struct smt_p_refused) ,
+		SWAP_SMT_P_REFUSED				} ,
+	{ SMT_P_VERSION, sizeof(struct smt_p_version) ,
+		SWAP_SMT_P_VERSION				} ,
+#ifdef ESS
+	{ SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } ,
+	{ SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } ,
+	{ SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } ,
+	{ SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } ,
+	{ SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } ,
+	{ SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } ,
+	{ SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } ,
+	{ SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } ,
+	{ SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } ,
+#endif
+#if	0
+	{ SMT_P_FSC,	sizeof(struct smt_p_fsc) ,
+		SWAP_SMT_P_FSC					} ,
+#endif
+
+	{ SMT_P_SETCOUNT,0,	SWAP_SMT_P_SETCOUNT		} ,
+	{ SMT_P1048,	0,	SWAP_SMT_P1048			} ,
+	{ SMT_P208C,	0,	SWAP_SMT_P208C			} ,
+	{ SMT_P208D,	0,	SWAP_SMT_P208D			} ,
+	{ SMT_P208E,	0,	SWAP_SMT_P208E			} ,
+	{ SMT_P208F,	0,	SWAP_SMT_P208F			} ,
+	{ SMT_P2090,	0,	SWAP_SMT_P2090			} ,
+#ifdef	ESS
+	{ SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } ,
+	{ SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } ,
+	{ SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } ,
+#endif
+	{ SMT_P4050,	0,	SWAP_SMT_P4050			} ,
+	{ SMT_P4051,	0,	SWAP_SMT_P4051			} ,
+	{ SMT_P4052,	0,	SWAP_SMT_P4052			} ,
+	{ SMT_P4053,	0,	SWAP_SMT_P4053			} ,
+} ;
+
+#define N_SMT_PLEN	(sizeof(smt_pdef)/sizeof(smt_pdef[0]))
+
+int smt_check_para(smc,sm,list)
+struct s_smc *smc ;
+struct smt_header	*sm ;
+const u_short		list[] ;
+{
+	const u_short		*p = list ;
+	while (*p) {
+		if (!sm_to_para(smc,sm,(int) *p)) {
+			DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0);
+			return(-1) ;
+		}
+		p++ ;
+	}
+	return(0) ;
+}
+
+EXPORT_PMF void *sm_to_para(smc,sm,para)
+struct s_smc *smc ;
+struct smt_header	*sm ;
+int para ;
+{
+	char	*p ;
+	int	len ;
+	int	plen ;
+	void	*found = 0 ;
+
+	SK_UNUSED(smc) ;
+
+	len = sm->smt_len ;
+	p = (char *)(sm+1) ;		/* pointer to info */
+	while (len > 0 ) {
+		if (((struct smt_para *)p)->p_type == para)
+			found = (void *) p ;
+		plen = ((struct smt_para *)p)->p_len + PARA_LEN ;
+		p += plen ;
+		len -= plen ;
+		if (len < 0) {
+			DB_SMT("SMT : sm_to_para - length error %d\n",plen,0) ;
+			return(0) ;
+		}
+		if ((plen & 3) && (para != SMT_P_ECHODATA)) {
+			DB_SMT("SMT : sm_to_para - odd length %d\n",plen,0) ;
+			return(0) ;
+		}
+		if (found)
+			return(found) ;
+	}
+	return(0) ;
+}
+
+int is_my_addr(smc,addr)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+{
+	return(*(short *)(&addr->a[0]) ==
+		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0])
+	  && *(short *)(&addr->a[2]) ==
+		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2])
+	  && *(short *)(&addr->a[4]) ==
+		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ;
+}
+
+int is_zero(addr)
+struct fddi_addr *addr ;
+{
+	return(*(short *)(&addr->a[0]) == 0 &&
+	       *(short *)(&addr->a[2]) == 0 &&
+	       *(short *)(&addr->a[4]) == 0 ) ;
+}
+
+int is_broadcast(addr)
+struct fddi_addr *addr ;
+{
+	return(*(u_short *)(&addr->a[0]) == 0xffff &&
+	       *(u_short *)(&addr->a[2]) == 0xffff &&
+	       *(u_short *)(&addr->a[4]) == 0xffff ) ;
+}
+
+int is_individual(addr)
+struct fddi_addr *addr ;
+{
+	return(!(addr->a[0] & GROUP_ADDR)) ;
+}
+
+int is_equal(addr1,addr2)
+struct fddi_addr *addr1 ;
+struct fddi_addr *addr2 ;
+{
+	return(*(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) &&
+	       *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) &&
+	       *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]) ) ;
+}
+
+
+#if	0
+/*
+ * send ANTC data test frame
+ */
+void fddi_send_antc(smc,dest)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dest) ;
+#if	0
+	SMbuf			*mb ;
+	struct smt_header	*smt ;
+	int			i ;
+	char			*p ;
+
+	mb = smt_get_mbuf() ;
+	mb->sm_len = 3000+12 ;
+	p = smtod(mb, char *) + 12 ;
+	for (i = 0 ; i < 3000 ; i++)
+		*p++ = 1 << (i&7) ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = *dest ;
+	smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
+	smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ;
+#endif
+}
+#endif
+
+#ifdef	DEBUG
+#define hextoasc(x)	"0123456789abcdef"[x]
+
+char *addr_to_string(addr)
+struct fddi_addr *addr ;
+{
+	int	i ;
+	static char	string[6*3] = "****" ;
+
+	for (i = 0 ; i < 6 ; i++) {
+		string[i*3] = hextoasc((addr->a[i]>>4)&0xf) ;
+		string[i*3+1] = hextoasc((addr->a[i])&0xf) ;
+		string[i*3+2] = ':' ;
+	}
+	string[5*3+2] = 0 ;
+	return(string) ;
+}
+#endif
+
+#ifdef	AM29K
+smt_ifconfig(argc,argv)
+int argc ;
+char *argv[] ;
+{
+	if (argc >= 2 && !strcmp(argv[0],"opt_bypass") &&
+	    !strcmp(argv[1],"yes")) {
+		smc->mib.fddiSMTBypassPresent = 1 ;
+		return(0) ;
+	}
+	return(amdfddi_config(0,argc,argv)) ;
+}
+#endif
+
+/*
+ * return static mac index
+ */
+static int mac_index(smc,mac)
+struct s_smc *smc ;
+int mac ;
+{
+	SK_UNUSED(mac) ;
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+	return(NUMPHYS+1) ;
+#else
+	return((smc->s.sas == SMT_SAS) ? 2 : 3) ;
+#endif
+}
+
+/*
+ * return static phy index
+ */
+static int phy_index(smc,phy)
+struct s_smc *smc ;
+int phy ;
+{
+	SK_UNUSED(smc) ;
+	return(phy+1);
+}
+
+/*
+ * return dynamic mac connection resource index
+ */
+static int mac_con_resource_index(smc,mac)
+struct s_smc *smc ;
+int mac ;
+{
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+	SK_UNUSED(mac) ;
+	return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_MAC))) ;
+#else
+	SK_UNUSED(mac) ;
+	switch (smc->mib.fddiSMTCF_State) {
+	case SC9_C_WRAP_A :
+	case SC5_THRU_B :
+	case SC11_C_WRAP_S :
+		return(1) ;
+	case SC10_C_WRAP_B :
+	case SC4_THRU_A :
+		return(2) ;
+	}
+	return(smc->s.sas == SMT_SAS ? 2 : 3) ;
+#endif
+}
+
+/*
+ * return dynamic phy connection resource index
+ */
+static int phy_con_resource_index(smc,phy)
+struct s_smc *smc ;
+int phy ;
+{
+#ifdef	CONCENTRATOR
+	return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_PHY(phy)))) ;
+#else
+	switch (smc->mib.fddiSMTCF_State) {
+	case SC9_C_WRAP_A :
+		return(phy == PA ? 3 : 2) ;
+	case SC10_C_WRAP_B :
+		return(phy == PA ? 1 : 3) ;
+	case SC4_THRU_A :
+		return(phy == PA ? 3 : 1) ;
+	case SC5_THRU_B :
+		return(phy == PA ? 2 : 3) ;
+	case SC11_C_WRAP_S :
+		return(2) ;
+	}
+	return(phy) ;
+#endif
+}
+
+#ifdef	CONCENTRATOR
+static int entity_to_index(smc,e)
+struct s_smc *smc ;
+int e ;
+{
+	if (e == ENTITY_MAC)
+		return(mac_index(smc,1)) ;
+	else
+		return(phy_index(smc,e - ENTITY_PHY(0))) ;
+}
+#endif
+
+#ifdef	LITTLE_ENDIAN
+static int smt_swap_short(s)
+u_short s ;
+{
+	return(((s>>8)&0xff)|((s&0xff)<<8)) ;
+}
+
+void smt_swap_para(sm,len,direction)
+struct smt_header *sm ;
+int len ;
+int direction ;			/* 0 encode 1 decode */
+{
+	struct smt_para	*pa ;
+	const  struct smt_pdef	*pd ;
+	char	*p ;
+	int	plen ;
+	int	type ;
+	int	i ;
+
+/*	printf("smt_swap_para sm %x len %d dir %d\n",
+		sm,len,direction) ;
+ */
+	smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ;
+
+	/* swap args */
+	len -= sizeof(struct smt_header) ;
+
+	p = (char *) (sm + 1) ;
+	while (len > 0) {
+		pa = (struct smt_para *) p ;
+		plen = pa->p_len ;
+		type = pa->p_type ;
+		pa->p_type = smt_swap_short(pa->p_type) ;
+		pa->p_len = smt_swap_short(pa->p_len) ;
+		if (direction) {
+			plen = pa->p_len ;
+			type = pa->p_type ;
+		}
+		/*
+		 * note: paras can have 0 length !
+		 */
+		if (plen < 0)
+			break ;
+		plen += PARA_LEN ;
+		for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) {
+			if (pd->ptype == type)
+				break ;
+		}
+		if (i && pd->pswap) {
+			smt_string_swap(p+PARA_LEN,pd->pswap,len) ;
+		}
+		len -= plen ;
+		p += plen ;
+	}
+}
+
+static void smt_string_swap(data,format,len)
+char *data ;
+const char *format ;
+int len ;
+{
+	const char	*open_paren = 0 ;
+	int	x ;
+
+	while (len > 0  && *format) {
+		switch (*format) {
+		case '[' :
+			open_paren = format ;
+			break ;
+		case ']' :
+			format = open_paren ;
+			break ;
+		case '1' :
+		case '2' :
+		case '3' :
+		case '4' :
+		case '5' :
+		case '6' :
+		case '7' :
+		case '8' :
+		case '9' :
+			data  += *format - '0' ;
+			len   -= *format - '0' ;
+			break ;
+		case 'c':
+			data++ ;
+			len-- ;
+			break ;
+		case 's' :
+			x = data[0] ;
+			data[0] = data[1] ;
+			data[1] = x ;
+			data += 2 ;
+			len -= 2 ;
+			break ;
+		case 'l' :
+			x = data[0] ;
+			data[0] = data[3] ;
+			data[3] = x ;
+			x = data[1] ;
+			data[1] = data[2] ;
+			data[2] = x ;
+			data += 4 ;
+			len -= 4 ;
+			break ;
+		}
+		format++ ;
+	}
+}
+#else
+void smt_swap_para(sm,len,direction)
+struct smt_header *sm ;
+int len ;
+int direction ;			/* 0 encode 1 decode */
+{
+	SK_UNUSED(sm) ;
+	SK_UNUSED(len) ;
+	SK_UNUSED(direction) ;
+}
+#endif
+
+/*
+ * PMF actions
+ */
+int smt_action(smc,class,code,index)
+struct s_smc *smc ;
+int class ;
+int code ;
+int index ;
+{
+	int	event ;
+	int	port ;
+	DB_SMT("SMT: action %d code %d\n",class,code) ;
+	switch(class) {
+	case SMT_STATION_ACTION :
+		switch(code) {
+		case SMT_STATION_ACTION_CONNECT :
+			smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
+			queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+			break ;
+		case SMT_STATION_ACTION_DISCONNECT :
+			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+			smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ;
+			RS_SET(smc,RS_DISCONNECT) ;
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT,
+				smt_get_event_word(smc));
+			break ;
+		case SMT_STATION_ACTION_PATHTEST :
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST,
+				smt_get_event_word(smc));
+			break ;
+		case SMT_STATION_ACTION_SELFTEST :
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST,
+				smt_get_event_word(smc));
+			break ;
+		case SMT_STATION_ACTION_DISABLE_A :
+			if (smc->y[PA].pc_mode == PM_PEER) {
+				RS_SET(smc,RS_EVENT) ;
+				queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ;
+			}
+			break ;
+		case SMT_STATION_ACTION_DISABLE_B :
+			if (smc->y[PB].pc_mode == PM_PEER) {
+				RS_SET(smc,RS_EVENT) ;
+				queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ;
+			}
+			break ;
+		case SMT_STATION_ACTION_DISABLE_M :
+			for (port = 0 ; port <  NUMPHYS ; port++) {
+				if (smc->mib.p[port].fddiPORTMy_Type != TM)
+					continue ;
+				RS_SET(smc,RS_EVENT) ;
+				queue_event(smc,EVENT_PCM+port,PC_DISABLE) ;
+			}
+			break ;
+		default :
+			return(1) ;
+		}
+		break ;
+	case SMT_PORT_ACTION :
+		switch(code) {
+		case SMT_PORT_ACTION_ENABLE :
+			event = PC_ENABLE ;
+			break ;
+		case SMT_PORT_ACTION_DISABLE :
+			event = PC_DISABLE ;
+			break ;
+		case SMT_PORT_ACTION_MAINT :
+			event = PC_MAINT ;
+			break ;
+		case SMT_PORT_ACTION_START :
+			event = PC_START ;
+			break ;
+		case SMT_PORT_ACTION_STOP :
+			event = PC_STOP ;
+			break ;
+		default :
+			return(1) ;
+		}
+		queue_event(smc,EVENT_PCM+index,event) ;
+		break ;
+	default :
+		return(1) ;
+	}
+	return(0) ;
+}
+
+/*
+ * change tneg
+ *	set T_Req in MIB (Path Attribute)
+ *	calculate new values for MAC
+ *	if change required
+ *		disconnect
+ *		set reconnect
+ *	end
+ */
+void smt_change_t_neg(smc,tneg)
+struct s_smc *smc ;
+u_long tneg ;
+{
+	smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
+
+	if (smt_set_mac_opvalues(smc)) {
+		RS_SET(smc,RS_EVENT) ;
+		smc->sm.please_reconnect = 1 ;
+		queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+	}
+}
+
+/*
+ * canonical conversion of <len> bytes beginning form *data
+ */
+#ifdef  USE_CAN_ADDR
+void hwm_conv_can(smc,data,len)
+struct s_smc *smc ;
+char *data ;
+int len ;
+{
+	int i ;
+
+	SK_UNUSED(smc) ;
+
+	for (i = len; i ; i--, data++) {
+		*data = canonical[*(u_char *)data] ;
+	}
+}
+#endif
+
+#endif	/* no SLIM_SMT */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smtdef.c linux/drivers/net/skfp/smtdef.c
--- v2.3.46/linux/drivers/net/skfp/smtdef.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/smtdef.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,371 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT/CMT defaults
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef OEM_USER_DATA
+#define OEM_USER_DATA	"SK-NET FDDI V2.0 Userdata"
+#endif
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smtdef.c	2.53 99/08/11 (C) SK " ;
+#endif
+
+/*
+ * defaults
+ */
+#define TTMS(x)	((u_long)(x)*1000L)
+#define TTS(x)	((u_long)(x)*1000000L)
+#define TTUS(x)	((u_long)(x))
+
+#define DEFAULT_TB_MIN		TTMS(5)
+#define DEFAULT_TB_MAX		TTMS(50)
+#define DEFAULT_C_MIN		TTUS(1600)
+#define DEFAULT_T_OUT		TTMS(100+5)
+#define DEFAULT_TL_MIN		TTUS(30)
+#define DEFAULT_LC_SHORT	TTMS(50+5)
+#define DEFAULT_LC_MEDIUM	TTMS(500+20)
+#define DEFAULT_LC_LONG		TTS(5)+TTMS(50)
+#define DEFAULT_LC_EXTENDED	TTS(50)+TTMS(50)
+#define DEFAULT_T_NEXT_9	TTMS(200+10)
+#define DEFAULT_NS_MAX		TTUS(1310)
+#define DEFAULT_I_MAX		TTMS(25)
+#define DEFAULT_IN_MAX		TTMS(40)
+#define DEFAULT_TD_MIN		TTMS(5)
+#define DEFAULT_T_NON_OP	TTS(1)
+#define DEFAULT_T_STUCK		TTS(8)
+#define DEFAULT_T_DIRECT	TTMS(370)
+#define DEFAULT_T_JAM		TTMS(370)
+#define DEFAULT_T_ANNOUNCE	TTMS(2500)
+#define DEFAULT_D_MAX		TTUS(1617)
+#define DEFAULT_LEM_ALARM	(8)
+#define DEFAULT_LEM_CUTOFF	(7)
+#define DEFAULT_TEST_DONE	TTS(1)
+#define DEFAULT_CHECK_POLL	TTS(1)
+#define DEFAULT_POLL		TTMS(50)
+
+/*
+ * LCT errors threshold
+ */
+#define DEFAULT_LCT_SHORT	1
+#define DEFAULT_LCT_MEDIUM	3
+#define DEFAULT_LCT_LONG	5
+#define DEFAULT_LCT_EXTEND	50
+
+/* Forward declarations */
+extern  void	smt_reset_defaults ();
+static	void	smt_init_mib ();
+
+static int set_min_max() ;
+
+void smt_set_defaults(smc)
+struct s_smc *smc ;
+{
+	smt_reset_defaults(smc,0) ;
+}
+
+#define MS2BCLK(x)	((x)*12500L)
+#define US2BCLK(x)	((x)*1250L)
+
+void smt_reset_defaults(smc,level)
+struct s_smc *smc ;
+int level ;
+{
+	struct smt_config	*smt ;
+	int			i ;
+	u_long			smt_boot_time;
+
+
+	smt_init_mib(smc,level) ;
+
+	smc->os.smc_version = SMC_VERSION ;
+	smt_boot_time = smt_get_time();
+	for( i = 0; i < NUMMACS; i++ )
+		smc->sm.last_tok_time[i] = smt_boot_time ;
+	smt = &smc->s ;
+	smt->attach_s = 0 ;
+	smt->build_ring_map = 1 ;
+	smt->sas = SMT_DAS ;
+	smt->numphys = NUMPHYS ;
+	smt->pcm_tb_min = DEFAULT_TB_MIN ;
+	smt->pcm_tb_max = DEFAULT_TB_MAX ;
+	smt->pcm_c_min = DEFAULT_C_MIN ;
+	smt->pcm_t_out = DEFAULT_T_OUT ;
+	smt->pcm_tl_min = DEFAULT_TL_MIN ;
+	smt->pcm_lc_short = DEFAULT_LC_SHORT ;
+	smt->pcm_lc_medium = DEFAULT_LC_MEDIUM ;
+	smt->pcm_lc_long = DEFAULT_LC_LONG ;
+	smt->pcm_lc_extended = DEFAULT_LC_EXTENDED ;
+	smt->pcm_t_next_9 = DEFAULT_T_NEXT_9 ;
+	smt->pcm_ns_max = DEFAULT_NS_MAX ;
+	smt->ecm_i_max = DEFAULT_I_MAX ;
+	smt->ecm_in_max = DEFAULT_IN_MAX ;
+	smt->ecm_td_min = DEFAULT_TD_MIN ;
+	smt->ecm_test_done = DEFAULT_TEST_DONE ;
+	smt->ecm_check_poll = DEFAULT_CHECK_POLL ;
+	smt->rmt_t_non_op = DEFAULT_T_NON_OP ;
+	smt->rmt_t_stuck = DEFAULT_T_STUCK ;
+	smt->rmt_t_direct = DEFAULT_T_DIRECT ;
+	smt->rmt_t_jam = DEFAULT_T_JAM ;
+	smt->rmt_t_announce = DEFAULT_T_ANNOUNCE ;
+	smt->rmt_t_poll = DEFAULT_POLL ;
+        smt->rmt_dup_mac_behavior = FALSE ;  /* See Struct smt_config */
+	smt->mac_d_max = DEFAULT_D_MAX ;
+
+	smt->lct_short = DEFAULT_LCT_SHORT ;
+	smt->lct_medium = DEFAULT_LCT_MEDIUM ;
+	smt->lct_long = DEFAULT_LCT_LONG ;
+	smt->lct_extended = DEFAULT_LCT_EXTEND ;
+
+#ifndef	SLIM_SMT
+#ifdef	ESS
+	if (level == 0) {
+		smc->ess.sync_bw_available = FALSE ;
+		smc->mib.fddiESSPayload = 0 ;
+		smc->mib.fddiESSOverhead = 0 ;
+		smc->mib.fddiESSMaxTNeg = (u_long)(- MS2BCLK(25)) ;
+		smc->mib.fddiESSMinSegmentSize = 1 ;
+		smc->mib.fddiESSCategory = SB_STATIC ;
+		smc->mib.fddiESSSynchTxMode = FALSE ;
+		smc->ess.raf_act_timer_poll = FALSE ;
+		smc->ess.timer_count = 7 ; 	/* first RAF alc req after 3s */
+	}
+	smc->ess.local_sba_active = FALSE ;
+	smc->ess.sba_reply_pend = NULL ;
+#endif
+#ifdef	SBA
+	smt_init_sba(smc,level) ;
+#endif
+#endif	/* no SLIM_SMT */
+#ifdef	TAG_MODE
+	if (level == 0) {
+		smc->hw.pci_fix_value = 0 ;
+	}
+#endif
+}
+
+/*
+ * manufacturer data
+ */
+static const char man_data[32] =
+/*	 01234567890123456789012345678901	*/
+	"xxxSK-NET FDDI SMT 7.3 - V2.8.8" ;
+
+static void smt_init_mib(smc,level)
+struct s_smc *smc ;
+int level ;
+{
+	struct fddi_mib		*mib ;
+	struct fddi_mib_p	*pm ;
+	int			port ;
+	int			path ;
+
+	mib = &smc->mib ;
+	if (level == 0) {
+		/*
+		 * set EVERYTHING to ZERO
+		 * EXCEPT hw and os
+		 */
+		memset(((char *)smc)+
+			sizeof(struct s_smt_os)+sizeof(struct s_smt_hw), 0,
+			sizeof(struct s_smc) -
+			sizeof(struct s_smt_os) - sizeof(struct s_smt_hw)) ;
+	}
+	else {
+		mib->fddiSMTRemoteDisconnectFlag = 0 ;
+		mib->fddiSMTPeerWrapFlag = 0 ;
+	}
+
+	mib->fddiSMTOpVersionId = 2 ;
+	mib->fddiSMTHiVersionId = 2 ;
+	mib->fddiSMTLoVersionId = 2 ;
+	memcpy((char *) mib->fddiSMTManufacturerData,man_data,32) ;
+	if (level == 0) {
+		strcpy(mib->fddiSMTUserData,OEM_USER_DATA) ;
+	}
+	mib->fddiSMTMIBVersionId = 1 ;
+	mib->fddiSMTMac_Ct = NUMMACS ;
+	mib->fddiSMTConnectionPolicy = POLICY_MM | POLICY_AA | POLICY_BB ;
+
+	/*
+	 * fddiSMTNonMaster_Ct and fddiSMTMaster_Ct are set in smt_fixup_mib
+	 * s.sas is not set yet (is set in init driver)
+	 */
+	mib->fddiSMTAvailablePaths = MIB_PATH_P | MIB_PATH_S ;
+
+	mib->fddiSMTConfigCapabilities = 0 ;	/* no hold,no wrap_ab*/
+	mib->fddiSMTTT_Notify = 10 ;
+	mib->fddiSMTStatRptPolicy = TRUE ;
+	mib->fddiSMTTrace_MaxExpiration = SEC2MIB(7) ;
+	mib->fddiSMTMACIndexes = INDEX_MAC ;
+	mib->fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;	/* seperated */
+
+	mib->m[MAC0].fddiMACIndex = INDEX_MAC ;
+	mib->m[MAC0].fddiMACFrameStatusFunctions = FSC_TYPE0 ;
+	mib->m[MAC0].fddiMACRequestedPaths =
+		MIB_P_PATH_LOCAL |
+		MIB_P_PATH_SEC_ALTER |
+		MIB_P_PATH_PRIM_ALTER ;
+	mib->m[MAC0].fddiMACAvailablePaths = MIB_PATH_P ;
+	mib->m[MAC0].fddiMACCurrentPath = MIB_PATH_PRIMARY ;
+	mib->m[MAC0].fddiMACT_MaxCapabilitiy = (u_long)(- MS2BCLK(165)) ;
+	mib->m[MAC0].fddiMACTVXCapabilitiy = (u_long)(- US2BCLK(52)) ;
+	if (level == 0) {
+		mib->m[MAC0].fddiMACTvxValue = (u_long)(- US2BCLK(27)) ;
+		mib->m[MAC0].fddiMACTvxValueMIB = (u_long)(- US2BCLK(27)) ;
+		mib->m[MAC0].fddiMACT_Req = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_ReqMIB = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_Max = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_MaxMIB = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_Min = (u_long)(- MS2BCLK(4)) ;
+	}
+	mib->m[MAC0].fddiMACHardwarePresent = TRUE ;
+	mib->m[MAC0].fddiMACMA_UnitdataEnable = TRUE ;
+	mib->m[MAC0].fddiMACFrameErrorThreshold = 1 ;
+	mib->m[MAC0].fddiMACNotCopiedThreshold = 1 ;
+	/*
+	 * Path attributes
+	 */
+	for (path = 0 ; path < NUMPATHS ; path++) {
+		mib->a[path].fddiPATHIndex = INDEX_PATH + path ;
+		if (level == 0) {
+			mib->a[path].fddiPATHTVXLowerBound =
+				(u_long)(- US2BCLK(27)) ;
+			mib->a[path].fddiPATHT_MaxLowerBound =
+				(u_long)(- MS2BCLK(165)) ;
+			mib->a[path].fddiPATHMaxT_Req =
+				(u_long)(- MS2BCLK(165)) ;
+		}
+	}
+
+
+	/*
+	 * Port attributes
+	 */
+	pm = mib->p ;
+	for (port = 0 ; port <  NUMPHYS ; port++) {
+		/*
+		 * set MIB pointer in phy
+		 */
+		/* Attention: don't initialize mib pointer here! */
+		/*  It must be initialized during phase 2 */
+		smc->y[port].mib = 0 ;
+		mib->fddiSMTPORTIndexes[port] = port+INDEX_PORT ;
+
+		pm->fddiPORTIndex = port+INDEX_PORT ;
+		pm->fddiPORTHardwarePresent = TRUE ;
+		if (level == 0) {
+			pm->fddiPORTLer_Alarm = DEFAULT_LEM_ALARM ;
+			pm->fddiPORTLer_Cutoff = DEFAULT_LEM_CUTOFF ;
+		}
+		/*
+		 * fddiPORTRequestedPaths are set in pcmplc.c
+		 * we don't know the port type yet !
+		 */
+		pm->fddiPORTRequestedPaths[1] = 0 ;
+		pm->fddiPORTRequestedPaths[2] = 0 ;
+		pm->fddiPORTRequestedPaths[3] = 0 ;
+		pm->fddiPORTAvailablePaths = MIB_PATH_P ;
+		pm->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
+		pm++ ;
+	}
+
+	(void) smt_set_mac_opvalues(smc) ;
+}
+
+int smt_set_mac_opvalues(smc)
+struct s_smc *smc ;
+{
+	int	st ;
+	int	st2 ;
+
+	st = set_min_max(1,smc->mib.m[MAC0].fddiMACTvxValueMIB,
+		smc->mib.a[PATH0].fddiPATHTVXLowerBound,
+		&smc->mib.m[MAC0].fddiMACTvxValue) ;
+	st |= set_min_max(0,smc->mib.m[MAC0].fddiMACT_MaxMIB,
+		smc->mib.a[PATH0].fddiPATHT_MaxLowerBound,
+		&smc->mib.m[MAC0].fddiMACT_Max) ;
+	st |= (st2 = set_min_max(0,smc->mib.m[MAC0].fddiMACT_ReqMIB,
+		smc->mib.a[PATH0].fddiPATHMaxT_Req,
+		&smc->mib.m[MAC0].fddiMACT_Req)) ;
+	if (st2) {
+		/* Treq attribute changed remotely. So send an AIX_EVENT to the
+		 * user
+		 */
+		AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+			FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ,
+			smt_get_event_word(smc));
+	}
+	return(st) ;
+}
+
+void smt_fixup_mib(smc)
+struct s_smc *smc ;
+{
+#ifdef	CONCENTRATOR
+	switch (smc->s.sas) {
+	case SMT_SAS :
+		smc->mib.fddiSMTNonMaster_Ct = 1 ;
+		break ;
+	case SMT_DAS :
+		smc->mib.fddiSMTNonMaster_Ct = 2 ;
+		break ;
+	case SMT_NAC :
+		smc->mib.fddiSMTNonMaster_Ct = 0 ;
+		break ;
+	}
+	smc->mib.fddiSMTMaster_Ct = NUMPHYS - smc->mib.fddiSMTNonMaster_Ct ;
+#else
+	switch (smc->s.sas) {
+	case SMT_SAS :
+		smc->mib.fddiSMTNonMaster_Ct = 1 ;
+		break ;
+	case SMT_DAS :
+		smc->mib.fddiSMTNonMaster_Ct = 2 ;
+		break ;
+	}
+	smc->mib.fddiSMTMaster_Ct = 0 ;
+#endif
+}
+
+/*
+ * determine new setting for operational value
+ * if limit is lower than mib
+ *	use limit
+ * else
+ *	use mib
+ * NOTE : numbers are negative, negate comparison !
+ */
+static int set_min_max(maxflag,mib,limit,oper)
+int maxflag ;
+u_long mib ;
+u_long limit ;
+u_long *oper ;
+{
+	u_long	old ;
+	old = *oper ;
+	if ((limit > mib) ^ maxflag)
+		*oper = limit ;
+	else
+		*oper = mib ;
+	return(old != *oper) ;
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smtinit.c linux/drivers/net/skfp/smtinit.c
--- v2.3.46/linux/drivers/net/skfp/smtinit.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/smtinit.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	Init SMT
+	call all module level initialization routines
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smtinit.c	1.15 97/05/06 (C) SK " ;
+#endif
+
+extern void init_fddi_driver() ;
+
+/* define global debug variable */
+#if defined(DEBUG) && !defined(DEBUG_BRD)
+struct smt_debug debug;
+#endif
+
+#ifndef MULT_OEM
+#define OEMID(smc,i)	oem_id[i]
+	extern u_char	oem_id[] ;
+#else	/* MULT_OEM */
+#define OEMID(smc,i)	smc->hw.oem_id->oi_mark[i]
+	extern struct s_oem_ids	oem_ids[] ;
+#endif	/* MULT_OEM */
+
+/*
+ * Set OEM specific values
+ *
+ * Can not be called in smt_reset_defaults, because it is not sure that
+ * the OEM ID is already defined.
+ */
+static void set_oem_spec_val(smc)
+struct s_smc *smc ;
+{
+	struct fddi_mib *mib ;
+
+	mib = &smc->mib ;
+
+	/*
+	 * set IBM specific values
+	 */
+	if (OEMID(smc,0) == 'I') {
+		mib->fddiSMTConnectionPolicy = POLICY_MM ;
+	}
+}
+
+/*
+ * Init SMT
+ */
+int init_smt(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;		/* canonical address or NULL */
+{
+	int	p ;
+
+#if defined(DEBUG) && !defined(DEBUG_BRD)
+	debug.d_smt = 0 ;
+	debug.d_smtf = 0 ;
+	debug.d_rmt = 0 ;
+	debug.d_ecm = 0 ;
+	debug.d_pcm = 0 ;
+	debug.d_cfm = 0 ;
+
+	debug.d_plc = 0 ;
+#ifdef	ESS
+	debug.d_ess = 0 ;
+#endif
+#ifdef	SBA
+	debug.d_sba = 0 ;
+#endif
+#endif	/* DEBUG && !DEBUG_BRD */
+
+	/* First initialize the ports mib->pointers */
+	for ( p = 0; p < NUMPHYS; p ++ ) {
+		smc->y[p].mib = & smc->mib.p[p] ;
+	}
+
+	set_oem_spec_val(smc) ;	
+	(void) smt_set_mac_opvalues(smc) ;
+	init_fddi_driver(smc,mac_addr) ;	/* HW driver */
+	smt_fixup_mib(smc) ;		/* update values that depend on s.sas */
+
+	ev_init(smc) ;			/* event queue */
+#ifndef	SLIM_SMT
+	smt_init_evc(smc) ;		/* evcs in MIB */
+#endif	/* no SLIM_SMT */
+	smt_timer_init(smc) ;		/* timer package */
+	smt_agent_init(smc) ;		/* SMT frame manager */
+
+	pcm_init(smc) ;			/* PCM state machine */
+	ecm_init(smc) ;			/* ECM state machine */
+	cfm_init(smc) ;			/* CFM state machine */
+	rmt_init(smc) ;			/* RMT state machine */
+
+	for (p = 0 ; p < NUMPHYS ; p++) {
+		pcm(smc,p,0) ;		/* PCM A state machine */
+	}
+	ecm(smc,0) ;			/* ECM state machine */
+	cfm(smc,0) ;			/* CFM state machine */
+	rmt(smc,0) ;			/* RMT state machine */
+
+	smt_agent_task(smc) ;		/* NIF FSM etc */
+
+        PNMI_INIT(smc) ;                /* PNMI initialization */
+
+	return(0) ;
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smtparse.c linux/drivers/net/skfp/smtparse.c
--- v2.3.46/linux/drivers/net/skfp/smtparse.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/smtparse.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,475 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+/*
+	parser for SMT parameters
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smtparse.c	1.12 98/10/06 (C) SK " ;
+#endif
+
+#ifdef	sun
+#define _far
+#endif
+
+/*
+ * convert to BCLK units
+ */
+#define MS2BCLK(x)      ((x)*12500L)
+#define US2BCLK(x)      ((x/10)*125L)
+
+/*
+ * parameter table
+ */
+static struct s_ptab {
+	char	*pt_name ;
+	u_short	pt_num ;
+	u_short	pt_type ;
+	u_long	pt_min ;
+	u_long	pt_max ;
+} ptab[] = {
+	{ "PMFPASSWD",0,	0 } ,
+	{ "USERDATA",1,		0 } ,
+	{ "LERCUTOFFA",2,	1,	4,	15	} ,
+	{ "LERCUTOFFB",3,	1,	4,	15	} ,
+	{ "LERALARMA",4,	1,	4,	15	} ,
+	{ "LERALARMB",5,	1,	4,	15	} ,
+	{ "TMAX",6,		1,	5,	165	} ,
+	{ "TMIN",7,		1,	5,	165	} ,
+	{ "TREQ",8,		1,	5,	165	} ,
+	{ "TVX",9,		1,	2500,	10000	} ,
+#ifdef ESS
+	{ "SBAPAYLOAD",10,	1,	0,	1562	} ,
+	{ "SBAOVERHEAD",11,	1,	50,	5000	} ,
+	{ "MAXTNEG",12,		1,	5,	165	} ,
+	{ "MINSEGMENTSIZE",13,	1,	0,	4478	} ,
+	{ "SBACATEGORY",14,	1,	0,	0xffff	} ,
+	{ "SYNCHTXMODE",15,	0 } ,
+#endif
+#ifdef SBA
+	{ "SBACOMMAND",16,	0 } ,
+	{ "SBAAVAILABLE",17,	1,	0,	100	} ,
+#endif
+	{ 0 }
+} ;
+
+/* Define maximum string size for values and keybuffer */
+#define MAX_VAL	40
+
+/*
+ * local function declarations
+ */
+static u_long parse_num() ;
+static int parse_word() ;
+
+#ifdef SIM
+#define DB_MAIN(a,b,c)	printf(a,b,c)
+#else
+#define DB_MAIN(a,b,c)
+#endif
+
+/*
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
+		char _far *value)
+ *
+ *	parse SMT parameter
+ *	*keyword
+ *		pointer to keyword, must be \0, \n or \r terminated
+ *	*value	pointer to value, either char * or u_long *
+ *		if char *
+ *			pointer to value, must be \0, \n or \r terminated
+ *		if u_long *
+ *			contains binary value
+ *
+ *	type	0: integer
+ *		1: string
+ *	return
+ *		0	parameter parsed ok
+ *		!= 0	error
+ *	NOTE:
+ *		function can be called with DS != SS
+ *
+ *
+ * END_MANUAL_ENTRY()
+ */
+int smt_parse_arg(smc,keyword,type,value)
+struct s_smc *smc ;
+char _far *keyword ;
+int type ;
+char _far *value ;
+{
+	char		keybuf[MAX_VAL+1];
+	char		valbuf[MAX_VAL+1];
+	char		c ;
+	char 		*p ;
+	char		*v ;
+	char		*d ;
+	u_long		val = 0 ;
+	struct s_ptab	*pt ;
+	int		st ;
+	int		i ;
+
+	/*
+	 * parse keyword
+	 */
+	if ((st = parse_word(keybuf,keyword)))
+		return(st) ;
+	/*
+	 * parse value if given as string
+	 */
+	if (type == 1) {
+		if ((st = parse_word(valbuf,value)))
+			return(st) ;
+	}
+	/*
+	 * search in table
+	 */
+	st = 0 ;
+	for (pt = ptab ; (v = pt->pt_name) ; pt++) {
+		for (p = keybuf ; (c = *p) ; p++,v++) {
+			if (c != *v)
+				break ;
+		}
+		if (!c && !*v)
+			break ;
+	}
+	if (!v)
+		return(-1) ;
+#if	0
+	printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
+#endif
+	/*
+	 * set value in MIB
+	 */
+	if (pt->pt_type)
+		val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
+	switch (pt->pt_num) {
+	case 0 :
+		v = valbuf ;
+		d = (char *) smc->mib.fddiPRPMFPasswd ;
+		for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
+			*d++ = *v++ ;
+		DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
+		break ;
+	case 1 :
+		v = valbuf ;
+		d = (char *) smc->mib.fddiSMTUserData ;
+		for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
+			*d++ = *v++ ;
+		DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
+		break ;
+	case 2 :
+		smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
+		break ;
+	case 3 :
+		smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
+		break ;
+	case 4 :
+		smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
+		break ;
+	case 5 :
+		smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
+		break ;
+	case 6 :			/* TMAX */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
+			(u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 7 :			/* TMIN */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.m[MAC0].fddiMACT_Min =
+			(u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 8 :			/* TREQ */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.a[PATH0].fddiPATHMaxT_Req =
+			(u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 9 :			/* TVX */
+		DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
+		smc->mib.a[PATH0].fddiPATHTVXLowerBound =
+			(u_long) -US2BCLK((long)val) ;
+		break ;
+#ifdef	ESS
+	case 10 :			/* SBAPAYLOAD */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		if (smc->mib.fddiESSPayload != val) {
+			smc->ess.raf_act_timer_poll = TRUE ;
+			smc->mib.fddiESSPayload = val ;
+		}
+		break ;
+	case 11 :			/* SBAOVERHEAD */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSOverhead = val ;
+		break ;
+	case 12 :			/* MAXTNEG */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 13 :			/* MINSEGMENTSIZE */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSMinSegmentSize = val ;
+		break ;
+	case 14 :			/* SBACATEGORY */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSCategory =
+			(smc->mib.fddiESSCategory & 0xffff) |
+			((u_long)(val << 16)) ;
+		break ;
+	case 15 :			/* SYNCHTXMODE */
+		/* do not use memcmp(valbuf,"ALL",3) because DS != SS */
+		if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
+			smc->mib.fddiESSSynchTxMode = TRUE ;
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+		}
+		/* if (!memcmp(valbuf,"SPLIT",5)) { */
+		if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
+			valbuf[3] == 'I' && valbuf[4] == 'T') {
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+			smc->mib.fddiESSSynchTxMode = FALSE ;
+		}
+		break ;
+#endif
+#ifdef	SBA
+	case 16 :			/* SBACOMMAND */
+		/* if (!memcmp(valbuf,"START",5)) { */
+		if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
+			valbuf[3] == 'R' && valbuf[4] == 'T') {
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+			smc->mib.fddiSBACommand = SB_START ;
+		}
+		/* if (!memcmp(valbuf,"STOP",4)) { */
+		if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
+			valbuf[3] == 'P') {
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+			smc->mib.fddiSBACommand = SB_STOP ;
+		}
+		break ;
+	case 17 :			/* SBAAVAILABLE */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiSBAAvailable = (u_char) val ;
+		break ;
+#endif
+	}
+	return(0) ;
+}
+
+static int parse_word(buf,text)
+char *buf ;
+char _far *text ;
+{
+	char		c ;
+	char 		*p ;
+	int		p_len ;
+	int		quote ;
+	int		i ;
+	int		ok ;
+
+	/*
+	 * skip leading white space
+	 */
+	p = buf ;
+	for (i = 0 ; i < MAX_VAL ; i++)
+		*p++ = 0 ;
+	p = buf ;
+	p_len = 0 ;
+	ok = 0 ;
+	while ( (c = *text++) && (c != '\n') && (c != '\r')) {
+		if ((c != ' ') && (c != '\t')) {
+			ok = 1 ;
+			break ;
+		}
+	}
+	if (!ok)
+		return(-1) ;
+	if (c == '"') {
+		quote = 1 ;
+	}
+	else {
+		quote = 0 ;
+		text-- ;
+	}
+	/*
+	 * parse valbuf
+	 */
+	ok = 0 ;
+	while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
+		&& (c != '\r')) {
+		switch (quote) {
+		case 0 :
+			if ((c == ' ') || (c == '\t') || (c == '=')) {
+				ok = 1 ;
+				break ;
+			}
+			*p++ = c ;
+			p_len++ ;
+			break ;
+		case 2 :
+			*p++ = c ;
+			p_len++ ;
+			quote = 1 ;
+			break ;
+		case 1 :
+			switch (c) {
+			case '"' :
+				ok = 1 ;
+				break ;
+			case '\\' :
+				quote = 2 ;
+				break ;
+			default :
+				*p++ = c ;
+				p_len++ ;
+			}
+		}
+	}
+	*p++ = 0 ;
+	for (p = buf ; (c = *p) ; p++) {
+		if (c >= 'a' && c <= 'z')
+			*p = c + 'A' - 'a' ;
+	}
+	return(0) ;
+}
+
+static u_long parse_num(type,value,v,mn,mx,scale)
+int type ;
+char _far *value ;
+char *v ;
+u_long mn ;
+u_long mx ;
+int scale ;
+{
+	u_long	x = 0 ;
+	char	c ;
+
+	if (type == 0) {		/* integer */
+		u_long _far	*l ;
+		u_long		u1 ;
+
+		l = (u_long _far *) value ;
+		u1 = *l ;
+		/*
+		 * if the value is negative take the lower limit
+		 */
+		if ((long)u1 < 0) {
+			if (- ((long)u1) > (long) mx) {
+				u1 = 0 ;
+			}
+			else {
+				u1 = (u_long) - ((long)u1) ;
+			}
+		}
+		x = u1 ;
+	}
+	else {				/* string */
+		int	sign = 0 ;
+
+		if (*v == '-') {
+			sign = 1 ;
+		}
+		while ((c = *v++) && (c >= '0') && (c <= '9')) {
+			x = x * 10 + c - '0' ;
+		}
+		if (scale == 10) {
+			x *= 10 ;
+			if (c == '.') {
+				if ((c = *v++) && (c >= '0') && (c <= '9')) {
+					x += c - '0' ;
+				}
+			}
+		}
+		if (sign)
+			x = (u_long) - ((long)x) ;
+	}
+	/*
+	 * if the value is negative
+	 *	and the absolute value is outside the limits
+	 *		take the lower limit
+	 *	else
+	 *		take the absoute value
+	 */
+	if ((long)x < 0) {
+		if (- ((long)x) > (long) mx) {
+			x = 0 ;
+		}
+		else {
+			x = (u_long) - ((long)x) ;
+		}
+	}
+	if (x < mn)
+		return(mn) ;
+	else if (x > mx)
+		return(mx) ;
+	return(x) ;
+}
+
+#if 0
+struct	s_smc	SMC ;
+main()
+{
+	char	*p ;
+	char	*v ;
+	char	buf[100] ;
+	int	toggle = 0 ;
+
+	while (gets(buf)) {
+		p = buf ;
+		while (*p && ((*p == ' ') || (*p == '\t')))
+			p++ ;
+
+		while (*p && ((*p != ' ') && (*p != '\t')))
+			p++ ;
+
+		v = p ;
+		while (*v && ((*v == ' ') || (*v == '\t')))
+			v++ ;
+		if ((*v >= '0') && (*v <= '9')) {
+			toggle = !toggle ;
+			if (toggle) {
+				u_long	l ;
+				l = atol(v) ;
+				smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
+			}
+			else
+				smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
+		}
+		else {
+			smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
+		}
+	}
+	exit(0) ;
+}
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smttimer.c linux/drivers/net/skfp/smttimer.c
--- v2.3.46/linux/drivers/net/skfp/smttimer.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/smttimer.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT timer
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smttimer.c	2.4 97/08/04 (C) SK " ;
+#endif
+
+/*
+ * external function declarations
+ */
+extern u_long hwt_read() ;
+extern void hwt_stop() ;
+extern void hwt_start() ;
+
+static void timer_done() ;
+
+
+void smt_timer_init(smc)
+struct s_smc *smc ;
+{
+	smc->t.st_queue = 0 ;
+	smc->t.st_fast.tm_active = FALSE ;
+	smc->t.st_fast.tm_next = 0 ;
+	hwt_init(smc) ;
+}
+
+void smt_timer_stop(smc,timer)
+struct s_smc *smc ;
+struct smt_timer *timer ;
+{
+	struct smt_timer	**prev ;
+	struct smt_timer	*tm ;
+
+	/*
+	 * remove timer from queue
+	 */
+	timer->tm_active = FALSE ;
+	if (smc->t.st_queue == timer && !timer->tm_next) {
+		hwt_stop(smc) ;
+	}
+	for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+		if (tm == timer) {
+			*prev = tm->tm_next ;
+			if (tm->tm_next) {
+				tm->tm_next->tm_delta += tm->tm_delta ;
+			}
+			return ;
+		}
+	}
+}
+
+void smt_timer_start(smc,timer,time,token)
+struct s_smc *smc ;
+struct smt_timer *timer ;
+u_long		time ;
+u_long		token ;
+{
+	struct smt_timer	**prev ;
+	struct smt_timer	*tm ;
+	u_long			delta = 0 ;
+
+	time /= 16 ;		/* input is uS, clock ticks are 16uS */
+	if (!time)
+		time = 1 ;
+	smt_timer_stop(smc,timer) ;
+	timer->tm_smc = smc ;
+	timer->tm_token = token ;
+	timer->tm_active = TRUE ;
+	if (!smc->t.st_queue) {
+		smc->t.st_queue = timer ;
+		timer->tm_next = 0 ;
+		timer->tm_delta = time ;
+		hwt_start(smc,time) ;
+		return ;
+	}
+	/*
+	 * timer correction
+	 */
+	timer_done(smc,0) ;
+
+	/*
+	 * find position in queue
+	 */
+	delta = 0 ;
+	for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+		if (delta + tm->tm_delta > time) {
+			break ;
+		}
+		delta += tm->tm_delta ;
+	}
+	/* insert in queue */
+	*prev = timer ;
+	timer->tm_next = tm ;
+	timer->tm_delta = time - delta ;
+	if (tm)
+		tm->tm_delta -= timer->tm_delta ;
+	/*
+	 * start new with first
+	 */
+	hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
+
+void smt_force_irq(smc)
+struct s_smc *smc ;
+{
+	smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); 
+}
+
+void smt_timer_done(smc)
+struct s_smc *smc ;
+{
+	timer_done(smc,1) ;
+}
+
+static void timer_done(smc,restart)
+struct s_smc *smc ;
+int restart ;
+{
+	u_long			delta ;
+	struct smt_timer	*tm ;
+	struct smt_timer	*next ;
+	struct smt_timer	**last ;
+	int			done = 0 ;
+
+	delta = hwt_read(smc) ;
+	last = &smc->t.st_queue ;
+	tm = smc->t.st_queue ;
+	while (tm && !done) {
+		if (delta >= tm->tm_delta) {
+			tm->tm_active = FALSE ;
+			delta -= tm->tm_delta ;
+			last = &tm->tm_next ;
+			tm = tm->tm_next ;
+		}
+		else {
+			tm->tm_delta -= delta ;
+			delta = 0 ;
+			done = 1 ;
+		}
+	}
+	*last = 0 ;
+	next = smc->t.st_queue ;
+	smc->t.st_queue = tm ;
+
+	for ( tm = next ; tm ; tm = next) {
+		next = tm->tm_next ;
+		timer_event(smc,tm->tm_token) ;
+	}
+
+	if (restart && smc->t.st_queue)
+		hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/srf.c linux/drivers/net/skfp/srf.c
--- v2.3.46/linux/drivers/net/skfp/srf.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/skfp/srf.c	Fri Feb 18 14:55:53 2000
@@ -0,0 +1,441 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT 7.2 Status Response Frame Implementation
+	SRF state machine and frame generation
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	SLIM_SMT
+#ifndef	BOOT
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)srf.c	1.18 97/08/04 (C) SK " ;
+#endif
+
+
+/*
+ * function declarations
+ */
+static void clear_all_rep() ;
+static void clear_reported() ;
+static void smt_send_srf() ;
+static struct s_srf_evc *smt_get_evc() ;
+
+#define MAX_EVCS	(sizeof(smc->evcs)/sizeof(smc->evcs[0]))
+
+struct evc_init {
+	u_char code ;
+	u_char index ;
+	u_char n ;
+	u_short	para ;
+}  ;
+
+static const struct evc_init evc_inits[] = {
+	{ SMT_COND_SMT_PEER_WRAP,		0,1,SMT_P1048	} ,
+
+	{ SMT_COND_MAC_DUP_ADDR,		INDEX_MAC, NUMMACS,SMT_P208C } ,
+	{ SMT_COND_MAC_FRAME_ERROR,		INDEX_MAC, NUMMACS,SMT_P208D } ,
+	{ SMT_COND_MAC_NOT_COPIED,		INDEX_MAC, NUMMACS,SMT_P208E } ,
+	{ SMT_EVENT_MAC_NEIGHBOR_CHANGE,	INDEX_MAC, NUMMACS,SMT_P208F } ,
+	{ SMT_EVENT_MAC_PATH_CHANGE,		INDEX_MAC, NUMMACS,SMT_P2090 } ,
+
+	{ SMT_COND_PORT_LER,			INDEX_PORT,NUMPHYS,SMT_P4050 } ,
+	{ SMT_COND_PORT_EB_ERROR,		INDEX_PORT,NUMPHYS,SMT_P4052 } ,
+	{ SMT_EVENT_PORT_CONNECTION,		INDEX_PORT,NUMPHYS,SMT_P4051 } ,
+	{ SMT_EVENT_PORT_PATH_CHANGE,		INDEX_PORT,NUMPHYS,SMT_P4053 } ,
+} ;
+
+#define MAX_INIT_EVC	(sizeof(evc_inits)/sizeof(evc_inits[0]))
+
+void smt_init_evc(smc)
+struct s_smc *smc ;
+{
+	struct s_srf_evc	*evc ;
+	const struct evc_init 	*init ;
+	int			i ;
+	int			index ;
+	int			offset ;
+
+	static u_char		fail_safe = FALSE ;
+
+	memset((char *)smc->evcs,0,sizeof(smc->evcs)) ;
+
+	evc = smc->evcs ;
+	init = evc_inits ;
+
+	for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) {
+		for (index = 0 ; index < init->n ; index++) {
+			evc->evc_code = init->code ;
+			evc->evc_para = init->para ;
+			evc->evc_index = init->index + index ;
+#ifndef	DEBUG
+			evc->evc_multiple = &fail_safe ;
+			evc->evc_cond_state = &fail_safe ;
+#endif
+			evc++ ;
+		}
+		init++ ;
+	}
+
+	if ((unsigned) (evc - smc->evcs) > MAX_EVCS) {
+		SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ;
+	}
+
+	/*
+	 * conditions
+	 */
+	smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ;
+	smc->evcs[1].evc_cond_state =
+		&smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
+	smc->evcs[2].evc_cond_state =
+		&smc->mib.m[MAC0].fddiMACFrameErrorFlag ;
+	smc->evcs[3].evc_cond_state =
+		&smc->mib.m[MAC0].fddiMACNotCopiedFlag ;
+
+	/*
+	 * events
+	 */
+	smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ;
+	smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ;
+
+	offset = 6 ;
+	for (i = 0 ; i < NUMPHYS ; i++) {
+		/*
+		 * conditions
+		 */
+		smc->evcs[offset + 0*NUMPHYS].evc_cond_state =
+			&smc->mib.p[i].fddiPORTLerFlag ;
+		smc->evcs[offset + 1*NUMPHYS].evc_cond_state =
+			&smc->mib.p[i].fddiPORTEB_Condition ;
+
+		/*
+		 * events
+		 */
+		smc->evcs[offset + 2*NUMPHYS].evc_multiple =
+			&smc->mib.p[i].fddiPORTMultiple_U ;
+		smc->evcs[offset + 3*NUMPHYS].evc_multiple =
+			&smc->mib.p[i].fddiPORTMultiple_P ;
+		offset++ ;
+	}
+#ifdef	DEBUG
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (SMT_IS_CONDITION(evc->evc_code)) {
+			if (!evc->evc_cond_state) {
+				SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ;
+			}
+			evc->evc_multiple = &fail_safe ;
+		}
+		else {
+			if (!evc->evc_multiple) {
+				SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ;
+			}
+			evc->evc_cond_state = &fail_safe ;
+		}
+	}
+#endif
+	smc->srf.TSR = smt_get_time() ;
+	smc->srf.sr_state = SR0_WAIT ;
+}
+
+static struct s_srf_evc *smt_get_evc(smc,code,index)
+struct s_smc *smc ;
+int code ;
+int index ;
+{
+	int			i ;
+	struct s_srf_evc	*evc ;
+
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (evc->evc_code == code && evc->evc_index == index)
+			return(evc) ;
+	}
+	return(0) ;
+}
+
+#define THRESHOLD_2	(2*TICKS_PER_SECOND)
+#define THRESHOLD_32	(32*TICKS_PER_SECOND)
+
+#ifdef	DEBUG
+static const char * const srf_names[] = {
+	"None","MACPathChangeEvent",	"MACNeighborChangeEvent",
+	"PORTPathChangeEvent",		"PORTUndesiredConnectionAttemptEvent",
+	"SMTPeerWrapCondition",		"SMTHoldCondition",
+	"MACFrameErrorCondition",	"MACDuplicateAddressCondition",
+	"MACNotCopiedCondition",	"PORTEBErrorCondition",
+	"PORTLerCondition"
+} ;
+#endif
+
+void smt_srf_event(smc,code,index,cond)
+struct s_smc *smc ;
+int code ;
+int index ;
+int cond ;
+{
+	struct s_srf_evc	*evc ;
+	int			cond_asserted = 0 ;
+	int			cond_deasserted = 0 ;
+	int			event_occured = 0 ;
+	int			tsr ;
+	int			T_Limit = 2*TICKS_PER_SECOND ;
+
+	if (code == SMT_COND_MAC_DUP_ADDR && cond) {
+		RS_SET(smc,RS_DUPADDR) ;
+	}
+
+	if (code) {
+		DB_SMT("SRF: %s index %d\n",srf_names[code],index) ;
+
+		if (!(evc = smt_get_evc(smc,code,index))) {
+			DB_SMT("SRF : smt_get_evc() failed\n",0,0) ;
+			return ;
+		}
+		/*
+		 * ignore condition if no change
+		 */
+		if (SMT_IS_CONDITION(code)) {
+			if (*evc->evc_cond_state == cond)
+				return ;
+		}
+
+		/*
+		 * set transition time stamp
+		 */
+		smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ;
+		if (SMT_IS_CONDITION(code)) {
+			DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ;
+			if (cond) {
+				*evc->evc_cond_state = TRUE ;
+				evc->evc_rep_required = TRUE ;
+				smc->srf.any_report = TRUE ;
+				cond_asserted = TRUE ;
+			}
+			else {
+				*evc->evc_cond_state = FALSE ;
+				cond_deasserted = TRUE ;
+			}
+		}
+		else {
+			if (evc->evc_rep_required) {
+				*evc->evc_multiple  = TRUE ;
+			}
+			else {
+				evc->evc_rep_required = TRUE ;
+				*evc->evc_multiple  = FALSE ;
+			}
+			smc->srf.any_report = TRUE ;
+			event_occured = TRUE ;
+		}
+#ifdef	FDDI_MIB
+		snmp_srf_event(smc,evc) ;
+#endif	/* FDDI_MIB */
+	}
+	tsr = smt_get_time() - smc->srf.TSR ;
+
+	switch (smc->srf.sr_state) {
+	case SR0_WAIT :
+		/* SR01a */
+		if (cond_asserted && tsr < T_Limit) {
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+			smc->srf.sr_state = SR1_HOLDOFF ;
+			break ;
+		}
+		/* SR01b */
+		if (cond_deasserted && tsr < T_Limit) {
+			smc->srf.sr_state = SR1_HOLDOFF ;
+			break ;
+		}
+		/* SR01c */
+		if (event_occured && tsr < T_Limit) {
+			smc->srf.sr_state = SR1_HOLDOFF ;
+			break ;
+		}
+		/* SR00b */
+		if (cond_asserted && tsr >= T_Limit) {
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR00c */
+		if (cond_deasserted && tsr >= T_Limit) {
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR00d */
+		if (event_occured && tsr >= T_Limit) {
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR00e */
+		if (smc->srf.any_report && (u_long) tsr >=
+			smc->srf.SRThreshold) {
+			smc->srf.SRThreshold *= 2 ;
+			if (smc->srf.SRThreshold > THRESHOLD_32)
+				smc->srf.SRThreshold = THRESHOLD_32 ;
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR02 */
+		if (!smc->mib.fddiSMTStatRptPolicy) {
+			smc->srf.sr_state = SR2_DISABLED ;
+			break ;
+		}
+		break ;
+	case SR1_HOLDOFF :
+		/* SR10b */
+		if (tsr >= T_Limit) {
+			smc->srf.sr_state = SR0_WAIT ;
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR11a */
+		if (cond_asserted) {
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+		}
+		/* SR11b */
+		/* SR11c */
+		/* handled above */
+		/* SR12 */
+		if (!smc->mib.fddiSMTStatRptPolicy) {
+			smc->srf.sr_state = SR2_DISABLED ;
+			break ;
+		}
+		break ;
+	case SR2_DISABLED :
+		if (smc->mib.fddiSMTStatRptPolicy) {
+			smc->srf.sr_state = SR0_WAIT ;
+			smc->srf.TSR = smt_get_time() ;
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+			clear_all_rep(smc) ;
+			break ;
+		}
+		break ;
+	}
+}
+
+static void clear_all_rep(smc)
+struct s_smc *smc ;
+{
+	struct s_srf_evc	*evc ;
+	int			i ;
+
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		evc->evc_rep_required = FALSE ;
+		if (SMT_IS_CONDITION(evc->evc_code))
+			*evc->evc_cond_state = FALSE ;
+	}
+	smc->srf.any_report = FALSE ;
+}
+
+static void clear_reported(smc)
+struct s_smc *smc ;
+{
+	struct s_srf_evc	*evc ;
+	int			i ;
+
+	smc->srf.any_report = FALSE ;
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (SMT_IS_CONDITION(evc->evc_code)) {
+			if (*evc->evc_cond_state == FALSE)
+				evc->evc_rep_required = FALSE ;
+			else
+				smc->srf.any_report = TRUE ;
+		}
+		else {
+			evc->evc_rep_required = FALSE ;
+			*evc->evc_multiple = FALSE ;
+		}
+	}
+}
+
+extern SMbuf *smt_build_frame() ;
+
+/*
+ * build and send SMT SRF frame
+ */
+static void smt_send_srf(smc)
+struct s_smc *smc ;
+{
+
+	struct smt_header	*smt ;
+	struct s_srf_evc	*evc ;
+	SK_LOC_DECL(struct s_pcon,pcon) ;
+	SMbuf			*mb ;
+	int			i ;
+
+	static const struct fddi_addr SMT_SRF_DA = {
+		0x80, 0x01, 0x43, 0x00, 0x80, 0x08
+	} ;
+
+	/*
+	 * build SMT header
+	 */
+	if (!smc->r.sm_ma_avail)
+		return ;
+	if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0)))
+		return ;
+
+	RS_SET(smc,RS_SOFTERROR) ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = SMT_SRF_DA ;		/* DA == SRF multicast */
+
+	/*
+	 * setup parameter status
+	 */
+	pcon.pc_len = SMT_MAX_INFO_LEN ;	/* max para length */
+	pcon.pc_err = 0 ;			/* no error */
+	pcon.pc_badset = 0 ;			/* no bad set count */
+	pcon.pc_p = (void *) (smt + 1) ;	/* paras start here */
+
+	smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ;
+
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (evc->evc_rep_required) {
+			smt_add_para(smc,&pcon,evc->evc_para,
+				(int)evc->evc_index,0) ;
+		}
+	}
+	smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
+	mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
+
+	DB_SMT("SRF: sending SRF at %x, len %d \n",smt,mb->sm_len) ;
+	DB_SMT("SRF: state SR%d Threshold %d\n",
+		smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ;
+#ifdef	DEBUG
+	dump_smt(smc,smt,"SRF Send") ;
+#endif
+	smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
+	clear_reported(smc) ;
+}
+
+#endif	/* no BOOT */
+#endif	/* no SLIM_SMT */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.3.46/linux/drivers/net/slip.c	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/slip.c	Thu Feb 17 09:18:47 2000
@@ -449,7 +449,7 @@
 	struct slip *sl = (struct slip *) tty->disc_data;
 
 	/* First make sure we're connected. */
-	if (!sl || sl->magic != SLIP_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) {
+	if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) {
 		return;
 	}
 	if (sl->xleft <= 0)  {
@@ -472,10 +472,10 @@
 
 	spin_lock(&sl->lock);
 
-	if (test_bit(LINK_STATE_XOFF, &dev->state)) {
+	if (netif_queue_stopped(dev)) {
 		struct slip *sl = (struct slip*)(dev->priv);
 
-		if (!test_bit(LINK_STATE_START, &dev->state))
+		if (!netif_running(dev))
 			goto out;
 
 		/* May be we must check transmitter timeout here ?
@@ -507,7 +507,7 @@
 	struct slip *sl = (struct slip*)(dev->priv);
 
 	spin_lock(&sl->lock);
-	if (!test_bit(LINK_STATE_START, &dev->state))  {
+	if (!netif_running(dev))  {
 		spin_unlock(&sl->lock);
 		printk("%s: xmit call when iface is down\n", dev->name);
 		dev_kfree_skb(skb);
@@ -679,7 +679,7 @@
 	struct slip *sl = (struct slip *) tty->disc_data;
 
 	if (!sl || sl->magic != SLIP_MAGIC ||
-	    !test_bit(LINK_STATE_START, &sl->dev->state))
+	    !netif_running(sl->dev))
 		return;
 
 	/* Read the characters out of the buffer */
@@ -1468,7 +1468,7 @@
 			unsigned char s = END;
 #endif
 			/* put END into tty queue. Is it right ??? */
-			if (!test_bit(LINK_STATE_XOFF, &sl->dev->state))
+			if (!netif_queue_stopped(sl->dev))
 			{
 				/* if device busy no outfill */
 				sl->tty->driver.write(sl->tty, 0, &s, 1);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.3.46/linux/drivers/net/starfire.c	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/starfire.c	Fri Feb 18 15:07:20 2000
@@ -813,7 +813,7 @@
 		np->rx_info[i].skb = skb;
 		if (skb == NULL)
 			break;
-		np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz);
+		np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		skb->dev = dev;			/* Mark as being used by this device. */
 		/* Grrr, we cannot offset to correctly align the IP header. */
 		np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid);
@@ -859,7 +859,7 @@
 
 	np->tx_info[entry].skb = skb;
 	np->tx_info[entry].mapping =
-		pci_map_single(np->pdev, skb->data, skb->len);
+		pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
 
 	np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping);
 	/* Add  |TxDescIntr to generate Tx-done interrupts. */
@@ -959,10 +959,10 @@
 					skb = np->tx_info[entry].skb;
 					pci_unmap_single(np->pdev,
 									 np->tx_info[entry].mapping,
-									 skb->len);
+									 skb->len, PCI_DMA_TODEVICE);
 
 					/* Scavenge the descriptor. */
-					kfree_skb(skb);
+					dev_kfree_skb_irq(skb);
 					np->tx_info[entry].skb = NULL;
 					np->tx_info[entry].mapping = 0;
 					np->dirty_tx++;
@@ -1044,7 +1044,7 @@
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single(np->pdev,
 									np->rx_info[entry].mapping,
-									pkt_len);
+									pkt_len, PCI_DMA_FROMDEVICE);
 #if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
 				eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
@@ -1055,7 +1055,7 @@
 			} else {
 				char *temp;
 
-				pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz);
+				pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 				skb = np->rx_info[entry].skb;
 				temp = skb_put(skb, pkt_len);
 				np->rx_info[entry].skb = NULL;
@@ -1099,7 +1099,7 @@
 			if (skb == NULL)
 				break;			/* Better luck next round. */
 			np->rx_info[entry].mapping =
-				pci_map_single(np->pdev, skb->tail, np->rx_buf_sz);
+				pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			skb->dev = dev;			/* Mark as being used by this device. */
 			np->rx_ring[entry].rxaddr =
 				cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
@@ -1324,8 +1324,8 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
 		if (np->rx_info[i].skb != NULL) {
-			pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz);
-			kfree_skb(np->rx_info[i].skb);
+			pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(np->rx_info[i].skb);
 		}
 		np->rx_info[i].skb = NULL;
 		np->rx_info[i].mapping = 0;
@@ -1335,8 +1335,8 @@
 		if (skb != NULL) {
 			pci_unmap_single(np->pdev,
 							 np->tx_info[i].mapping,
-							 skb->len);
-			kfree_skb(skb);
+							 skb->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb(skb);
 		}
 		np->tx_info[i].skb = NULL;
 		np->tx_info[i].mapping = 0;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.3.46/linux/drivers/net/strip.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/strip.c	Thu Feb 17 09:18:47 2000
@@ -1354,7 +1354,7 @@
 
     /* First make sure we're connected. */
     if (!strip_info || strip_info->magic != STRIP_MAGIC || 
-    	!test_bit(LINK_STATE_START, &strip_info->dev.state))
+    	!netif_running(&strip_info->dev))
         return;
 
     if (strip_info->tx_left > 0)
@@ -1644,7 +1644,7 @@
 {
     struct strip *strip_info = (struct strip *)(dev->priv);
 
-    if (!test_bit(LINK_STATE_START, &dev->state))
+    if (!netif_running(dev))
     {
         printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name);
         return(1);
@@ -2338,7 +2338,7 @@
     const unsigned char *end = cp + count;
 
     if (!strip_info || strip_info->magic != STRIP_MAGIC 
-    	|| !test_bit(LINK_STATE_START, &strip_info->dev.state))
+    	|| !netif_running(&strip_info->dev))
         return;
 
     /* Argh! mtu change time! - costs us the packet part received at the change */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.3.46/linux/drivers/net/sunbmac.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/sunbmac.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.15 2000/02/10 21:14:22 davem Exp $
+/* $Id: sunbmac.c,v 1.18 2000/02/18 13:49:21 davem Exp $
  * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -190,20 +190,14 @@
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		if (bp->rx_skbs[i] != NULL) {
-			if (in_irq())
-				dev_kfree_skb_irq(bp->rx_skbs[i]);
-			else
-				dev_kfree_skb(bp->rx_skbs[i]);
+			dev_kfree_skb_any(bp->rx_skbs[i]);
 			bp->rx_skbs[i] = NULL;
 		}
 	}
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (bp->tx_skbs[i] != NULL) {
-			if (in_irq())
-				dev_kfree_skb_irq(bp->tx_skbs[i]);
-			else
-				dev_kfree_skb(bp->tx_skbs[i]);
+			dev_kfree_skb_any(bp->tx_skbs[i]);
 			bp->tx_skbs[i] = NULL;
 		}
 	}
@@ -240,7 +234,8 @@
 
 		bb->be_rxd[i].rx_addr =
 			sbus_map_single(bp->bigmac_sdev, skb->data,
-					RX_BUF_ALLOC_SIZE - 34);
+					RX_BUF_ALLOC_SIZE - 34,
+					SBUS_DMA_FROMDEVICE);
 		bb->be_rxd[i].rx_flags =
 			(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 	}
@@ -776,7 +771,8 @@
 		bp->enet_stats.tx_packets++;
 		bp->enet_stats.tx_bytes += skb->len;
 		sbus_unmap_single(bp->bigmac_sdev,
-				  this->tx_addr, skb->len);
+				  this->tx_addr, skb->len,
+				  SBUS_DMA_TODEVICE);
 
 		DTX(("skb(%p) ", skb));
 		bp->tx_skbs[elem] = NULL;
@@ -787,7 +783,7 @@
 	DTX((" DONE, tx_old=%d\n", elem));
 	bp->tx_old = elem;
 
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+	if (netif_queue_stopped(dev) &&
 	    TX_BUFFS_AVAIL(bp) > 0)
 		netif_wake_queue(bp->dev);
 
@@ -831,14 +827,16 @@
 			}
 			sbus_unmap_single(bp->bigmac_sdev,
 					  this->rx_addr,
-					  RX_BUF_ALLOC_SIZE - 34);
+					  RX_BUF_ALLOC_SIZE - 34,
+					  SBUS_DMA_FROMDEVICE);
 			bp->rx_skbs[elem] = new_skb;
 			new_skb->dev = bp->dev;
 			skb_put(new_skb, ETH_FRAME_LEN);
 			skb_reserve(new_skb, 34);
 			this->rx_addr = sbus_map_single(bp->bigmac_sdev,
 							new_skb->data,
-							RX_BUF_ALLOC_SIZE - 34);
+							RX_BUF_ALLOC_SIZE - 34,
+							SBUS_DMA_FROMDEVICE);
 			this->rx_flags =
 				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 
@@ -855,7 +853,7 @@
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
 			sbus_dma_sync_single(bp->bigmac_sdev,
-					     this->rx_addr, len);
+					     this->rx_addr, len, SBUS_DMA_FROMDEVICE);
 			eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);
 
 			/* Reuse original ring buffer. */
@@ -951,7 +949,7 @@
 	u32 mapping;
 
 	len = skb->len;
-	mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len);
+	mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);
 
 	/* Avoid a race... */
 	spin_lock_irq(&bp->lock);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.3.46/linux/drivers/net/sunhme.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/sunhme.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.87 2000/02/10 21:14:22 davem Exp $
+/* $Id: sunhme.c,v 1.92 2000/02/18 13:49:22 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -152,6 +152,13 @@
 #define DEFAULT_IPG2       4 /* For all modes */
 #define DEFAULT_JAMSIZE    4 /* Toe jam */
 
+/* NOTE: In the descriptor writes one _must_ write the address
+ *	 member _first_.  The card must not be allowed to see
+ *	 the updated descriptor flags until the address is
+ *	 correct.  I've added a write memory barrier between
+ *	 the two stores so that I can sleep well at night... -DaveM
+ */
+
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
 static void sbus_hme_write32(unsigned long reg, u32 val)
 {
@@ -166,13 +173,15 @@
 static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
 {
 	rxd->rx_addr = addr;
+	wmb();
 	rxd->rx_flags = flags;
 }
 
 static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
 {
-	txd->tx_flags = flags;
 	txd->tx_addr = addr;
+	wmb();
+	txd->tx_flags = flags;
 }
 
 static u32 sbus_hme_read_desc32(u32 *p)
@@ -193,18 +202,20 @@
 static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
 {
 	rxd->rx_addr = cpu_to_le32(addr);
+	wmb();
 	rxd->rx_flags = cpu_to_le32(flags);
 }
 
 static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
 {
-	txd->tx_flags = cpu_to_le32(flags);
 	txd->tx_addr = cpu_to_le32(addr);
+	wmb();
+	txd->tx_flags = cpu_to_le32(flags);
 }
 
 static u32 pci_hme_read_desc32(u32 *p)
 {
-	return cpu_to_le32(*p);
+	return cpu_to_le32p(p);
 }
 
 #define hme_write32(__hp, __reg, __val) \
@@ -217,12 +228,12 @@
 	((__hp)->write_txd((__txd), (__flags), (__addr)))
 #define hme_read_desc32(__hp, __p) \
 	((__hp)->read_desc32(__p))
-#define hme_dma_map(__hp, __ptr, __size) \
-	((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size)))
-#define hme_dma_unmap(__hp, __addr, __size) \
-	((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size)))
-#define hme_dma_sync(__hp, __addr, __size) \
-	((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size)))
+#define hme_dma_map(__hp, __ptr, __size, __dir) \
+	((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
+#define hme_dma_unmap(__hp, __addr, __size, __dir) \
+	((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
+#define hme_dma_sync(__hp, __addr, __size, __dir) \
+	((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size), (__dir)))
 #else
 #ifdef CONFIG_SBUS
 /* SBUS only compilation */
@@ -232,19 +243,21 @@
 	sbus_readl(__reg)
 #define hme_write_rxd(__hp, __rxd, __flags, __addr) \
 do {	(__rxd)->rx_addr = (__addr); \
+	wmb(); \
 	(__rxd)->rx_flags = (__flags); \
 } while(0)
 #define hme_write_txd(__hp, __txd, __flags, __addr) \
 do {	(__txd)->tx_addr = (__addr); \
+	wmb(); \
 	(__txd)->tx_flags = (__flags); \
 } while(0)
 #define hme_read_desc32(__hp, __p)	(*(__p))
-#define hme_dma_map(__hp, __ptr, __size) \
-	sbus_map_single((__hp)->happy_dev, (__ptr), (__size))
+#define hme_dma_map(__hp, __ptr, __size, __dir) \
+	sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size) \
-	sbus_unmap_single((__hp)->happy_dev, (__addr), (__size))
-#define hme_dma_sync(__hp, __addr, __size) \
-	sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size))
+	sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync(__hp, __addr, __size, __dir) \
+	sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir))
 #else
 /* PCI only compilation */
 #define hme_write32(__hp, __reg, __val) \
@@ -253,22 +266,28 @@
 	readl(__reg)
 #define hme_write_rxd(__hp, __rxd, __flags, __addr) \
 do {	(__rxd)->rx_addr = cpu_to_le32(__addr); \
+	wmb(); \
 	(__rxd)->rx_flags = cpu_to_le32(__flags); \
 } while(0)
 #define hme_write_txd(__hp, __txd, __flags, __addr) \
 do {	(__txd)->tx_addr = cpu_to_le32(__addr); \
+	wmb(); \
 	(__txd)->tx_flags = cpu_to_le32(__flags); \
 } while(0)
-#define hme_read_desc32(__hp, __p)	cpu_to_le32(*(__p))
-#define hme_dma_map(__hp, __ptr, __size) \
-	pci_map_single((__hp)->happy_dev, (__ptr), (__size))
-#define hme_dma_unmap(__hp, __addr, __size) \
-	pci_unmap_single((__hp)->happy_dev, (__addr), (__size))
-#define hme_dma_sync(__hp, __addr, __size) \
-	pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size))
+#define hme_read_desc32(__hp, __p)	cpu_to_le32p(__p)
+#define hme_dma_map(__hp, __ptr, __size, __dir) \
+	pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+#define hme_dma_unmap(__hp, __addr, __size, __dir) \
+	pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync(__hp, __addr, __size, __dir) \
+	pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir))
 #endif
 #endif
 
+#define DMA_BIDIRECTIONAL	SBUS_DMA_BIDIRECTIONAL
+#define DMA_FROMDEVICE		SBUS_DMA_FROMDEVICE
+#define DMA_TODEVICE		SBUS_DMA_TODEVICE
+
 /* Oh yes, the MIF BitBang is mighty fun to program.  BitBucket is more like it. */
 static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit)
 {
@@ -1193,11 +1212,8 @@
 
 			rxd = &hp->happy_block->happy_meal_rxd[i];
 			dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
-			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE);
-			if (in_irq())
-				dev_kfree_skb_irq(skb);
-			else
-				dev_kfree_skb(skb);
+			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+			dev_kfree_skb_any(skb);
 			hp->rx_skbs[i] = NULL;
 		}
 	}
@@ -1210,11 +1226,8 @@
 
 			txd = &hp->happy_block->happy_meal_txd[i];
 			dma_addr = hme_read_desc32(hp, &txd->tx_addr);
-			hme_dma_unmap(hp, dma_addr, skb->len);
-			if (in_irq())
-				dev_kfree_skb_irq(skb);
-			else
-				dev_kfree_skb(skb);
+			hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);
+			dev_kfree_skb_any(skb);
 			hp->tx_skbs[i] = NULL;
 		}
 	}
@@ -1253,7 +1266,7 @@
 		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
 		hme_write_rxd(hp, &hb->happy_meal_rxd[i],
 			      (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),
-			      hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE));
+			      hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
 		skb_reserve(skb, RX_OFFSET);
 	}
 
@@ -1895,7 +1908,7 @@
 			break;
 		dma_addr = hme_read_desc32(hp, &this->tx_addr);
 		skb = hp->tx_skbs[elem];
-		hme_dma_unmap(hp, dma_addr, skb->len);
+		hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);
 		hp->tx_skbs[elem] = NULL;
 		hp->net_stats.tx_bytes += skb->len;
 
@@ -1907,7 +1920,7 @@
 	hp->tx_old = elem;
 	TXD((">"));
 
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+	if (netif_queue_stopped(dev) &&
 	    TX_BUFFS_AVAIL(hp) > 0)
 		netif_wake_queue(dev);
 
@@ -1973,13 +1986,13 @@
 				drops++;
 				goto drop_it;
 			}
-			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE);
+			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
 			hp->rx_skbs[elem] = new_skb;
 			new_skb->dev = dev;
 			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
 			hme_write_rxd(hp, this,
 				      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
-				      hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE));
+				      hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
 			skb_reserve(new_skb, RX_OFFSET);
 
 			/* Trim the original skb for the netif. */
@@ -1995,7 +2008,7 @@
 			copy_skb->dev = dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			hme_dma_sync(hp, dma_addr, len);
+			hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE);
 			memcpy(copy_skb->data, skb->data, len);
 
 			/* Reuse original ring buffer. */
@@ -2178,7 +2191,7 @@
 	u32 mapping;
 
 	len = skb->len;
-	mapping = hme_dma_map(hp, skb->data, len);
+	mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
 
 	spin_lock_irq(&hp->happy_lock);
 
@@ -2192,10 +2205,11 @@
 	if (TX_BUFFS_AVAIL(hp) <= 0)
 		netif_stop_queue(dev);
 
-	spin_unlock_irq(&hp->happy_lock);
-
 	/* Get it going. */
 	hme_write32(hp, hp->etxregs + ETX_PENDING, ETX_TP_DMAWAKEUP);
+
+	spin_unlock_irq(&hp->happy_lock);
+
 	dev->trans_start = jiffies;
 
 	tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
@@ -2642,9 +2656,9 @@
 	hp->read_desc32 = sbus_hme_read_desc32;
 	hp->write_txd = sbus_hme_write_txd;
 	hp->write_rxd = sbus_hme_write_rxd;
-	hp->dma_map = (u32 (*)(void *, void *, long))sbus_map_single;
-	hp->dma_unmap = (void (*)(void *, u32, long))sbus_unmap_single;
-	hp->dma_sync = (void (*)(void *, u32, long))sbus_dma_sync_single;
+	hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single;
+	hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single;
+	hp->dma_sync = (void (*)(void *, u32, long, int))sbus_dma_sync_single;
 	hp->read32 = sbus_hme_read32;
 	hp->write32 = sbus_hme_write32;
 #endif
@@ -2817,9 +2831,9 @@
 	hp->read_desc32 = pci_hme_read_desc32;
 	hp->write_txd = pci_hme_write_txd;
 	hp->write_rxd = pci_hme_write_rxd;
-	hp->dma_map = (u32 (*)(void *, void *, long))pci_map_single;
-	hp->dma_unmap = (void (*)(void *, u32, long))pci_unmap_single;
-	hp->dma_sync = (void (*)(void *, u32, long))pci_dma_sync_single;
+	hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single;
+	hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single;
+	hp->dma_sync = (void (*)(void *, u32, long, int))pci_dma_sync_single;
 	hp->read32 = pci_hme_read32;
 	hp->write32 = pci_hme_write32;
 #endif
diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.3.46/linux/drivers/net/sunhme.h	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/sunhme.h	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sunhme.h,v 1.29 2000/02/09 11:15:40 davem Exp $
+/* $Id: sunhme.h,v 1.30 2000/02/18 13:49:26 davem Exp $
  * sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver.
  *           Also known as the "Happy Meal".
  *
@@ -502,9 +502,9 @@
 	u32 (*read_desc32)(u32 *);
 	void (*write_txd)(struct happy_meal_txd *, u32, u32);
 	void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
-	u32 (*dma_map)(void *, void *, long);
-	void (*dma_unmap)(void *, u32, long);
-	void (*dma_sync)(void *, u32, long);
+	u32 (*dma_map)(void *, void *, long, int);
+	void (*dma_unmap)(void *, u32, long, int);
+	void (*dma_sync)(void *, u32, long, int);
 #endif
 
 	/* This is either a sbus_dev or a pci_dev. */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.3.46/linux/drivers/net/sunlance.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/sunlance.c	Thu Feb 17 09:18:47 2000
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.97 2000/02/14 09:02:32 davem Exp $
+/* $Id: sunlance.c,v 1.99 2000/02/16 10:36:14 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -640,11 +640,11 @@
 		j = TX_NEXT(j);
 	}
 	lp->tx_old = j;
-
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+out:
+	if (netif_queue_stopped(dev) &&
 	    TX_BUFFS_AVAIL > 0)
 		netif_wake_queue(dev);
-out:
+
 	spin_unlock(&lp->lock);
 }
 
@@ -812,7 +812,7 @@
 	}
 	lp->tx_old = j;
 
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+	if (netif_queue_stopped(dev) &&
 	    TX_BUFFS_AVAIL > 0)
 		netif_wake_queue(dev);
 out:
@@ -1247,7 +1247,7 @@
 	volatile struct lance_init_block *ib = lp->init_block;
 	u16 mode;
 
-	if (!test_bit(LINK_STATE_START, &dev->state))
+	if (!netif_running(dev))
 		return;
 
 	if (lp->tx_old != lp->tx_new) {
diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.3.46/linux/drivers/net/sunqe.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/sunqe.c	Thu Feb 17 09:18:47 2000
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.44 2000/02/10 21:14:25 davem Exp $
+/* $Id: sunqe.c,v 1.45 2000/02/16 10:36:20 davem Exp $
  * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
  *          Once again I am out to prove that every ethernet
  *          controller out there can be most efficiently programmed
@@ -481,7 +481,7 @@
 			}
 			if (qe_status & CREG_STAT_RXIRQ)
 				qe_rx(qep);
-			if (test_bit(LINK_STATE_XOFF, &qep->dev->state) &&
+			if (netif_queue_stopped(qep->dev) &&
 			    (qe_status & CREG_STAT_TXIRQ)) {
 				spin_lock(&qep->lock);
 				qe_tx_reclaim(qep);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.3.46/linux/drivers/net/tlan.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/tlan.c	Thu Feb 17 15:32:46 2000
@@ -694,10 +694,7 @@
 
 	if ( ! priv->phyOnline ) {
 		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s PHY is not ready\n", dev->name );
-		if (in_irq())
-			dev_kfree_skb_irq(skb);
-		else
-			dev_kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		return 0;
 	}
 
@@ -754,12 +751,8 @@
 
 	CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
 
-	if ( bbuf ) {
-		if (in_irq())
-			dev_kfree_skb_irq(skb);
-		else
-			dev_kfree_skb(skb);
-	}
+	if ( bbuf )
+		dev_kfree_skb_any(skb);
 		
 	dev->trans_start = jiffies;
 	return 0;
@@ -1626,10 +1619,7 @@
 			list = priv->txList + i;
 			skb = (struct sk_buff *) list->buffer[9].address;
 			if ( skb ) {
-				if (in_irq())
-					dev_kfree_skb_irq( skb );
-				else
-					dev_kfree_skb( skb );
+				dev_kfree_skb_any( skb );
 				list->buffer[9].address = 0;
 			}
 		}
@@ -1638,10 +1628,7 @@
 			list = priv->rxList + i;
 			skb = (struct sk_buff *) list->buffer[9].address;
 			if ( skb ) {
-				if (in_irq())
-					dev_kfree_skb_irq( skb );
-				else
-					dev_kfree_skb( skb );
+				dev_kfree_skb_any( skb );
 				list->buffer[9].address = 0;
 			}
 		}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- v2.3.46/linux/drivers/net/tokenring/ibmtr.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/tokenring/ibmtr.c	Thu Feb 17 09:18:47 2000
@@ -1177,7 +1177,7 @@
 						      DPRINTK("New ring status: %02X\n", ring_status);
 
 					      if (ring_status & LOG_OVERFLOW) {
-						      if (test_bit(LINK_STATE_XOFF, &dev->state))
+						      if (netif_queue_stopped(dev))
                                                               ti->readlog_pending = 1;
 						      else
                                                               ibmtr_readlog(dev);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c
--- v2.3.46/linux/drivers/net/tokenring/olympic.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/tokenring/olympic.c	Thu Feb 17 09:18:47 2000
@@ -1152,7 +1152,7 @@
 	struct sockaddr *saddr = addr ; 
 	struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; 
 
-	if (test_bit(LINK_STATE_START, &dev->state)) { 
+	if (netif_running(dev)) { 
 		printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; 
 		return -EIO ; 
 	}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.3.46/linux/drivers/net/tulip.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/tulip.c	Sun Feb 20 20:13:21 2000
@@ -142,7 +142,7 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/unaligned.h>
-
+#include <asm/delay.h>
 
 
 /* A few user-configurable values. */
@@ -259,7 +259,7 @@
 
 enum tbl_flag {
 	HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
-	HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+	HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
 	HAS_PNICNWAY=0x80, HAS_NWAY143=0x40,	/* Uses internal NWay xcvr. */
 	HAS_8023X=0x100,
 };
@@ -275,7 +275,7 @@
   { "Digital DS21140 Tulip", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
   { "Digital DS21143 Tulip", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
 	t21142_timer },
   { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
 	HAS_MII | HAS_PNICNWAY, pnic_timer },
@@ -294,10 +294,10 @@
   { "Compex 9881 PMAC", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
   { "Intel DS21145 Tulip", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143,
 	t21142_timer },
   { "Xircom tulip work-alike", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
 	t21142_timer },
   {0},
 };
@@ -316,7 +316,7 @@
 	COMET,
 	COMPEX9881,
 	I21145,
-	XIRCLONE,
+	X3201_3,
 };
 
 
@@ -334,7 +334,7 @@
 	{ 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
 	{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
-	{ 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, XIRCLONE },
+	{ 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
 	{0},
 };
 MODULE_DEVICE_TABLE(pci,tulip_pci_tbl);
@@ -465,6 +465,7 @@
 	int ttimer;
 	int susp_rx;
 	unsigned long nir;
+	unsigned long base_addr;
 	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
@@ -473,7 +474,6 @@
 static int mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static void select_media(struct net_device *dev, int startup);
-static int tulip_open(struct net_device *dev);
 /* Chip-specific media selection (timer functions prototyped above). */
 static void t21142_lnk_change(struct net_device *dev, int csr5);
 static void t21142_start_nway(struct net_device *dev);
@@ -486,7 +486,10 @@
 static int tulip_refill_rx(struct net_device *dev);
 static int tulip_rx(struct net_device *dev);
 static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int tulip_open(struct net_device *dev);
 static int tulip_close(struct net_device *dev);
+static void tulip_up(struct net_device *dev);
+static void tulip_down(struct net_device *dev);
 static struct net_device_stats *tulip_get_stats(struct net_device *dev);
 static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
@@ -725,7 +728,7 @@
 #define EE_READ_CMD		(6)
 
 /* Note: this routine returns extra data bits for size detection. */
-static int read_eeprom(long ioaddr, int location, int addr_len)
+static int __devinit read_eeprom(long ioaddr, int location, int addr_len)
 {
 	int i;
 	unsigned retval = 0;
@@ -893,9 +896,60 @@
 	return;
 }
 
-
-static int
-tulip_open(struct net_device *dev)
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+   manipulated.  Keith Owens <kaos@ocs.com.au>. */
+
+static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
+{
+	long ioaddr = tp->base_addr;
+	const int strict_bits = 0x0060e202;
+	int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+	long flags;
+
+	/* really a hw lock */
+	spin_lock_irqsave (&tp->tx_lock, flags);
+
+	if (tp->chip_id != X3201_3)
+		goto out_write;
+
+	newcsr6 &= 0x726cfeca;	/* mask out the reserved CSR6 bits that always */
+	/* read 0 on the Xircom cards */
+	newcsr6 |= 0x320c0000;	/* or in the reserved bits that always read 1 */
+	currcsr6 = inl (ioaddr + CSR6);
+	if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+	    ((currcsr6 & ~0x2002) == 0))
+		goto out_write;
+
+	/* make sure the transmitter and receiver are stopped first */
+	currcsr6 &= ~0x2002;
+	while (1) {
+		csr5 = inl (ioaddr + CSR5);
+		if (csr5 == 0xffffffff)
+			break;	/* cannot read csr5, card removed? */
+		csr5_22_20 = csr5 & 0x700000;
+		csr5_19_17 = csr5 & 0x0e0000;
+		if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+		    (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+			break;	/* both are stopped or suspended */
+		if (!--attempts) {
+			printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts,"
+				"csr5=0x%08x\n", csr5);
+			goto out_write;
+		}
+		outl (currcsr6, ioaddr + CSR6);
+		udelay (1);
+	}
+
+out_write:
+	/* now it is safe to change csr6 */
+	outl (newcsr6, ioaddr + CSR6);
+
+	spin_unlock_irqrestore (&tp->lock, flags);
+}
+
+
+static void tulip_up(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
@@ -903,19 +957,16 @@
 	int i;
 
 	/* Wake the chip from sleep/snooze mode. */
-	if (tp->flags & HAS_PWRDWN)
+	if (tp->flags & HAS_ACPI)
 		pci_write_config_dword(tp->pdev, 0x40, 0);
 
 	/* On some chip revs we must set the MII/SYM port before the reset!? */
 	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
-		outl(0x00040000, ioaddr + CSR6);
+		outl_CSR6 (tp, 0x00040000);
 
 	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
 	outl(0x00000001, ioaddr + CSR0);
 
-	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))
-		return -EAGAIN;
-
 	/* Deassert reset.
 	   Wait the specified 50 PCI cycles after a reset by initializing
 	   Tx and Rx queues and the address filter list. */
@@ -924,22 +975,6 @@
 	if (tulip_debug > 1)
 		printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
 
-	MOD_INC_USE_COUNT;
-
-	spin_lock_init(&tp->tx_lock);
-	tulip_init_ring(dev);
-
-#if 0
-	if (tp->chip_id == PNIC2) {
-		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
-		u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)));
-		addr_high = (dev->dev_addr[4]<<8) + (dev->dev_addr[5]<<0);
-		outl((dev->dev_addr[0]<<8) + dev->dev_addr[1] +
-			 (dev->dev_addr[2]<<24) + (dev->dev_addr[3]<<16),
-			 ioaddr + 0xB0);
-		outl(addr_high + (addr_high<<16), ioaddr + 0xB8);
-	}
-#endif
 	if (tp->flags & MC_HASH_ONLY) {
 		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
 		u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
@@ -1022,7 +1057,7 @@
 				printk(KERN_INFO "%s: Using MII transceiver %d, status "
 					   "%4.4x.\n",
 					   dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
-			outl(0x82020000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x82020000);
 			tp->csr6 = 0x820E0000;
 			dev->if_port = 11;
 			outl(0x0000, ioaddr + CSR13);
@@ -1072,13 +1107,13 @@
 		select_media(dev, 1);
 
 	/* Start the chip's Tx to process setup frame. */
-	outl(tp->csr6, ioaddr + CSR6);
-	outl(tp->csr6 | 0x2000, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6);
+	outl_CSR6(tp, tp->csr6 | 0x2000);
 
 	/* Enable interrupts by setting the interrupt mask. */
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6 | 0x2002);
 	outl(0, ioaddr + CSR2);		/* Rx poll demand */
 
 	if (tulip_debug > 2) {
@@ -1094,11 +1129,28 @@
 	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 	add_timer(&tp->timer);
 
-	netif_start_queue(dev);
+	netif_device_attach(dev);
+}
+
+
+static int
+tulip_open(struct net_device *dev)
+{
+	MOD_INC_USE_COUNT;
+	
+	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
 
+	tulip_init_ring (dev);
+	
+	tulip_up (dev);
+	
 	return 0;
 }
 
+
 /* Set up the transceiver control registers for the selected media type. */
 static void select_media(struct net_device *dev, int startup)
 {
@@ -1314,7 +1366,6 @@
   */
 static int check_duplex(struct net_device *dev)
 {
-	long ioaddr = dev->base_addr;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int mii_reg1, mii_reg5, negotiated, duplex;
 
@@ -1346,8 +1397,8 @@
 			tp->csr6 &= ~0x00400000;
 		if (tp->full_duplex) tp->csr6 |= 0x0200;
 		else				 tp->csr6 &= ~0x0200;
-		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x0002);
+		outl_CSR6(tp, tp->csr6 | 0x2002);
 		if (tulip_debug > 0)
 			printk(KERN_INFO "%s: Setting %s-duplex based on MII"
 				   "#%d link partner capability of %4.4x.\n",
@@ -1492,8 +1543,8 @@
 					   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);
+			outl_CSR6(tp, tp->csr6 | 0x0002);
+			outl_CSR6(tp, tp->csr6 | 0x2002);
 			next_tick = (24*HZ)/10;
 			break;
 		}
@@ -1513,6 +1564,7 @@
 	add_timer(&tp->timer);
 }
 
+
 /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
    of available transceivers.  */
 static void t21142_timer(unsigned long data)
@@ -1573,8 +1625,8 @@
 			tp->csr6 &= 0x00D5;
 			tp->csr6 |= new_csr6;
 			outl(0x0301, ioaddr + CSR12);
-			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			outl_CSR6(tp, tp->csr6 | 0x0002);
+			outl_CSR6(tp, tp->csr6 | 0x2002);
 		}
 		next_tick = 3*HZ;
 	}
@@ -1583,6 +1635,7 @@
 	add_timer(&tp->timer);
 }
 
+
 static void t21142_start_nway(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1599,7 +1652,7 @@
 	outl(0x0001, ioaddr + CSR13);
 	outl(csr14, ioaddr + CSR14);
 	tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
-	outl(tp->csr6, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6);
 	if (tp->mtable  &&  tp->mtable->csr15dir) {
 		outl(tp->mtable->csr15dir, ioaddr + CSR15);
 		outl(tp->mtable->csr15val, ioaddr + CSR15);
@@ -1608,6 +1661,7 @@
 	outl(0x1301, ioaddr + CSR12); 		/* Trigger NWAY. */
 }
 
+
 static void t21142_lnk_change(struct net_device *dev, int csr5)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1664,12 +1718,12 @@
 			outl(1, ioaddr + CSR13);
 		}
 #if 0							/* Restart shouldn't be needed. */
-		outl(tp->csr6 | 0x0000, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x0000);
 		if (debug > 2)
 			printk(KERN_DEBUG "%s:  Restarting Tx and Rx, CSR5 is %8.8x.\n",
 				   dev->name, inl(ioaddr + CSR5));
 #endif
-		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x2002);
 		if (debug > 2)
 			printk(KERN_DEBUG "%s:  Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
 				   dev->name, tp->csr6, inl(ioaddr + CSR6),
@@ -1715,11 +1769,12 @@
 		tp->csr6 = 0x83860000;
 		outl(0x0003FF7F, ioaddr + CSR14);
 		outl(0x0301, ioaddr + CSR12);
-		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x0002);
+		outl_CSR6(tp, tp->csr6 | 0x2002);
 	}
 }
 
+
 static void mxic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
@@ -1737,6 +1792,7 @@
 	}
 }
 
+
 static void pnic_do_nway(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1763,12 +1819,15 @@
 				   dev->name, phy_reg, medianame[dev->if_port]);
 		if (tp->csr6 != new_csr6) {
 			tp->csr6 = new_csr6;
-			outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
-			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			/* Restart Tx */
+			outl_CSR6(tp, tp->csr6 | 0x0002);
+			outl_CSR6(tp, tp->csr6 | 0x2002);
 			dev->trans_start = jiffies;
 		}
 	}
 }
+
+
 static void pnic_lnk_change(struct net_device *dev, int csr5)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1782,7 +1841,7 @@
 		outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
 		if (! tp->nwayset  ||  jiffies - dev->trans_start > 1*HZ) {
 			tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
-			outl(tp->csr6, ioaddr + CSR6);
+			outl_CSR6(tp, tp->csr6);
 			outl(0x30, ioaddr + CSR12);
 			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
 			dev->trans_start = jiffies;
@@ -1792,6 +1851,8 @@
 		outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
 	}
 }
+
+
 static void pnic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
@@ -1842,8 +1903,9 @@
 			}
 			if (tp->csr6 != new_csr6) {
 				tp->csr6 = new_csr6;
-				outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				/* Restart Tx */
+				outl_CSR6(tp, tp->csr6 | 0x0002);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 				dev->trans_start = jiffies;
 				if (tulip_debug > 1)
 					printk(KERN_INFO "%s: Changing PNIC configuration to %s "
@@ -1965,8 +2027,8 @@
 #endif
 
 	/* Stop and restart the chip's Tx processes . */
-	outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6 | 0x0002);
+	outl_CSR6(tp, tp->csr6 | 0x2002);
 	/* Trigger an immediate transmit demand. */
 	outl(0, ioaddr + CSR1);
 
@@ -2173,8 +2235,8 @@
 					printk(KERN_WARNING "%s: The transmitter stopped."
 						   "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
 						   dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
-				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				outl_CSR6(tp, tp->csr6 | 0x0002);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 			}
 			spin_unlock(&tp->tx_lock);
 		}
@@ -2190,14 +2252,14 @@
 				else
 					tp->csr6 |= 0x00200000;  /* Store-n-forward. */
 				/* Restart the transmit process. */
-				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				outl_CSR6(tp, tp->csr6 | 0x0002);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 				outl(0, ioaddr + CSR1);
 			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
 				tp->stats.rx_errors++;
 				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 			}
 			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
 				if (tp->link_change)
@@ -2378,69 +2440,79 @@
 	return received;
 }
 
-static int
-tulip_close(struct net_device *dev)
+
+static void tulip_down (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
-	int i;
+	struct tulip_private *tp = (struct tulip_private *) dev->priv;
 
-	netif_stop_queue(dev);
+	netif_device_detach (dev);
 
-	if (tulip_debug > 1)
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-			   dev->name, inl(ioaddr + CSR5));
+	del_timer (&tp->timer);
 
 	/* Disable interrupts by clearing the interrupt mask. */
-	outl(0x00000000, ioaddr + CSR7);
+	outl (0x00000000, ioaddr + CSR7);
+
 	/* Stop the Tx and Rx processes. */
-	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+	outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002);
+
 	/* 21040 -- Leave the card in 10baseT state. */
 	if (tp->chip_id == DC21040)
-		outl(0x00000004, ioaddr + CSR13);
+		outl (0x00000004, ioaddr + CSR13);
 
-	if (inl(ioaddr + CSR6) != 0xffffffff)
-		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+	if (inl (ioaddr + CSR6) != 0xffffffff)
+		tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff;
+
+	dev->if_port = tp->saved_if_port;
+
+	/* Leave the driver in snooze, not sleep, mode. */
+	if (tp->flags & HAS_ACPI)
+		pci_write_config_dword (tp->pdev, 0x40, 0x40000000);
+}
+  
+  
+static int tulip_close (struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *) dev->priv;
+	int i;
 
-	del_timer(&tp->timer);
+	tulip_down (dev);
 
-	free_irq(dev->irq, dev);
+	if (tulip_debug > 1)
+		printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+			dev->name, inl (ioaddr + CSR5));
 
-	dev->if_port = tp->saved_if_port;
+	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 Tulip chip. */
+		tp->rx_ring[i].status = 0;	/* Not owned by Tulip chip. */
 		tp->rx_ring[i].length = 0;
-		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+		tp->rx_ring[i].buffer1 = 0xBADF00D0;	/* An invalid address. */
 		if (skb) {
-			dev_kfree_skb(skb);
+			dev_kfree_skb (skb);
 		}
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (tp->tx_skbuff[i])
-			dev_kfree_skb(tp->tx_skbuff[i]);
+			dev_kfree_skb (tp->tx_skbuff[i]);
 		tp->tx_skbuff[i] = 0;
 	}
 
-	/* Leave the driver in snooze, not sleep, mode. */
-	if (tp->flags & HAS_PWRDWN)
-		pci_write_config_dword(tp->pdev, 0x40, 0x40000000);
-
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
 
-static struct enet_statistics *
-tulip_get_stats(struct net_device *dev)
+static struct enet_statistics *tulip_get_stats(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 
 	return &tp->stats;
@@ -2672,7 +2744,7 @@
 			outl(0, ioaddr + CSR1);
 		}
 	}
-	outl(csr6 | 0x0000, ioaddr + CSR6);
+	outl_CSR6(tp, csr6 | 0x0000);
 }
 
 
@@ -2697,10 +2769,10 @@
 	board_idx++;
 
 	if (tulip_debug > 0  &&  did_version++ == 0)
-		printk(KERN_INFO "%s", version);
+		printk (KERN_INFO "%s", version);
 
         if( pdev->subsystem_vendor == 0x1376 ){
-		printk(KERN_ERR "tulip: skipping LMC card.\n");
+		printk (KERN_ERR PFX "skipping LMC card.\n");
 		return -ENODEV;
 	}
 	
@@ -2709,31 +2781,37 @@
 
 	/* Make certain the data structures are quadword aligned. */
 	dev = init_etherdev (NULL, sizeof (*tp));
-	if (!dev)
+	if (!dev) {
+		printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
 		return -ENOMEM;
+	}
 
 	/* We do a request_region() only to register /proc/ioports info. */
 	/* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
-	if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name))
+	if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) {
+		printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
+		goto err_out_free_netdev;
+	}
+
+	if (pci_enable_device(pdev)) {
+		printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n",
+			pdev->vendor, pdev->device,
+			pdev->bus->number, pdev->devfn);
 		goto err_out_free_netdev;
+	}
 
-	pci_enable_device (pdev);
+	pci_set_master(pdev);
 
 	tp = dev->priv;
 	memset(tp, 0, sizeof(*tp));
 
 	pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
 
-	/* Bring the 21041/21143 out of sleep mode.
-	   Caution: Snooze mode does not work with some boards! */
-	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
-		pci_write_config_dword(pdev, 0x40, 0x00000000);
-
 	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
 		   dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
 
 	/* Stop the chip's Tx and Rx processes. */
-	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+	outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002);
 	/* Clear the missed-packet counter. */
 	(volatile int)inl(ioaddr + CSR8);
 
@@ -2835,6 +2913,7 @@
 	tp->flags = tulip_tbl[chip_idx].flags;
 	tp->csr0 = csr0;
 	tp->pdev = pdev;
+	tp->base_addr = dev->base_addr;
 
 	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
 	   And the ASIX must have a burst limit or horrible things happen. */
@@ -2853,6 +2932,7 @@
 #ifdef TULIP_NO_MEDIA_SWITCH
 	tp->medialock = 1;
 #endif
+	tp->tx_lock = SPIN_LOCK_UNLOCKED;
 
 	/* The lower four bits are the media type. */
 	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
@@ -2962,7 +3042,7 @@
 		outl(0x00000000, ioaddr + CSR13);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
-		outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
+		outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200);
 		outl(0x0000EF05, ioaddr + CSR13);
 		break;
 	case DC21040:
@@ -2976,10 +3056,10 @@
 	case DC21142:
 	case PNIC2:
 		if (tp->mii_cnt  ||  media_cap[dev->if_port] & MediaIsMII) {
-			outl(0x82020000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x82020000);
 			outl(0x0000, ioaddr + CSR13);
 			outl(0x0000, ioaddr + CSR14);
-			outl(0x820E0000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x820E0000);
 		} else
 			t21142_start_nway(dev);
 		break;
@@ -2987,19 +3067,19 @@
 		if ( ! tp->mii_cnt) {
 			tp->nway = 1;
 			tp->nwayset = 0;
-			outl(0x00420000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x00420000);
 			outl(0x30, ioaddr + CSR12);
-			outl(0x0001F078, ioaddr + 0xB8);
-			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+			outl_CSR6(tp, 0x0001F078);
+			outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */
 		}
 		break;
 	case MX98713: case COMPEX9881:
-		outl(0x00000000, ioaddr + CSR6);
+		outl_CSR6(tp, 0x00000000);
 		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
 		outl(0x00000001, ioaddr + CSR13);
 		break;
 	case MX98715: case MX98725:
-		outl(0x01a80000, ioaddr + CSR6);
+		outl_CSR6(tp, 0x01a80000);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00001000, ioaddr + CSR12);
 		break;
@@ -3008,7 +3088,8 @@
 		break;
 	}
 
-	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
+	/* put the chip in snooze mode until opened */
+	if (tulip_tbl[chip_idx].flags & HAS_ACPI)
 		pci_write_config_dword(pdev, 0x40, 0x40000000);
 
 	return 0;
@@ -3024,20 +3105,8 @@
 {
 	struct net_device *dev = pdev->driver_data;
 
-	if (dev) {
-		long ioaddr = dev->base_addr;
-		struct tulip_private *tp = (struct tulip_private *)dev->priv;
-		int csr6 = inl(ioaddr + CSR6);
-		/* Disable interrupts, stop the chip, gather stats. */
-		if (csr6 != 0xffffffff) {
-			outl(0x00000000, ioaddr + CSR7);
-			outl(csr6 & ~0x2002, ioaddr + CSR6);
-			tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-		}
-		tulip_close(dev);
-		/* Put the 21143 into sleep mode. */
-		pci_write_config_dword(pdev, 0x40,0x80000000);
-	}
+	if (dev && netif_device_present (dev))
+		tulip_down (dev);
 }
 
 
@@ -3045,10 +3114,8 @@
 {
 	struct net_device *dev = pdev->driver_data;
 
-	if (dev) {
-		pci_write_config_dword(pdev, 0x40, 0x0000);
-		tulip_open(dev);
-	}
+	if (dev && !netif_device_present (dev))
+		tulip_up (dev);
 }
 
 
@@ -3078,7 +3145,7 @@
 
 static int __init tulip_init (void)
 {
-	return pci_register_driver (&tulip_driver) > 0 ? 0 : -ENODEV;
+	return pci_module_init (&tulip_driver);
 }
 
 
diff -u --recursive --new-file v2.3.46/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.3.46/linux/drivers/net/via-rhine.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/via-rhine.c	Thu Feb 17 09:18:47 2000
@@ -869,7 +869,7 @@
 			np->tx_skbuff[entry] = 0;
 		}
 		if (np->tx_full &&
-		    test_bit(LINK_STATE_XOFF, &dev->flags) &&
+		    netif_queue_stopped(dev) &&
 		    np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
 			/* The ring is no longer full, clear tbusy. */
 			np->tx_full = 0;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.3.46/linux/drivers/net/wan/cycx_x25.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/wan/cycx_x25.c	Thu Feb 17 09:18:47 2000
@@ -505,7 +505,7 @@
 	x25_channel_t *chan = dev->priv;
 	cycx_t *card = chan->card;
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		return -EBUSY; /* only one open is allowed */ 
 
 	netif_start_queue(dev);
@@ -1564,7 +1564,7 @@
 		x25_channel_t *chan = dev->priv;
 
 		printk(KERN_INFO "%-5.5s %-15.15s   %d     ETH_P_%s\n",
-				 chan->name, chan->addr, test_bit(LINK_STATE_XOFF, &dev->state),
+				 chan->name, chan->addr, netif_queue_stopped(dev),
 				 chan->protocol == ETH_P_IP ? "IP" : "X25");
 		dev = chan->slave;
 	}
diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c
--- v2.3.46/linux/drivers/net/wan/dlci.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/net/wan/dlci.c	Thu Feb 17 09:18:47 2000
@@ -361,7 +361,7 @@
 	if (!*(short *)(dev->dev_addr))
 		return(-EINVAL);
 
-	if (!test_bit(LINK_STATE_START, &dlp->slave->state))
+	if (!netif_running(dlp->slave))
 		return(-ENOTCONN);
 
 	flp = dlp->slave->priv;
@@ -495,7 +495,7 @@
 	if (!master)
 		return(-ENODEV);
 
-	if (test_bit(LINK_STATE_START, &master->state))
+	if (netif_running(master))
 		return(-EBUSY);
 
 	dlp = master->priv;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- v2.3.46/linux/drivers/net/wan/lapbether.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/wan/lapbether.c	Thu Feb 17 09:18:47 2000
@@ -163,7 +163,7 @@
 	
 	dev = lapbeth_get_x25_dev(dev);
 
-	if (dev == NULL || test_bit(LINK_STATE_START, &dev->state) == 0) {
+	if (dev == NULL || !netif_running(dev)) {
 		kfree_skb(skb);
 		return 0;
 	}
@@ -215,7 +215,7 @@
 	 * Just to be *really* sure not to send anything if the interface
 	 * is down, the ethernet device may have gone.
 	 */
-	if (!test_bit(LINK_STATE_START, &dev->state)) {
+	if (!netif_running(dev)) {
 		lapbeth_check_devices(dev);
 		kfree_skb(skb);
 		return -ENODEV;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c
--- v2.3.46/linux/drivers/net/wan/sbni.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/wan/sbni.c	Thu Feb 17 09:18:47 2000
@@ -1081,7 +1081,7 @@
 	}
 	sti();
 	outb(csr0 | RC_CHK, dev->base_addr + CSR0);
-	if(test_bit(LINK_STATE_START, &dev->state))
+	if(netif_running(dev))
 	{
 		struct timer_list* watchdog = &lp->watchdog; 
 		init_timer(watchdog);
@@ -1171,7 +1171,7 @@
 	/* struct net_local *lp = (struct net_local *)dev->priv; */
 	struct sockaddr *saddr = addr;
 	
-	if(test_bit(LINK_STATE_START, &dev->state))
+	if(netif_running(dev))
 	{
 		/* Only possible while card isn't started */
 		return -EBUSY;
diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/sdla.c linux/drivers/net/wan/sdla.c
--- v2.3.46/linux/drivers/net/wan/sdla.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/net/wan/sdla.c	Thu Feb 17 09:18:47 2000
@@ -510,7 +510,7 @@
 
 	flp->dlci[i] = abs(flp->dlci[i]);
 
-	if (test_bit(LINK_STATE_START, &slave->state) && (flp->config.station == FRAD_STATION_NODE))
+	if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
 		sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
 
 	return(0);
@@ -532,7 +532,7 @@
 
 	flp->dlci[i] = -abs(flp->dlci[i]);
 
-	if (test_bit(LINK_STATE_START, &slave->state) && (flp->config.station == FRAD_STATION_NODE))
+	if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
 		sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
 
 	return(0);
@@ -565,7 +565,7 @@
 	flp->dlci[i] = -*(short *)(master->dev_addr);
 	master->mtu = slave->mtu;
 
-	if (test_bit(LINK_STATE_START, &slave->state)) {
+	if (netif_running(dev)) {
 		if (flp->config.station == FRAD_STATION_CPE)
 			sdla_reconfig(slave);
 		else
@@ -594,7 +594,7 @@
 
 	MOD_DEC_USE_COUNT;
 
-	if (test_bit(LINK_STATE_START, &slave->state)) {
+	if (netif_running(slave)) {
 		if (flp->config.station == FRAD_STATION_CPE)
 			sdla_reconfig(slave);
 		else
@@ -624,7 +624,7 @@
 
 	ret = SDLA_RET_OK;
 	len = sizeof(struct dlci_conf);
-	if (test_bit(LINK_STATE_START, &slave->state)) {
+	if (netif_running(slave)) {
 		if (get)
 			ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
 			            NULL, 0, &dlp->config, &len);
@@ -1104,7 +1104,7 @@
 
 	if (!get)
 	{
-		if (test_bit(LINK_STATE_START, &dev->state))
+		if (netif_running(dev))
 			return(-EBUSY);
 
 		if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
@@ -1167,7 +1167,7 @@
 	else
 	{
 		/* no sense reading if the CPU isn't started */
-		if (test_bit(LINK_STATE_START, &dev->state))
+		if (netif_running(dev))
 		{
 			size = sizeof(data);
 			if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
@@ -1316,7 +1316,7 @@
 
 	flp = dev->priv;
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		return(-EBUSY);
 
 	/* for now, you can't change the MTU! */
diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c
--- v2.3.46/linux/drivers/net/wan/x25_asy.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/wan/x25_asy.c	Thu Feb 17 09:18:47 2000
@@ -301,7 +301,7 @@
 	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
 
 	/* First make sure we're connected. */
-	if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state))
+	if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
 		return;
 
 	if (sl->xleft <= 0)  
@@ -340,7 +340,7 @@
 	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
 	int err;
 
-	if (!test_bit(LINK_STATE_START, &sl->dev->state))
+	if (!netif_running(sl->dev))
 	{
 		printk("%s: xmit call when iface is down\n", dev->name);
 		return 1;
@@ -406,7 +406,7 @@
 static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
 {
 	struct x25_asy *sl=token;
-	if(test_bit(LINK_STATE_XOFF, &sl->dev->state))
+	if (netif_queue_stopped(sl->dev))
 	{
 		printk(KERN_ERR "x25_asy: tbusy drop\n");
 		kfree_skb(skb);
@@ -563,7 +563,7 @@
 {
 	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
 
-	if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state))
+	if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
 		return;
 
 	/*
@@ -903,7 +903,7 @@
 				 * VSV = if dev->start==0, then device
 				 * unregistered while close proc.
 				 */
-				if (test_bit(LINK_STATE_START, &x25_asy_ctrls[i]->dev.state))
+				if (netif_running(&(x25_asy_ctrls[i]->dev)))
 					unregister_netdev(&(x25_asy_ctrls[i]->dev));
 
 				kfree(x25_asy_ctrls[i]);
diff -u --recursive --new-file v2.3.46/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.3.46/linux/drivers/net/wavelan.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/wavelan.c	Thu Feb 17 09:18:47 2000
@@ -871,8 +871,7 @@
 	net_local *lp = (net_local *) dev->priv;
 
 	/* Check if we can do it now ! */
-	if (!test_bit(LINK_STATE_START, &dev->state) &&
-	    test_bit(LINK_STATE_XOFF, &dev->state)) {
+	if (!netif_running(dev) && netif_queue_stopped(dev)) {
 		lp->reconfig_82586 = 1;
 #ifdef DEBUG_CONFIG_INFO
 		printk(KERN_DEBUG
@@ -3713,7 +3712,7 @@
 
 	/* Check the state of the command unit. */
 	if (((status & SCB_ST_CNA) == SCB_ST_CNA) ||
-	    (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && test_bit(LINK_STATE_START, &dev->state))) {
+	    (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && netif_running(dev))) {
 #ifdef DEBUG_INTERRUPT_ERROR
 		printk(KERN_INFO
 		       "%s: wavelan_interrupt(): CU inactive -- restarting\n",
@@ -3724,7 +3723,7 @@
 
 	/* Check the state of the command unit. */
 	if (((status & SCB_ST_RNR) == SCB_ST_RNR) ||
-	    (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && test_bit(LINK_STATE_START, &dev->state))) {
+	    (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && netif_running(dev))) {
 #ifdef DEBUG_INTERRUPT_ERROR
 		printk(KERN_INFO
 		       "%s: wavelan_interrupt(): RU not ready -- restarting\n",
diff -u --recursive --new-file v2.3.46/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.3.46/linux/drivers/net/yellowfin.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/yellowfin.c	Sun Feb 20 09:06:14 2000
@@ -75,7 +75,6 @@
 #error You must compile this driver with "-O".
 #endif
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/modversions.h>
@@ -851,7 +850,7 @@
 	/* Code that should never be run!  Perhaps remove after testing.. */
 	{
 		static int stopit = 10;
-		if ((!(test_bit(LINK_STATE_START, &dev->state)))  &&  --stopit < 0) {
+		if ((!(netif_running(dev)))  &&  --stopit < 0) {
 			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
 				   dev->name);
 			free_irq(irq, dev);
@@ -1378,7 +1377,12 @@
 {
 	if (debug)					/* Emit version even if no cards detected. */
 		printk(KERN_INFO "%s", version);
-	return pci_register_driver (&yellowfin_driver) > 0 ? 0 : -ENODEV;
+
+	if (pci_register_driver (&yellowfin_driver) > 0)
+		return 0;
+
+	pci_unregister_driver (&yellowfin_driver);
+	return -ENODEV;
 }
 
 
diff -u --recursive --new-file v2.3.46/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.46/linux/drivers/parport/parport_pc.c	Thu Feb 10 17:11:12 2000
+++ linux/drivers/parport/parport_pc.c	Fri Feb 18 15:07:20 2000
@@ -561,7 +561,8 @@
 		if ((start ^ end) & ~0xffffUL)
 			maxlen = (0x10000 - start) & 0xffff;
 
-		dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length);
+		dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length,
+						       PCI_DMA_TODEVICE);
         } else {
 		/* above 16 MB we use a bounce buffer as ISA-DMA is not possible */
 		maxlen   = PAGE_SIZE;          /* sizeof(priv->dma_buf) */
@@ -661,7 +662,7 @@
 	frob_econtrol (port, 1<<3, 0);
 	
 	if (dma_handle)
-		pci_unmap_single(priv->dev, dma_handle, length);
+		pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE);
 
 	return length - left;
 }
diff -u --recursive --new-file v2.3.46/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.3.46/linux/drivers/pcmcia/cs.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/pcmcia/cs.c	Sun Feb 20 20:37:09 2000
@@ -82,13 +82,14 @@
 #else
 #define CB_OPT ""
 #endif
-#if defined(CONFIG_APM) || defined(CONFIG_ACPI)
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) || defined(CONFIG_ACPI)
 #define APM_OPT " [apm]"
 #else
 #define APM_OPT ""
 #endif
 #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \
-    !defined(CONFIG_APM) && !defined(CONFIG_ACPI)
+    !defined(CONFIG_APM) && !defined(CONFIG_APM_MODULE) && \
+    !defined(CONFIG_ACPI)
 #define OPTIONS " none"
 #else
 #define OPTIONS PCI_OPT CB_OPT APM_OPT
@@ -124,7 +125,7 @@
 static int io_speed		= 0;	/* ns */
 
 /* Optional features */
-#if defined(CONFIG_APM) || defined(CONFIG_ACPI)
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) || defined(CONFIG_ACPI)
 static int do_apm		= 1;
 MODULE_PARM(do_apm, "i");
 #else
diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- v2.3.46/linux/drivers/sbus/audio/audio.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sbus/audio/audio.c	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: audio.c,v 1.48 2000/02/09 22:33:19 davem Exp $
+/* $Id: audio.c,v 1.49 2000/02/17 05:52:41 davem Exp $
  * drivers/sbus/audio/audio.c
  *
  * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.3.46/linux/drivers/sbus/audio/cs4231.c	Tue Feb  1 01:35:44 2000
+++ linux/drivers/sbus/audio/cs4231.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: cs4231.c,v 1.42 2000/01/28 13:42:48 jj Exp $
+/* $Id: cs4231.c,v 1.43 2000/02/18 13:49:39 davem Exp $
  * drivers/sbus/audio/cs4231.c
  *
  * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -1171,11 +1171,11 @@
 static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
 {
 	struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
-	void (*dma_unmap_single)(struct sbus_dev *, dma_addr_t, size_t) = sbus_unmap_single;
+	void (*dma_unmap_single)(struct sbus_dev *, dma_addr_t, size_t, int) = sbus_unmap_single;
 
 #ifdef EB4231_SUPPORT
 	if (cs4231_chip->status & CS_STATUS_IS_EBUS)
-		dma_unmap_single = (void (*)(struct sbus_dev *, dma_addr_t, size_t)) pci_unmap_single;
+		dma_unmap_single = (void (*)(struct sbus_dev *, dma_addr_t, size_t, int)) pci_unmap_single;
 #endif
         /* zero out any info about what data we have as well */
         if (file->f_mode & FMODE_READ) {
@@ -1184,14 +1184,16 @@
                 if (cs4231_chip->input_dma_handle) {
 			dma_unmap_single(drv->dev,
 					 cs4231_chip->input_dma_handle,
-					 cs4231_chip->input_dma_size);
+					 cs4231_chip->input_dma_size,
+					 SBUS_DMA_FROMDEVICE);
                         cs4231_chip->input_dma_handle = 0;
                         cs4231_chip->input_dma_size = 0;
                 }
                 if (cs4231_chip->input_next_dma_handle) {
 			dma_unmap_single(drv->dev,
 					 cs4231_chip->input_next_dma_handle,
-					 cs4231_chip->input_next_dma_size);
+					 cs4231_chip->input_next_dma_size,
+					 SBUS_DMA_FROMDEVICE);
                         cs4231_chip->input_next_dma_handle = 0;
                         cs4231_chip->input_next_dma_size = 0;
                 }
@@ -1203,14 +1205,16 @@
                 if (cs4231_chip->output_dma_handle) {
 			dma_unmap_single(drv->dev,
 					 cs4231_chip->output_dma_handle,
-					 cs4231_chip->output_dma_size);
+					 cs4231_chip->output_dma_size,
+					 SBUS_DMA_TODEVICE);
                         cs4231_chip->output_dma_handle = 0;
                         cs4231_chip->output_dma_size = 0;
                 }
                 if (cs4231_chip->output_next_dma_handle) {
 			dma_unmap_single(drv->dev,
 					 cs4231_chip->output_next_dma_handle,
-					 cs4231_chip->output_next_dma_size);
+					 cs4231_chip->output_next_dma_size,
+					 SBUS_DMA_TODEVICE);
                         cs4231_chip->output_next_dma_handle = 0;
                         cs4231_chip->output_next_dma_size = 0;
                 }
@@ -1248,7 +1252,8 @@
         if (cs4231_chip->output_dma_handle) {
                 sbus_unmap_single(drv->dev,
                                   cs4231_chip->output_dma_handle,
-                                  cs4231_chip->output_dma_size);
+                                  cs4231_chip->output_dma_size,
+                                  SBUS_DMA_TODEVICE);
                 cs4231_chip->output_dma_handle = 0;
                 cs4231_chip->output_dma_size = 0;
                 cs4231_chip->playing_count--;
@@ -1267,7 +1272,8 @@
                 cs4231_chip->output_next_dma_handle =
                         sbus_map_single(drv->dev,
                                         (char *)cs4231_chip->output_ptr,
-                                        cs4231_chip->output_size);
+                                        cs4231_chip->output_size,
+                                        SBUS_DMA_TODEVICE);
                 cs4231_chip->output_next_dma_size = cs4231_chip->output_size;
                 sbus_writel(cs4231_chip->output_next_dma_handle,
                             cs4231_chip->regs + APCPNVA);
@@ -1297,7 +1303,8 @@
         if (cs4231_chip->output_dma_handle) {
 		pci_unmap_single((struct pci_dev *)drv->dev,
 				 cs4231_chip->output_dma_handle,
-				 cs4231_chip->output_dma_size);
+				 cs4231_chip->output_dma_size,
+                                 PCI_DMA_TODEVICE);
                 cs4231_chip->output_dma_handle = 0;
                 cs4231_chip->output_dma_size = 0;
                 cs4231_chip->playing_count--;
@@ -1316,7 +1323,8 @@
                 cs4231_chip->output_next_dma_handle =
 			pci_map_single((struct pci_dev *)drv->dev,
 				       (char *)cs4231_chip->output_ptr,
-				       cs4231_chip->output_size);
+				       cs4231_chip->output_size,
+                                       PCI_DMA_TODEVICE);
                 cs4231_chip->output_next_dma_size = cs4231_chip->output_size;
 
                 writel(cs4231_chip->output_next_dma_size,
@@ -1362,7 +1370,8 @@
         if (cs4231_chip->input_dma_handle) {
                 sbus_unmap_single(drv->dev,
                                   cs4231_chip->input_dma_handle,
-                                  cs4231_chip->input_dma_size);
+                                  cs4231_chip->input_dma_size,
+                                  SBUS_DMA_FROMDEVICE);
                 cs4231_chip->input_dma_handle = 0;
                 cs4231_chip->input_dma_size = 0;
                 cs4231_chip->recording_count--;
@@ -1384,7 +1393,8 @@
                 cs4231_chip->input_next_dma_handle =
                         sbus_map_single(drv->dev,
                                         (char *)cs4231_chip->input_ptr,
-                                        cs4231_chip->input_size);
+                                        cs4231_chip->input_size,
+                                        SBUS_DMA_FROMDEVICE);
                 cs4231_chip->input_next_dma_size = cs4231_chip->input_size;
                 sbus_writel(cs4231_chip->input_next_dma_handle,
                             cs4231_chip->regs + APCCNVA);
@@ -1418,7 +1428,8 @@
         if (cs4231_chip->input_dma_handle) {
 		pci_unmap_single((struct pci_dev *)drv->dev,
 				 cs4231_chip->input_dma_handle,
-				 cs4231_chip->input_dma_size);
+				 cs4231_chip->input_dma_size,
+                                 PCI_DMA_FROMDEVICE);
                 cs4231_chip->input_dma_handle = 0;
                 cs4231_chip->input_dma_size = 0;
                 cs4231_chip->recording_count--;
@@ -1441,7 +1452,8 @@
                 cs4231_chip->input_next_dma_handle =
 			pci_map_single((struct pci_dev *)drv->dev,
 				       (char *)cs4231_chip->input_ptr,
-				       cs4231_chip->input_size);
+				       cs4231_chip->input_size,
+                                       PCI_DMA_FROMDEVICE);
                 cs4231_chip->input_next_dma_size = cs4231_chip->input_size;
 
                 writel(cs4231_chip->input_next_dma_size,
@@ -1556,7 +1568,8 @@
         if (cs4231_chip->output_dma_handle) {
 		pci_unmap_single((struct pci_dev *)drv->dev,
 				 cs4231_chip->output_dma_handle,
-				 cs4231_chip->output_dma_size);
+				 cs4231_chip->output_dma_size,
+                                 PCI_DMA_TODEVICE);
                 cs4231_chip->output_dma_handle = 0;
                 cs4231_chip->output_dma_size = 0;
         }
@@ -1564,7 +1577,8 @@
         if (cs4231_chip->output_next_dma_handle) {
 		pci_unmap_single((struct pci_dev *)drv->dev,
 				 cs4231_chip->output_next_dma_handle,
-				 cs4231_chip->output_next_dma_size);
+				 cs4231_chip->output_next_dma_size,
+                                 PCI_DMA_TODEVICE);
                 cs4231_chip->output_next_dma_handle = 0;
                 cs4231_chip->output_next_dma_size = 0;
         }
@@ -1589,7 +1603,8 @@
         if (cs4231_chip->output_dma_handle) {
                 sbus_unmap_single(drv->dev,
                                   cs4231_chip->output_dma_handle,
-                                  cs4231_chip->output_dma_size);
+                                  cs4231_chip->output_dma_size,
+                                  SBUS_DMA_TODEVICE);
                 cs4231_chip->output_dma_handle = 0;
                 cs4231_chip->output_dma_size = 0;
         }
@@ -1597,7 +1612,8 @@
         if (cs4231_chip->output_next_dma_handle) {
                 sbus_unmap_single(drv->dev,
                                   cs4231_chip->output_next_dma_handle,
-                                  cs4231_chip->output_next_dma_size);
+                                  cs4231_chip->output_next_dma_size,
+                                  SBUS_DMA_TODEVICE);
                 cs4231_chip->output_next_dma_handle = 0;
                 cs4231_chip->output_next_dma_size = 0;
         }
@@ -1699,7 +1715,8 @@
         if (cs4231_chip->input_dma_handle) {
                 sbus_unmap_single(drv->dev,
                                   cs4231_chip->input_dma_handle,
-                                  cs4231_chip->input_dma_size);
+                                  cs4231_chip->input_dma_size,
+                                  SBUS_DMA_FROMDEVICE);
                 cs4231_chip->input_dma_handle = 0;
                 cs4231_chip->input_dma_size = 0;
         }
@@ -1707,7 +1724,8 @@
         if (cs4231_chip->input_next_dma_handle) {
                 sbus_unmap_single(drv->dev,
                                   cs4231_chip->input_next_dma_handle,
-                                  cs4231_chip->input_next_dma_size);
+                                  cs4231_chip->input_next_dma_size,
+                                  SBUS_DMA_FROMDEVICE);
                 cs4231_chip->input_next_dma_handle = 0;
                 cs4231_chip->input_next_dma_size = 0;
         }
@@ -1765,7 +1783,8 @@
         if (cs4231_chip->input_dma_handle) {
 		pci_unmap_single((struct pci_dev *)drv->dev,
 				 cs4231_chip->input_dma_handle,
-				 cs4231_chip->input_dma_size);
+				 cs4231_chip->input_dma_size,
+                                 PCI_DMA_FROMDEVICE);
                 cs4231_chip->input_dma_handle = 0;
                 cs4231_chip->input_dma_size = 0;
         }
@@ -1773,7 +1792,8 @@
         if (cs4231_chip->input_next_dma_handle) {
 		pci_unmap_single((struct pci_dev *)drv->dev,
 				 cs4231_chip->input_next_dma_handle,
-				 cs4231_chip->input_next_dma_size);
+				 cs4231_chip->input_next_dma_size,
+                                 PCI_DMA_FROMDEVICE);
                 cs4231_chip->input_next_dma_handle = 0;
                 cs4231_chip->input_next_dma_size = 0;
         }
diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c
--- v2.3.46/linux/drivers/sbus/audio/dbri.c	Tue Feb  1 01:35:44 2000
+++ linux/drivers/sbus/audio/dbri.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.18 2000/01/28 13:42:50 jj Exp $
+/* $Id: dbri.c,v 1.19 2000/02/18 13:49:42 davem Exp $
  * drivers/sbus/audio/dbri.c
  *
  * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -356,7 +356,8 @@
                 if (buffer)
                         sbus_unmap_single(dbri->sdev,
                                           dbri->descs[td].buffer_dvma,
-                                          dbri->descs[td].len);
+                                          dbri->descs[td].len,
+                                          SBUS_DMA_TODEVICE);
 
                 callback = dbri->descs[td].output_callback;
 		callback_arg = dbri->descs[td].output_callback_arg;
@@ -391,7 +392,8 @@
         if (buffer)
                 sbus_unmap_single(dbri->sdev,
                                   dbri->descs[rd].buffer_dvma,
-                                  dbri->descs[rd].len);
+                                  dbri->descs[rd].len,
+                                  SBUS_DMA_FROMDEVICE);
 
         callback = dbri->descs[rd].input_callback;
         if (callback != NULL)
@@ -592,7 +594,9 @@
 		if (buffer)
                         sbus_unmap_single(dbri->sdev,
                                           dbri->descs[desc].buffer_dvma,
-                                          dbri->descs[desc].len);
+                                          dbri->descs[desc].len,
+                                          output_callback != NULL ? SBUS_DMA_TODEVICE
+                                          : SBUS_DMA_FROMDEVICE);
 
 		dbri->descs[desc].inuse = 0;
 		desc = dbri->descs[desc].next;
@@ -863,7 +867,8 @@
                 return;
         }
 
-        dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len);
+        dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len,
+							 SBUS_DMA_TODEVICE);
         while (len > 0) {
                 int mylen;
 
@@ -907,6 +912,9 @@
         }
 
 	if (first_td == -1 || last_td == -1) {
+		sbus_unmap_single(dbri->sdev, dvma_buffer_base,
+				  dvma_buffer - dvma_buffer_base + len,
+				  SBUS_DMA_TODEVICE);
                 return;
         }
 
@@ -914,7 +922,7 @@
 
         dbri->descs[last_td].buffer = buffer;
         dbri->descs[last_td].buffer_dvma = dvma_buffer_base;
-        dbri->descs[last_td].len = len;
+        dbri->descs[last_td].len = dvma_buffer - dvma_buffer_base + len;
         dbri->descs[last_td].output_callback = callback;
         dbri->descs[last_td].output_callback_arg = callback_arg;
 
@@ -999,7 +1007,8 @@
         /* Make sure buffer size is multiple of four */
         len &= ~3;
 
-        bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len);
+        bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len,
+						       SBUS_DMA_FROMDEVICE);
 
 	while (len > 0) {
 		int rd, mylen;
@@ -1043,8 +1052,12 @@
 		len -= mylen;
         }
 
-	if (last_rd == -1 || first_rd == -1)
+	if (last_rd == -1 || first_rd == -1) {
+		sbus_unmap_single(dbri->sdev, bus_buffer_base,
+				  bus_buffer - bus_buffer_base + len,
+				  SBUS_DMA_FROMDEVICE);
                 return;
+	}
 
 	for (rd=first_rd; rd != -1; rd = dbri->descs[rd].next) {
 		dprintk(D_DESC, ("DBRI RD %d: %08x %08x %08x %08x\n",
@@ -1057,7 +1070,7 @@
 
 	dbri->descs[last_rd].buffer = buffer;
         dbri->descs[last_rd].buffer_dvma = bus_buffer_base;
-	dbri->descs[last_rd].len = len;
+	dbri->descs[last_rd].len = bus_buffer - bus_buffer_base + len;
 	dbri->descs[last_rd].input_callback = callback;
 	dbri->descs[last_rd].input_callback_arg = callback_arg;
 
diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.3.46/linux/drivers/sbus/char/bpp.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sbus/char/bpp.c	Sun Feb 20 08:48:46 2000
@@ -1027,7 +1027,6 @@
 	for (idx = 0; idx < BPP_NO; idx += 1) {
 		instances[idx].opened = 0;
 		probeLptPort(idx);
-		sprintf(devname, "%s%i", dev_name, idx);
 	}
 	devfs_handle = devfs_mk_dir (NULL, "bpp", 3, NULL);
 	devfs_register_series (devfs_handle, "%u", BPP_NO, DEVFS_FL_DEFAULT,
diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c
--- v2.3.46/linux/drivers/sbus/dvma.c	Wed Dec 29 13:13:18 1999
+++ linux/drivers/sbus/dvma.c	Thu Feb 17 09:26:31 2000
@@ -105,7 +105,8 @@
 		}
 
 		dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0,
-					 PAGE_SIZE, "dma");
+					 dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1,
+					 "dma");
 
 		dma->node = dma->sdev->prom_node;
 		
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.3.46/linux/drivers/scsi/aic7xxx.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/scsi/aic7xxx.c	Sun Feb 20 08:48:45 2000
@@ -719,6 +719,11 @@
 #define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
 
 /*
+ * The stored DMA mapping for single-buffer data transfers.
+ */
+#define aic7xxx_mapping(cmd)	     ((cmd)->SCp.phase)
+
+/*
  * So we can keep track of our host structs
  */
 static struct aic7xxx_host *first_aic7xxx = NULL;
@@ -2894,15 +2899,23 @@
   struct aic7xxx_scb *scbp;
   unsigned char queue_depth;
 
-  if (scb->sg_count == 1)
-    pci_unmap_single(p->pdev, le32_to_cpu(scb->sg_list[0].address),
-		     le32_to_cpu(scb->sg_list[0].length));
-  else if (scb->sg_count > 1)
+  if (cmd->use_sg > 1)
   {
     struct scatterlist *sg;
 
     sg = (struct scatterlist *)cmd->request_buffer;
-    pci_unmap_sg(p->pdev, sg, cmd->use_sg);
+    pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+  }
+  else if (cmd->request_bufflen)
+    pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
+		     cmd->request_bufflen,
+                     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+  if (scb->flags & SCB_SENSE)
+  {
+    pci_unmap_single(p->pdev,
+                     le32_to_cpu(scb->sg_list[0].address),
+                     sizeof(cmd->sense_buffer),
+                     PCI_DMA_FROMDEVICE);
   }
   if (scb->flags & SCB_RECOVERY_SCB)
   {
@@ -4887,7 +4900,8 @@
                 }
 		scb->sg_list[0].address =
                         cpu_to_le32(pci_map_single(p->pdev, sense_buffer,
-                                                   sizeof(cmd->sense_buffer)));
+                                                   sizeof(cmd->sense_buffer),
+                                                   PCI_DMA_FROMDEVICE));
                 hscb->data_pointer = scb->sg_list[0].address;
 
                 scb->flags |= SCB_SENSE;
@@ -10607,6 +10621,7 @@
   cmd->lun = 0;
   cmd->request_bufflen = 255;
   cmd->request_buffer = buffer;
+  cmd->sc_data_direction = SCSI_DATA_READ;
   cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
   cmd->bufflen = 0;
   cmd->buffer = NULL;
@@ -10954,7 +10969,7 @@
 
     sg = (struct scatterlist *)cmd->request_buffer;
     scb->sg_length = 0;
-    use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg);
+    use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
     /*
      * Copy the segments into the SG array.  NOTE!!! - We used to
      * have the first entry both in the data_pointer area and the first
@@ -10981,7 +10996,9 @@
     if (cmd->request_bufflen)
     {
       unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
-					    cmd->request_bufflen);
+					    cmd->request_bufflen,
+                                            scsi_to_pci_dma_dir(cmd->sc_data_direction));
+      aic7xxx_mapping(cmd) = address;
       scb->sg_list[0].address = cpu_to_le32(address);
       scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
       scb->sg_count = 1;
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- v2.3.46/linux/drivers/scsi/constants.c	Mon Jul  5 19:56:46 1999
+++ linux/drivers/scsi/constants.c	Wed Feb 16 20:21:45 2000
@@ -410,11 +410,13 @@
 #endif
 
 /* Print sense information */
-void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
+static 
+void print_sense_internal(const char * devclass, 
+			  const unsigned char * sense_buffer,
+			  kdev_t dev)
 {
     int i, s;
     int sense_class, valid, code;
-    unsigned char * sense_buffer = SCpnt->sense_buffer;
     const char * error = NULL;
     
     sense_class = (sense_buffer[0] >> 4) & 0x07;
@@ -423,8 +425,8 @@
     
     if (sense_class == 7) {	/* extended sense data */
 	s = sense_buffer[7] + 8;
-	if(s > sizeof(SCpnt->sense_buffer))
-           s = sizeof(SCpnt->sense_buffer);
+	if(s > SCSI_SENSE_BUFFERSIZE)
+	   s = SCSI_SENSE_BUFFERSIZE;
 	
 	if (!valid)
 	    printk("[valid=0] ");
@@ -455,10 +457,10 @@
 	
 #if (CONSTANTS & CONST_SENSE)
 	printk( "%s%s: sense key %s\n", devclass,
-	       kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[2] & 0x0f]);
+	       kdevname(dev), snstext[sense_buffer[2] & 0x0f]);
 #else
 	printk("%s%s: sns = %2x %2x\n", devclass,
-	       kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]);
+	       kdevname(dev), sense_buffer[0], sense_buffer[2]);
 #endif
 	
 	/* Check to see if additional sense information is available */
@@ -495,11 +497,11 @@
 #if (CONSTANTS & CONST_SENSE)
 	if (sense_buffer[0] < 15)
 	    printk("%s%s: old sense key %s\n", devclass,
-	      kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[0] & 0x0f]);
+	      kdevname(dev), snstext[sense_buffer[0] & 0x0f]);
 	else
 #endif
 	    printk("%s%s: sns = %2x %2x\n", devclass,
-	      kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]);
+	      kdevname(dev), sense_buffer[0], sense_buffer[2]);
 	
 	printk("Non-extended sense class %d code 0x%0x ", sense_class, code);
 	s = 4;
@@ -513,6 +515,18 @@
     printk("\n");
 #endif
     return;
+}
+
+void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
+{
+	print_sense_internal(devclass, SCpnt->sense_buffer,
+			     SCpnt->request.rq_dev);
+}
+
+void print_req_sense(const char * devclass, Scsi_Request * SRpnt)
+{
+	print_sense_internal(devclass, SRpnt->sr_sense_buffer,
+			     SRpnt->sr_request.rq_dev);
 }
 
 #if (CONSTANTS & CONST_MSG) 
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c
--- v2.3.46/linux/drivers/scsi/eata_dma_proc.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/eata_dma_proc.c	Fri Feb 18 15:07:20 2000
@@ -167,6 +167,7 @@
 	cmnd[9] = 0;
 
 	scmd->cmd_len = 10;
+	scmd->sc_data_direction = DATA_READ;
 	
 	/*
 	 * Do the command and wait for it to finish.
@@ -291,6 +292,7 @@
 	    cmnd[9] = 0;
 	    
 	    scmd->cmd_len = 10;
+	    scmd->sc_data_direction = SCSI_DATA_READ;
 
 	    /*
 	     * Do the command and wait for it to finish.
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.3.46/linux/drivers/scsi/esp.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/esp.c	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.91 2000/02/14 08:46:24 jj Exp $
+/* $Id: esp.c,v 1.92 2000/02/18 13:49:58 davem Exp $
  * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
  *
  * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -1414,7 +1414,8 @@
 		sp->SCp.buffers_residual = 0;
 		if (sp->request_bufflen) {
 			sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
-							       sp->SCp.this_residual);
+							       sp->SCp.this_residual,
+							       scsi_to_sbus_dma_dir(sp->sc_data_direction));
 			sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
 		} else {
 			sp->SCp.ptr = NULL;
@@ -1423,7 +1424,8 @@
 		sp->SCp.buffer = (struct scatterlist *) sp->buffer;
 		sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
 						       sp->SCp.buffer,
-						       sp->use_sg);
+						       sp->use_sg,
+						       scsi_to_sbus_dma_dir(sp->sc_data_direction));
 		sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
 		sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer));
 	}
@@ -1432,11 +1434,13 @@
 static void esp_release_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
 {
 	if (sp->use_sg) {
-		sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg);
+		sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg,
+			      scsi_to_sbus_dma_dir(sp->sc_data_direction));
 	} else if (sp->request_bufflen) {
 		sbus_unmap_single(esp->sdev,
 				  sp->SCp.have_data_in,
-				  sp->request_bufflen);
+				  sp->request_bufflen,
+				  scsi_to_sbus_dma_dir(sp->sc_data_direction));
 	}
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.3.46/linux/drivers/scsi/hosts.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/hosts.c	Wed Feb 16 20:21:45 2000
@@ -777,6 +777,14 @@
     retval->max_id = 8;      
     retval->max_lun = 8;
 
+    /*
+     * All drivers right now should be able to handle 12 byte commands.
+     * Every so often there are requests for 16 byte commands, but individual
+     * low-level drivers need to certify that they actually do something
+     * sensible with such commands.
+     */
+    retval->max_cmd_len = 12;
+
     retval->unique_id = 0;
     retval->io_port = 0;
     retval->hostt = tpnt;
@@ -787,6 +795,7 @@
 
 
     retval->host_blocked = FALSE;
+    retval->host_self_blocked = FALSE;
 
 #ifdef DEBUG
     printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.3.46/linux/drivers/scsi/hosts.h	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/hosts.h	Sun Feb 20 20:49:29 2000
@@ -362,6 +362,17 @@
      * initialized, as required.
      */
 
+    /*
+     * The maximum length of SCSI commands that this host can accept.
+     * Probably 12 for most host adapters, but could be 16 for others.
+     * For drivers that don't set this field, a value of 12 is
+     * assumed.  I am leaving this as a number rather than a bit
+     * because you never know what subsequent SCSI standards might do
+     * (i.e. could there be a 20 byte or a 24-byte command a few years
+     * down the road?).  
+     */
+    unsigned char max_cmd_len;
+
     int this_id;
     int can_queue;
     short cmd_per_lun;
@@ -379,6 +390,12 @@
      * Host has rejected a command because it was busy.
      */
     unsigned host_blocked:1;
+
+    /*
+     * Host has requested that no further requests come through for the
+     * time being.
+     */
+    unsigned host_self_blocked:1;
     
     /*
      * Host uses correct SCSI ordering not PC ordering. The bit is
@@ -412,6 +429,10 @@
  */
 extern void scsi_free_host_dev(Scsi_Device * SDpnt);
 extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt);
+
+extern void scsi_unblock_requests(struct Scsi_Host * SHpnt);
+extern void scsi_block_requests(struct Scsi_Host * SHpnt);
+extern void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel);
 
 typedef struct SHN
     {
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.3.46/linux/drivers/scsi/pci2000.c	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/pci2000.c	Fri Feb 18 14:50:03 2000
@@ -53,7 +53,15 @@
 #include "pci2000.h"
 #include "psi_roy.h"
 
-#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
+#include <linux/bios32.h>
+#endif
+
+struct proc_dir_entry Proc_Scsi_Pci2000 =
+	{ PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
 
 //#define DEBUG 1
 
@@ -120,6 +128,28 @@
 	return TRUE;
 	}
 /****************************************************************
+ *	Name:			WaitReadyLong	:LOCAL
+ *
+ *	Description:	Wait for controller ready.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE on not ready.
+ *
+ ****************************************************************/
+static int WaitReadyLong (PADAPTER2000 padapter)
+	{
+	ULONG	z;
+
+	for ( z = 0;  z < (5000 * 4);  z++ )
+		{
+		if ( !inb_p (padapter->cmd) )
+			return FALSE;
+		udelay (250);
+		};								
+	return TRUE;
+	}
+/****************************************************************
  *	Name:	OpDone	:LOCAL
  *
  *	Description:	Clean up operation and issue done to caller.
@@ -204,7 +234,7 @@
 	if ( WaitReady (padapter) )						// test for command register ready
 		return DID_TIME_OUT;
 	outb_p (cmd, padapter->cmd);					// issue command
-	if ( WaitReady (padapter) )						// wait for adapter ready
+	if ( WaitReadyLong (padapter) )					// wait for adapter ready
 		return DID_TIME_OUT;
 	return DID_OK;
 	}
@@ -232,13 +262,23 @@
 	int					pun;
 	int					bus;
 	int					z;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    int					flags;
+#else /* version >= v2.1.95 */
     unsigned long		flags;
+#endif /* version >= v2.1.95 */
 
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /* Disable interrupts, if they aren't already disabled. */
+    save_flags (flags);
+    cli ();
+#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 
 	DEB(printk ("\npci2000 recieved interrupt "));
 	for ( z = 0; z < NumAdapters;  z++ )										// scan for interrupt to process
@@ -327,12 +367,20 @@
 	OpDone (SCpnt, DID_OK << 16);
 
 irq_return:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /*
+     * Restore the original flags which will enable interrupts
+     * if and only if they were enabled on entry.
+     */
+    restore_flags (flags);
+#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:	Pci2000_QueueCommand
@@ -589,21 +637,37 @@
 	PADAPTER2000	    padapter;
 	int					z, zz;
 	int					setirq;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	struct pci_dev	   *pdev = NULL;
+#else
+	UCHAR	pci_bus, pci_device_fn;
+#endif
 
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	if ( !pci_present () )
+#else
+	if ( !pcibios_present () )
+#endif
 		{
 		printk ("pci2000: PCI BIOS not present\n");
 		return 0;
 		}
 
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL )
+#else
+	while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) )
+#endif
 		{
 		pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
 		padapter = HOSTDATA(pshost);
 
-		padapter->basePort = pdev->resource[1].start;
-
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+		padapter->basePort = pdev->base_address[1] & 0xFFFE;
+#else
+		pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
+		padapter->basePort &= 0xFFFE;
+#endif
 		DEB (printk ("\nBase Regs = %#04X", padapter->basePort));			// get the base I/O port address
 		padapter->mb0	= padapter->basePort + RTR_MAILBOX;		   			// get the 32 bit mail boxes
 		padapter->mb1	= padapter->basePort + RTR_MAILBOX + 4;
@@ -620,7 +684,11 @@
 		if ( WaitReady (padapter) )
 			goto unregister;
 
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 		pshost->irq = pdev->irq;
+#else
+		pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+#endif
 		setirq = 1;
 		padapter->irqOwned = 0;
 		for ( z = 0;  z < installed;  z++ )									// scan for shared interrupts
@@ -714,7 +782,11 @@
     PADAPTER2000	padapter = HOSTDATA (pshost);
 
 	if ( padapter->irqOwned )
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+	    free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
 		free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
     release_region (pshost->io_port, pshost->n_io_port);
     scsi_unregister(pshost);
     return 0;
@@ -760,4 +832,3 @@
 
 #include "scsi_module.c"
 #endif
-
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2000.h linux/drivers/scsi/pci2000.h
--- v2.3.46/linux/drivers/scsi/pci2000.h	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/pci2000.h	Sun Feb 20 20:49:46 2000
@@ -200,10 +200,13 @@
 	#define NULL 0
 #endif
 
+extern struct proc_dir_entry Proc_Scsi_Pci2000;
+
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
 #define PCI2000 {																\
 		next:						NULL,										\
 		module:						NULL,										\
-		proc_name:					"pci2000",							\
+		proc_dir:					&Proc_Scsi_Pci2000,							\
 		proc_info:					NULL,	/* let's not bloat the kernel */	\
 		name:						"PCI-2000 SCSI Intelligent Disk Controller",\
 		detect:						Pci2000_Detect,								\
@@ -229,4 +232,27 @@
 		use_clustering:				DISABLE_CLUSTERING,							\
 		use_new_eh_code:			0											\
 		}
+#else
+#define PCI2000 { NULL, NULL,							\
+			&Proc_Scsi_Pci2000,/* proc_dir_entry */		\
+			NULL,		                				\
+			"PCI-2000 SCSI Intelligent Disk Controller",\
+			Pci2000_Detect,								\
+			Pci2000_Release,							\
+			NULL,	 									\
+			Pci2000_Command,							\
+			Pci2000_QueueCommand,						\
+			Pci2000_Abort,								\
+			Pci2000_Reset,								\
+			NULL,										\
+			Pci2000_BiosParam,                 			\
+			16, 										\
+			-1, 										\
+			16,		 									\
+			1, 											\
+			0, 											\
+			0, 											\
+			DISABLE_CLUSTERING }
+#endif
+
 #endif
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.3.46/linux/drivers/scsi/pci2220i.c	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/pci2220i.c	Fri Feb 18 14:50:03 2000
@@ -24,8 +24,15 @@
  *	Revisions 1.11		Mar-26-1999
  *		- Fixed spinlock and PCI configuration.
  *
+ *	Revision 2.00		December-1-1999
+ *		- Added code for the PCI-2240I controller
+ *		- Added code for ATAPI devices.
+ *		- Double buffer for scatter/gather support
+ *
  ****************************************************************************/
 
+//#define DEBUG 1
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -46,18 +53,22 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "pci2220i.h"
+#include "psi_dale.h"
 
-#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
+#include <linux/bios32.h>
+#endif
 
-#define	PCI2220I_VERSION		"1.11"
-//#define	READ_CMD				IDE_COMMAND_READ
-//#define	WRITE_CMD				IDE_COMMAND_WRITE
-//#define	MAX_BUS_MASTER_BLOCKS	1		// This is the maximum we can bus master
+#define	PCI2220I_VERSION		"2.00"
 #define	READ_CMD				IDE_CMD_READ_MULTIPLE
 #define	WRITE_CMD				IDE_CMD_WRITE_MULTIPLE
 #define	MAX_BUS_MASTER_BLOCKS	SECTORSXFER		// This is the maximum we can bus master
 
-//#define DEBUG 1
+struct proc_dir_entry Proc_Scsi_Pci2220i =
+	{ PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
 
 #ifdef DEBUG
 #define DEB(x) x
@@ -72,10 +83,10 @@
 
 typedef struct
 	{
-	UCHAR		   	device;				// device code
 	UCHAR			byte6;				// device select register image
 	UCHAR			spigot;				// spigot number
-	UCHAR			sparebyte;			// placeholder
+	UCHAR			spigots[2];			// RAID spigots
+	UCHAR			deviceID[2];		// device ID codes
 	USHORT			sectors;			// number of sectors per track
 	USHORT			heads;				// number of heads
 	USHORT			cylinders;			// number of cylinders for this device
@@ -85,12 +96,17 @@
 	ULONG			lastsectorlba[2];	// last addressable sector on the drive
 	USHORT			raid;				// RAID active flag
 	USHORT			mirrorRecon;
-	UCHAR			hotRecon;
+	UCHAR			reconOn;
 	USHORT			reconCount;
+	USHORT			reconIsStarting;	// indicate hot reconstruct is starting
+	UCHAR			cmdDrqInt;			// flag for command interrupt
+	UCHAR			packet;				// command packet size in bytes
 	}	OUR_DEVICE, *POUR_DEVICE;	
 
 typedef struct
 	{
+	USHORT		 bigD;					// identity is a PCI-2240I if true, otherwise a PCI-2220I
+	USHORT		 atapi;					// this interface is for ATAPI devices only
 	USHORT		 regDmaDesc;			// address of the DMA discriptor register for direction of transfer
 	USHORT		 regDmaCmdStat;			// Byte #1 of DMA command status register
 	USHORT		 regDmaAddrPci;			// 32 bit register for PCI address of DMA
@@ -119,16 +135,21 @@
 	USHORT		 timingPIO;				// TRUE if PIO timing is active
 	ULONG		 timingAddress;			// address to use on adapter for current timing mode
 	ULONG		 irqOwned;				// owned IRQ or zero if shared
-	OUR_DEVICE	 device[DALE_MAXDRIVES];
-	DISK_MIRROR	*raidData[8];
+	UCHAR		 numberOfDrives;		// saved number of drives on this controller
+	UCHAR		 failRegister;			// current inverted data in fail register
+	OUR_DEVICE	 device[BIGD_MAXDRIVES];
+	DISK_MIRROR	*raidData[BIGD_MAXDRIVES];
 	ULONG		 startSector;
 	USHORT		 sectorCount;
+	ULONG		 readCount;
+	UCHAR		*currentSgBuffer;
+	ULONG		 currentSgCount;
+	USHORT		 nextSg;
 	UCHAR		 cmd;
 	Scsi_Cmnd	*SCpnt;
-	VOID		*buffer;
 	POUR_DEVICE	 pdev;					// current device opearating on
+	USHORT		 devInReconIndex;
 	USHORT		 expectingIRQ;
-	USHORT		 reconIsStarting;		// indicate hot reconstruct is starting
 	USHORT		 reconOn;				// Hot reconstruct is to be done.
 	USHORT		 reconPhase;			// Hot reconstruct operation is in progress.
 	ULONG		 reconSize;
@@ -138,6 +159,9 @@
 	struct timer_list	reconTimer;	
 	struct timer_list	timer;
 	UCHAR		*kBuffer;
+	UCHAR		 reqSense;
+	UCHAR		 atapiCdb[16];
+	UCHAR		 atapiSpecial;
 	}	ADAPTER2220I, *PADAPTER2220I;
 
 #define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)
@@ -152,12 +176,41 @@
 
 static struct	Scsi_Host 	   *PsiHost[MAXADAPTER] = {NULL,};  // One for each adapter
 static			int				NumAdapters = 0;
+static			int				Installed = 0;
 static			SETUP			DaleSetup;
-static			DISK_MIRROR		DiskMirror[2];
-static			ULONG			ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
+static			DISK_MIRROR		DiskMirror[BIGD_MAXDRIVES];
+static			ULONG			ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE5};
+static			ULONG			ModeArray2[] = {BIGD_DATA_MODE2, BIGD_DATA_MODE3, BIGD_DATA_MODE4, BIGD_DATA_MODE5};
 
 static void ReconTimerExpiry (unsigned long data);
 
+/*******************************************************************************************************
+ *	Name:			Alarm
+ *
+ *	Description:	Sound the for the given device
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					device	 - Device number.
+ *	
+ *	Returns:		Nothing.
+ *
+ ******************************************************************************************************/
+static void Alarm (PADAPTER2220I padapter, UCHAR device)
+	{
+	UCHAR	zc;
+
+	if ( padapter->bigD )
+		{
+		zc = device | (FAIL_ANY | FAIL_AUDIBLE);
+		if ( padapter->failRegister & FAIL_ANY ) 
+			zc |= FAIL_MULTIPLE;
+		
+		padapter->failRegister = zc;
+		outb_p (~zc, padapter->regFail);
+		}
+	else
+		outb_p (0x3C | (1 << device), padapter->regFail);			// sound alarm and set fail light		
+	}
 /****************************************************************
  *	Name:	MuteAlarm	:LOCAL
  *
@@ -172,8 +225,16 @@
 	{
 	UCHAR	old;
 
-	old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
-	outb_p (old | 0x40, padapter->regFail);
+	if ( padapter->bigD )
+		{
+		padapter->failRegister &= ~FAIL_AUDIBLE;
+		outb_p (~padapter->failRegister, padapter->regFail);
+		}
+	else
+		{
+		old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
+		outb_p (old | 0x40, padapter->regFail);
+		}
 	}
 /****************************************************************
  *	Name:	WaitReady	:LOCAL
@@ -214,17 +275,17 @@
 	ULONG	z;
 	UCHAR	status;
 
-	for ( z = 0;  z < (250 * 4);  z++ )				// wait up to 1/4 second
+	for ( z = 0;  z < (125 * 16);  z++ )				// wait up to 1/4 second
 		{
 		status = inb_p (padapter->regStatCmd);
 		if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
 			{
-			DEB (printk ("\nPCI2220I:  Reset took %ld mSec to be ready", z / 4));
+			DEB (printk ("\nPCI2220I:  Reset took %ld mSec to be ready", z / 8));
 			return 0;
 			}
-		udelay (250);
+		udelay (125);
 		}
-	DEB (printk ("\nPCI2220I:  Reset took more than 1 Second to come ready, Disk Failure"));
+	DEB (printk ("\nPCI2220I:  Reset took more than 2 Seconds to come ready, Disk Failure"));
 	return status;
 	}
 /****************************************************************
@@ -252,6 +313,52 @@
 	return status;
 	}
 /****************************************************************
+ *	Name:	AtapiWaitReady	:LOCAL
+ *
+ *	Description:	Wait for device busy and DRQ to be cleared.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					msec	 - Number of milliseconds to wait.
+ *
+ *	Returns:		TRUE if drive does not clear busy in time.
+ *
+ ****************************************************************/
+static int AtapiWaitReady (PADAPTER2220I padapter, int msec)
+	{
+	int z;
+
+	for ( z = 0;  z < (msec * 16);  z++ )
+		{
+		if ( !(inb_p (padapter->regStatCmd) & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) )
+			return FALSE;
+		udelay (125);
+		}
+	return TRUE;
+	}
+/****************************************************************
+ *	Name:	AtapiWaitDrq	:LOCAL
+ *
+ *	Description:	Wait for device ready for data transfer.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					msec	 - Number of milliseconds to wait.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int AtapiWaitDrq (PADAPTER2220I padapter, int msec)
+	{
+	ULONG	z;
+
+	for ( z = 0;  z < (msec * 16);  z++ )
+		{
+		if ( inb_p (padapter->regStatCmd) & IDE_STATUS_DRQ )
+			return 0;
+		udelay (128);
+		}
+	return TRUE;
+	}
+/****************************************************************
  *	Name:	HardReset	:LOCAL
  *
  *	Description:	Wait for device ready for data transfer.
@@ -265,24 +372,113 @@
  ****************************************************************/
 static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
 	{
-	SelectSpigot (padapter, spigot | 0x80);
+	DEB (printk ("\npci2220i:RESET  spigot = %X  devices = %d, %d", spigot, pdev->deviceID[0], pdev->deviceID[1]));
+	udelay (100000);										// just wait 100 mSec to let drives flush	
+	SelectSpigot (padapter, spigot | SEL_IRQ_OFF);
 	
 	outb_p (0x0E, padapter->regAltStat);					// reset the suvivor
 	udelay (100);											// wait a little	
 	outb_p (0x08, padapter->regAltStat);					// clear the reset
 	udelay (100);
-	outb_p (0xA0, padapter->regLba24);						//Specify drive
 
-	outb_p (pdev->byte6, padapter->regLba24);				// select the drive
+	outb_p (0xA0, padapter->regLba24);						// select the master drive
 	if ( WaitReadyReset (padapter) )
+		{
+		DEB (printk ("\npci2220i: master not ready after reset"));
 		return TRUE;
+		}
+	outb_p (0xB0, padapter->regLba24);						// try the slave drive
+	if ( (inb_p (padapter->regStatCmd) & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) 
+		{
+		DEB (printk ("\nPCI2220I: initializing slave drive on spigot %X", spigot));
+		outb_p (SECTORSXFER, padapter->regSectCount);
+		WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);	
+		if ( WaitReady (padapter) )
+			{
+			DEB (printk ("\npci2220i: slave not ready after set multiple"));
+			return TRUE;
+			}
+		}
+	
+	outb_p (0xA0, padapter->regLba24);				// select the drive
 	outb_p (SECTORSXFER, padapter->regSectCount);
 	WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);	
 	if ( WaitReady (padapter) )
+		{
+		DEB (printk ("\npci2220i: master not ready after set multiple"));
+		return TRUE;
+		}
+	return FALSE;
+	}
+/****************************************************************
+ *	Name:	AtapiReset	:LOCAL
+ *
+ *	Description:	Wait for device ready for data transfer.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *
+ *	Returns:		TRUE if drive does not come ready.
+ *
+ ****************************************************************/
+static int AtapiReset (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	SelectSpigot (padapter, pdev->spigot);
+	AtapiDevice (padapter, pdev->byte6);
+	AtapiCountLo (padapter, 0);
+	AtapiCountHi (padapter, 0);
+	WriteCommand (padapter, IDE_COMMAND_ATAPI_RESET);
+	udelay (125);
+	if ( AtapiWaitReady (padapter, 1000) )
+		return TRUE;
+	if ( inb_p (padapter->regStatCmd) || (inb_p (padapter->regLba8) != 0x14) || (inb_p (padapter->regLba16) != 0xEB) )
 		return TRUE;
 	return FALSE;
 	}
 /****************************************************************
+ *	Name:	WalkScatGath	:LOCAL
+ *
+ *	Description:	Transfer data to/from scatter/gather buffers.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					datain   - TRUE if data read.
+ *					length   - Number of bytes to transfer.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void WalkScatGath (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+	{
+	ULONG	 count;
+	UCHAR	*buffer = padapter->kBuffer;
+
+	while ( length )
+		{
+		count = ( length > padapter->currentSgCount ) ? padapter->currentSgCount : length; 
+		
+		if ( datain )
+			memcpy (padapter->currentSgBuffer, buffer, count);
+		else
+			memcpy (buffer, padapter->currentSgBuffer, count);
+
+		padapter->currentSgCount -= count;
+		if ( !padapter->currentSgCount )
+			{
+			if ( padapter->nextSg < padapter->SCpnt->use_sg )
+				{
+				padapter->currentSgBuffer = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].address;
+				padapter->currentSgCount = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].length;
+				padapter->nextSg++;
+				}
+			}
+		else
+			padapter->currentSgBuffer += count;
+
+		length -= count;
+		buffer += count;
+		}
+	}
+/****************************************************************
  *	Name:	BusMaster	:LOCAL
  *
  *	Description:	Do a bus master I/O.
@@ -291,34 +487,84 @@
  *					datain	 - TRUE if data read.
  *					irq		 - TRUE if bus master interrupt expected.
  *
- *	Returns:		TRUE if drive does not assert DRQ in time.
+ *	Returns:		Nothing.
  *
  ****************************************************************/
 static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq)
 	{
 	ULONG zl;
 	
-	outl (padapter->timingAddress, padapter->regDmaAddrLoc);
-	outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
-	zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
+	zl = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
 	padapter->sectorCount -= zl;
 	zl *= (ULONG)BYTES_PER_SECTOR;
-	padapter->buffer += zl;
-	outl (zl, padapter->regDmaCount);
+
 	if ( datain )
 		{
-		outb_p (8, padapter->regDmaDesc);						// read operation
-		if ( irq && !padapter->sectorCount )
-			outb_p (5, padapter->regDmaMode);					// interrupt on
+		padapter->readCount = zl;
+		outb_p (8, padapter->regDmaDesc);							// read operation
+		if ( padapter->bigD )
+			{
+			if ( irq && !padapter->sectorCount )
+				outb_p (0x0C, padapter->regDmaMode);				// interrupt on
+			else
+				outb_p (0x08, padapter->regDmaMode);				// no interrupt
+			}
+		else 
+			{
+			if ( irq && !padapter->sectorCount )
+				outb_p (0x05, padapter->regDmaMode);				// interrupt on
+			else
+				outb_p (0x01, padapter->regDmaMode);				// no interrupt
+			}
+		}
+	else
+		{
+		outb_p (0x00, padapter->regDmaDesc);						// write operation
+		if ( padapter->bigD )
+			outb_p (0x08, padapter->regDmaMode);					// no interrupt						
 		else
-			outb_p (1, padapter->regDmaMode);					// no interrupt
+			outb_p (0x01, padapter->regDmaMode);					// no interrupt
+		WalkScatGath (padapter, FALSE, zl);	
+		}
+	
+	outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+	outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+	outl (zl, padapter->regDmaCount);
+	outb_p (0x03, padapter->regDmaCmdStat);							// kick the DMA engine in gear
+	}
+/****************************************************************
+ *	Name:	AtapiBusMaster	:LOCAL
+ *
+ *	Description:	Do a bus master I/O.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					datain	 - TRUE if data read.
+ *					length	 - Number of bytes to transfer.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void AtapiBusMaster (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+	{
+	outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+	outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+	outl (length, padapter->regDmaCount);
+	if ( datain )
+		{
+		if ( padapter->readCount )
+				WalkScatGath (padapter, TRUE, padapter->readCount);
+		outb_p (0x08, padapter->regDmaDesc);						// read operation
+		outb_p (0x08, padapter->regDmaMode);						// no interrupt
+		padapter->readCount = length;
 		}
 	else
 		{
-		outb_p (0, padapter->regDmaDesc);						// write operation
-		outb_p (1, padapter->regDmaMode);						// no interrupt
+		outb_p (0x00, padapter->regDmaDesc);						// write operation
+		outb_p (0x08, padapter->regDmaMode);						// no interrupt						
+		if ( !padapter->atapiSpecial )
+			WalkScatGath (padapter, FALSE, length);	
 		}
-	outb_p (0x03, padapter->regDmaCmdStat);						// kick the DMA engine in gear
+	outb_p (0x03, padapter->regDmaCmdStat);							// kick the DMA engine in gear
 	}
 /****************************************************************
  *	Name:	WriteData	:LOCAL
@@ -339,9 +585,9 @@
 		if ( padapter->timingPIO )
 			{
 			zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
-			outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
+			WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+			outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
 			padapter->sectorCount -= zl;
-			padapter->buffer += zl * BYTES_PER_SECTOR;
 			}
 		else
 			BusMaster (padapter, 0, 0);
@@ -355,31 +601,32 @@
  *
  *	Description:	Write data to device.
  *
- *	Parameters:		padapter - Pointer adapter data structure.
+ *	Parameters:		padapter - Pointer to adapter structure.
+ *					pdev	 - Pointer to device structure
  *
- *	Returns:		TRUE if drive does not assert DRQ in time.
+ *	Returns:		Index + 1 of drive not failed or zero for OK.
  *
  ****************************************************************/
-static int WriteDataBoth (PADAPTER2220I padapter)
+static int WriteDataBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
 	{
 	ULONG	zl;
 	UCHAR	status0, status1;
 
-	SelectSpigot (padapter, 1);
+	SelectSpigot (padapter, pdev->spigots[0]);
 	status0 = WaitDrq (padapter);
 	if ( !status0 )
 		{
-		SelectSpigot (padapter, 2);
+		SelectSpigot (padapter, pdev->spigots[1]);
 		status1 = WaitDrq (padapter);
 		if ( !status1 )
 			{
-			SelectSpigot (padapter, 3);
+			SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
 			if ( padapter->timingPIO )
 				{
 				zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
-				outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
+				WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+				outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
 				padapter->sectorCount -= zl;
-				padapter->buffer += zl * BYTES_PER_SECTOR;
 				}
 			else
 				BusMaster (padapter, 0, 0);
@@ -388,8 +635,8 @@
 		}
 	padapter->cmd = 0;												// null out the command byte
 	if ( status0 )
-		return 1;
-	return 2;
+		return 2;
+	return 1;
 	}
 /****************************************************************
  *	Name:	IdeCmd	:LOCAL
@@ -406,7 +653,7 @@
 	{
 	UCHAR	status;
 
-	SelectSpigot (padapter, pdev->spigot);							// select the spigot
+	SelectSpigot (padapter, pdev->spigot | padapter->bigD);							// select the spigot
 	outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);			// select the drive
 	status = WaitReady (padapter);
 	if ( !status )
@@ -429,26 +676,27 @@
  *	Description:	Process an IDE command to both drivers.
  *
  *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device structure
  *
- *	Returns:		Zero if no error or spigot of error.
+ *	Returns:		Index + 1 of drive not failed or zero for OK.
  *
  ****************************************************************/
-static UCHAR IdeCmdBoth (PADAPTER2220I padapter)
+static UCHAR IdeCmdBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
 	{
 	UCHAR	status0;
 	UCHAR	status1;
 
-	SelectSpigot (padapter, 3);										// select the spigots
+	SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);								// select the spigots
 	outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive
-	SelectSpigot (padapter, 1);
+	SelectSpigot (padapter, pdev->spigots[0]);
 	status0 = WaitReady (padapter);
 	if ( !status0 )
 		{
-		SelectSpigot (padapter, 2);
+		SelectSpigot (padapter, pdev->spigots[1]);
 		status1 = WaitReady (padapter);
 		if ( !status1 )
 			{
-			SelectSpigot (padapter, 3);
+			SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
 			outb_p (padapter->sectorCount, padapter->regSectCount);
 			outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0);
 			outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8);
@@ -460,8 +708,8 @@
 		}
 	padapter->cmd = 0;									// null out the command byte
 	if ( status0 )
-		return 1;
-	return 2;
+		return 2;
+	return 1;
 	}
 /****************************************************************
  *	Name:	OpDone	:LOCAL
@@ -498,6 +746,7 @@
 		{
 		padapter->cmd = 0;
 		padapter->SCpnt = NULL;	
+		padapter->pdev = NULL;
 		SCpnt->result = result;
 		SCpnt->scsi_done (SCpnt);
 		if ( padapter->reconOn && !padapter->reconTimer.data )
@@ -524,8 +773,8 @@
 	{
 	PIDENTIFY_DATA	pid = (PIDENTIFY_DATA)padapter->kBuffer;
 
-	SelectSpigot (padapter, spigot | 0x80);						// select the spigot
-	outb_p (device << 4, padapter->regLba24);				// select the drive
+	SelectSpigot (padapter, spigot | SEL_IRQ_OFF);					// select the spigot
+	outb_p ((device << 4) | 0xA0, padapter->regLba24);				// select the drive
 	if ( WaitReady (padapter) )
 		return 0;
 	WriteCommand (padapter, IDE_COMMAND_IDENTIFY);	
@@ -535,6 +784,192 @@
 	return (pid->LBATotalSectors - 1);
 	}
 /****************************************************************
+ *	Name:	AtapiIdentify	:LOCAL
+ *
+ *	Description:	Do an intline inquiry on a drive.
+ *
+ *	Parameters:		padapter - Pointer to host data block.
+ *					pdev	 - Pointer to device table.
+ *
+ *	Returns:		TRUE on error.
+ *
+ ****************************************************************/
+static ULONG AtapiIdentify (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	ATAPI_GENERAL_0		ag0;
+	USHORT				zs;
+	int					z;
+
+	AtapiDevice (padapter, pdev->byte6);	
+	WriteCommand (padapter, IDE_COMMAND_ATAPI_IDENTIFY);	
+	if ( AtapiWaitDrq (padapter, 3000) )
+		return TRUE;
+
+	*(USHORT *)&ag0 = inw_p (padapter->regData);
+	for ( z = 0;  z < 255;  z++ )
+		zs = inw_p (padapter->regData);
+
+	if ( ag0.ProtocolType == 2 )
+		{
+		if ( ag0.CmdDrqType == 1 )
+			pdev->cmdDrqInt = TRUE;
+		switch ( ag0.CmdPacketSize )
+			{
+			case 0:
+				pdev->packet = 6;
+				break;
+			case 1:
+				pdev->packet = 8;
+				break;
+			default:
+				pdev->packet = 6;
+				break;
+			}
+		return FALSE;
+		}
+	return TRUE;
+	}
+/****************************************************************
+ *	Name:	Atapi2Scsi
+ *
+ *	Description:	Convert ATAPI data to SCSI data.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					SCpnt	 - Pointer to SCSI command structure.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+void Atapi2Scsi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+	{
+	UCHAR	*buff = padapter->currentSgBuffer;
+ 
+	switch ( SCpnt->cmnd[0] )
+		{
+		case SCSIOP_MODE_SENSE:
+			buff[0] = padapter->kBuffer[1];
+			buff[1] = padapter->kBuffer[2];
+			buff[2] = padapter->kBuffer[3];
+			buff[3] = padapter->kBuffer[7];
+			memcpy (&buff[4], &padapter->kBuffer[8], padapter->atapiCdb[8] - 8);
+			break;
+		case SCSIOP_INQUIRY:
+			padapter->kBuffer[2] = 2;
+			memcpy (buff, padapter->kBuffer, padapter->currentSgCount);
+			break;		
+		default:
+			if ( padapter->readCount )
+				WalkScatGath (padapter, TRUE, padapter->readCount);
+			break;
+		}
+	}
+/****************************************************************
+ *	Name:	Scsi2Atapi
+ *
+ *	Description:	Convert SCSI packet command to Atapi packet command.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					SCpnt	 - Pointer to SCSI command structure.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void Scsi2Atapi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+	{
+	UCHAR	*cdb = SCpnt->cmnd;
+	UCHAR	*buff = padapter->currentSgBuffer;
+
+	switch (cdb[0]) 
+		{
+		case SCSIOP_READ6:
+            padapter->atapiCdb[0] = SCSIOP_READ;
+			padapter->atapiCdb[1] = cdb[1] & 0xE0;
+            padapter->atapiCdb[3] = cdb[1] & 0x1F;
+			padapter->atapiCdb[4] = cdb[2];
+			padapter->atapiCdb[5] = cdb[3];
+			padapter->atapiCdb[8] = cdb[4];
+			padapter->atapiCdb[9] = cdb[5];
+			break;
+		case SCSIOP_WRITE6:
+            padapter->atapiCdb[0] = SCSIOP_WRITE;
+			padapter->atapiCdb[1] = cdb[1] & 0xE0;
+            padapter->atapiCdb[3] = cdb[1] & 0x1F;
+			padapter->atapiCdb[4] = cdb[2];
+			padapter->atapiCdb[5] = cdb[3];
+			padapter->atapiCdb[8] = cdb[4];
+			padapter->atapiCdb[9] = cdb[5];
+			break;
+        case SCSIOP_MODE_SENSE: 
+            padapter->atapiCdb[0] = SCSIOP_MODE_SENSE10;
+			padapter->atapiCdb[2] = cdb[2];
+			padapter->atapiCdb[8] = cdb[4] + 4;
+            break;
+
+        case SCSIOP_MODE_SELECT: 
+			padapter->atapiSpecial = TRUE;
+			padapter->atapiCdb[0] = SCSIOP_MODE_SELECT10;
+			padapter->atapiCdb[1] = cdb[1] | 0x10;
+			memcpy (padapter->kBuffer, buff, 4);
+			padapter->kBuffer[4] = padapter->kBuffer[5] = 0;
+			padapter->kBuffer[6] = padapter->kBuffer[7] = 0;
+			memcpy (&padapter->kBuffer[8], &buff[4], cdb[4] - 4);
+			padapter->atapiCdb[8] = cdb[4] + 4;
+			break;
+	    }
+	}
+/****************************************************************
+ *	Name:	AtapiSendCdb
+ *
+ *	Description:	Send the CDB packet to the device.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *					cdb		 - Pointer to 16 byte SCSI cdb.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void AtapiSendCdb (PADAPTER2220I padapter, POUR_DEVICE pdev, CHAR *cdb)
+	{
+	DEB (printk ("\nPCI2242I: CDB: %X %X %X %X %X %X %X %X %X %X %X %X", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]));
+	outsw (padapter->regData, cdb, pdev->packet);
+	}
+/****************************************************************
+ *	Name:	AtapiRequestSense
+ *
+ *	Description:	Send the CDB packet to the device.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *					SCpnt	 - Pointer to SCSI command structure.
+ *					pass	 - If true then this is the second pass to send cdb.
+ *
+ *	Returns:		TRUE on error.
+ *
+ ****************************************************************/
+static int AtapiRequestSense (PADAPTER2220I padapter, POUR_DEVICE pdev, Scsi_Cmnd *SCpnt, UCHAR pass)
+	{
+	UCHAR	cdb[16] = {SCSIOP_REQUEST_SENSE,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0};		
+	
+	DEB (printk ("\nPCI2242I: AUTO REQUEST SENSE"));
+	cdb[4] = (UCHAR)(sizeof (SCpnt->sense_buffer));
+	if ( !pass )
+		{
+		padapter->reqSense = TRUE;
+	 	AtapiCountLo (padapter, cdb[4]);						
+		AtapiCountHi (padapter, 0);						
+		outb_p (0, padapter->regError);						
+		WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+		if ( pdev->cmdDrqInt )
+			return FALSE;
+
+		if ( AtapiWaitDrq (padapter, 500) )
+			return TRUE;
+		}
+	AtapiSendCdb (padapter, pdev, cdb);	
+	return FALSE;
+	}
+/****************************************************************
  *	Name:	InlineReadSignature	:LOCAL
  *
  *	Description:	Do an inline read RAID sigature.
@@ -549,10 +984,9 @@
 static UCHAR InlineReadSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, int index)
 	{
 	UCHAR	status;
-	UCHAR	spigot = 1 << index;
 	ULONG	zl = pdev->lastsectorlba[index];
 
-	SelectSpigot (padapter, spigot | 0x80);				// select the spigot without interrupts
+	SelectSpigot (padapter, pdev->spigots[index] | SEL_IRQ_OFF);	// select the spigot without interrupts
 	outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24);		
 	status = WaitReady (padapter);
 	if ( !status )
@@ -591,6 +1025,10 @@
 	UCHAR			error;
 
 	padapter->expectingIRQ = 0;
+#ifdef DEBUG
+	printk (" @@@@@@  status: %X @@@@@@@ ", status);
+	STOP_HERE();	
+#endif
 	if ( status & IDE_STATUS_WRITE_FAULT )
 		{
 		return DID_PARITY << 16;
@@ -678,25 +1116,33 @@
  ******************************************************************************************************/
 static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev)
 	{
-	UCHAR			 spigot;
+	UCHAR	spigot;
 	
-	DEB (printk ("\npci2220i:  Initialize failover process - survivor = %d", padapter->survivor));
+	DEB (printk ("\npci2220i:  Initialize failover process - survivor = %d", pdev->deviceID[padapter->survivor]));
 	pdev->raid = FALSE;									//initializes system for non raid mode
-	pdev->hotRecon = 0;
-	padapter->reconOn = FALSE;
-	spigot = (padapter->survivor) ? 2 : 1;	
+	pdev->reconOn = FALSE;
+	spigot = pdev->spigots[padapter->survivor];	
 
 	if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD )
-		return (TRUE); 	
+		{
+		DEB (printk ("\n         failed, is survivor"));
+		return (TRUE); 
+		}
 
 	if ( HardReset (padapter, pdev, spigot) )
+		{
+		DEB (printk ("\n         failed, reset"));
 		return TRUE;
+		}
 
-	outb_p (0x3C | spigot, padapter->regFail);			// sound alarm and set fail light		
+	Alarm (padapter, pdev->deviceID[padapter->survivor ^ 1]);
 	pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR;	//clear present status
 	
 	if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) )
+		{
+		DEB (printk ("\n         failed, write signature"));
 		return TRUE;
+		}
 	padapter->failinprog = TRUE;
 	return FALSE;
 	}
@@ -716,13 +1162,23 @@
 	POUR_DEVICE		pdev = padapter->pdev;
 	UCHAR			status = IDE_STATUS_BUSY;
 	UCHAR			temp, temp1;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    int					flags;
+#else /* version >= v2.1.95 */
     unsigned long		flags;
+#endif /* version >= v2.1.95 */
 
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /* Disable interrupts, if they aren't already disabled. */
+    save_flags (flags);
+    cli ();
+#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 	DEB (printk ("\nPCI2220I: Timeout expired "));
 
 	if ( padapter->failinprog )
@@ -739,7 +1195,7 @@
 			{
 			case RECON_PHASE_MARKING:
 			case RECON_PHASE_LAST:
-				padapter->survivor = (pdev->spigot ^ 3) >> 1;
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
 				DEB (printk ("\npci2220i: FAILURE 1"));
 				if ( InitFailover (padapter, pdev) )
 					OpDone (padapter, DID_ERROR << 16);
@@ -750,7 +1206,7 @@
 				goto timerExpiryDone;
 
 			case RECON_PHASE_COPY:
-				padapter->survivor = (pdev->spigot) >> 1;
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
 				DEB (printk ("\npci2220i: FAILURE 2"));
 				DEB (printk ("\n       spig/stat = %X", inb_p (padapter->regStatSel));
 				if ( InitFailover (padapter, pdev) )
@@ -758,14 +1214,14 @@
 				goto timerExpiryDone;
 
 			case RECON_PHASE_UPDATE:
-				padapter->survivor = (pdev->spigot) >> 1;
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
 				DEB (printk ("\npci2220i: FAILURE 3")));
 				if ( InitFailover (padapter, pdev) )
 					OpDone (padapter, DID_ERROR << 16);
 				goto timerExpiryDone;
 
 			case RECON_PHASE_END:
-				padapter->survivor = (pdev->spigot) >> 1;
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
 				DEB (printk ("\npci2220i: FAILURE 4"));
 				if ( InitFailover (padapter, pdev) )
 					OpDone (padapter, DID_ERROR << 16);
@@ -784,17 +1240,21 @@
 			if ( padapter->cmd == WRITE_CMD )
 				{
 				DEB (printk ("in RAID write operation"));
-				if ( inb_p (padapter->regStatSel) & 1 )
+				temp = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_1 : SEL_3;
+				if ( inb_p (padapter->regStatSel) & temp )
 					{
-					SelectSpigot (padapter, 0x81 ); // Masking the interrupt during spigot select
+					DEB (printk ("\npci2220i: Determined A OK"));
+					SelectSpigot (padapter, temp | SEL_IRQ_OFF); // Masking the interrupt during spigot select
 					temp = inb_p (padapter->regStatCmd);
 					}
 				else
 					temp = IDE_STATUS_BUSY;
 
-				if ( inb (padapter->regStatSel) & 2 )
+				temp1 = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_2 : SEL_4;
+				if ( inb (padapter->regStatSel) & temp1 )
 					{
-					SelectSpigot (padapter, 0x82 ); // Masking the interrupt during spigot select
+					DEB (printk ("\npci2220i: Determined B OK"));
+					SelectSpigot (padapter, temp1 | SEL_IRQ_OFF); // Masking the interrupt during spigot select
 					temp1 = inb_p (padapter->regStatCmd);
 					}
 				else
@@ -802,6 +1262,7 @@
 			
 				if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) )
 					{
+					DEB (printk ("\npci2220i: Status A: %X   B: %X", temp & 0xFF, temp1 & 0xFF));
 	 				if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) ) 
 						{
 						status = temp;
@@ -809,11 +1270,10 @@
 						}		
 					else	
 						{
-						if (temp & IDE_STATUS_BUSY)
+						if ( temp & IDE_STATUS_BUSY )
 							padapter->survivor = 1;
 						else
 							padapter->survivor = 0;
-						DEB (printk ("\npci2220i: FAILURE 5"));
 						if ( InitFailover (padapter, pdev) )
 							{
 							status = inb_p (padapter->regStatCmd);
@@ -826,7 +1286,7 @@
 			else
 				{
 				DEB (printk ("in RAID read operation"));
-				padapter->survivor = (pdev->spigot ^ 3) >> 1;
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
 				DEB (printk ("\npci2220i: FAILURE 6"));
 				if ( InitFailover (padapter, pdev) )
 					{
@@ -847,12 +1307,20 @@
 	OpDone (padapter, DecodeError (padapter, status));
 
 timerExpiryDone:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /*
+     * Restore the original flags which will enable interrupts
+     * if and only if they were enabled on entry.
+     */
+    restore_flags (flags);
+#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:			SetReconstruct	:LOCAL
@@ -871,7 +1339,6 @@
 	pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD;
 	pdev->DiskMirror[index ^ 1].reconstructPoint = 0;						// start the reconstruct
 	pdev->reconCount = 1990;												// mark target drive early
-	pdev->hotRecon = 1 >> index;
 	return pdev->DiskMirror[index].reconstructPoint;
 	}
 /****************************************************************
@@ -893,35 +1360,66 @@
 	USHORT			minmode;
 	ULONG			zl;
 	UCHAR			zc;
+	USHORT			z;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    int				flags;
+#else /* version >= v2.1.95 */
     unsigned long	flags;
+#endif /* version >= v2.1.95 */
 
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /* Disable interrupts, if they aren't already disabled. */
+    save_flags (flags);
+    cli ();
+#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 
 	padapter = (PADAPTER2220I)data;
 	if ( padapter->SCpnt )
 		goto reconTimerExpiry;
 
-	pdev = padapter->device;
-	pid = (PIDENTIFY_DATA)padapter->kBuffer;
 	padapter->reconTimer.data = 0;
+	for ( z = padapter->devInReconIndex + 1;  z < BIGD_MAXDRIVES;  z++ )
+		{
+		if ( padapter->device[z].reconOn )
+			break;
+		}
+	if ( z < BIGD_MAXDRIVES )
+		pdev = &padapter->device[z];
+	else
+		{
+		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
+			{
+			if ( padapter->device[z].reconOn )
+				break;
+			}
+		if ( z < BIGD_MAXDRIVES )
+			pdev = &padapter->device[z];
+		else
+			{
+			padapter->reconOn = FALSE;
+			goto reconTimerExpiry;
+			}
+		}
+
+	padapter->devInReconIndex = z;
+	pid = (PIDENTIFY_DATA)padapter->kBuffer;
 	padapter->pdev = pdev;
-	if ( padapter->reconIsStarting )
+	if ( pdev->reconIsStarting )
 		{
-		padapter->reconIsStarting = FALSE;
-		padapter->reconOn = FALSE;
-		pdev->hotRecon = FALSE;
+		pdev->reconIsStarting = FALSE;
+		pdev->reconOn = FALSE;
 
-		if ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
+		while ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
 			 (pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) )
 			{
 			if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) )
-				{
-				goto reconTimerExpiry;
-				}
+				break;;
 
 			if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR )				// is first drive survivor?
 				testsize = SetReconstruct (pdev, 0);
@@ -932,33 +1430,38 @@
 			if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
 				{
 				if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
-					{
-					pdev->hotRecon = 1;
 					pdev->mirrorRecon = 0;
-					}
 				else
-					{
-					pdev->hotRecon = 2;
 					pdev->mirrorRecon = 1;
-					}
+				pdev->reconOn = TRUE;
 				}
+			break;
 			}
 
-		if ( !pdev->hotRecon )
+		if ( !pdev->reconOn )
 			goto reconTimerExpiry;
 
-		zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83;		// mute the alarm
-		outb_p (zc | pdev->hotRecon | 0x40, padapter->regFail);
+		if ( padapter->bigD )
+			{
+			padapter->failRegister = 0;
+			outb_p (~padapter->failRegister, padapter->regFail);
+			}
+		else
+			{
+			zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83;		// mute the alarm
+			outb_p (0xFF, padapter->regFail);
+			}
 
 		while ( 1 )
 			{
-			if ( HardReset (padapter, pdev, pdev->hotRecon) )
+			DEB (printk ("\npci2220i: hard reset issue"));
+			if ( HardReset (padapter, pdev, pdev->spigots[pdev->mirrorRecon]) )
 				{
 				DEB (printk ("\npci2220i: sub 1"));
 				break;
 				}
 
-			pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->hotRecon, 0);
+			pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->spigots[pdev->mirrorRecon], pdev->deviceID[pdev->mirrorRecon] & 1);
 
 			if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize )
 				{
@@ -1014,12 +1517,11 @@
 			break;
 			}
 
-		if ( !padapter->reconOn )
+		if ( !pdev->reconOn )
 			{		
-			pdev->hotRecon = FALSE;
 			padapter->survivor = pdev->mirrorRecon ^ 1;
 			padapter->reconPhase = RECON_PHASE_FAILOVER;
-				DEB (printk ("\npci2220i: FAILURE 7"));
+			DEB (printk ("\npci2220i: FAILURE 7"));
 			InitFailover (padapter, pdev);
 			goto reconTimerExpiry;
 			}
@@ -1038,11 +1540,11 @@
 	if ( pdev->reconCount++ > 2000 )
 		{
 		pdev->reconCount = 0;
-		if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
+		if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
 			{
 			padapter->survivor = pdev->mirrorRecon ^ 1;
 			padapter->reconPhase = RECON_PHASE_FAILOVER;
-				DEB (printk ("\npci2220i: FAILURE 8"));
+			DEB (printk ("\npci2220i: FAILURE 8"));
 			InitFailover (padapter, pdev);
 			goto reconTimerExpiry;
 			}
@@ -1057,30 +1559,30 @@
 
 	if ( padapter->reconSize )
 		{
-		SelectSpigot (padapter, 3);										// select the spigots
-		outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);// select the drive
+		SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);	// select the spigots
+		outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);	// select the drive
 		SelectSpigot (padapter, pdev->spigot);
 		if ( WaitReady (padapter) )
 			goto reconTimerExpiry;
 
-		SelectSpigot (padapter, pdev->hotRecon);
+		SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
 		if ( WaitReady (padapter) )
 			{
 			padapter->survivor = pdev->mirrorRecon ^ 1;
 			padapter->reconPhase = RECON_PHASE_FAILOVER;
-				DEB (printk ("\npci2220i: FAILURE 9"));
+			DEB (printk ("\npci2220i: FAILURE 9"));
 			InitFailover (padapter, pdev);
 			goto reconTimerExpiry;
 			}
 	
-		SelectSpigot (padapter, 3);
+		SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);
 		outb_p (padapter->reconSize & 0xFF, padapter->regSectCount);
 		outb_p (((UCHAR *)(&zl))[0], padapter->regLba0);
 		outb_p (((UCHAR *)(&zl))[1], padapter->regLba8);
 		outb_p (((UCHAR *)(&zl))[2], padapter->regLba16);
 		padapter->expectingIRQ = TRUE;
 		padapter->reconPhase = RECON_PHASE_READY;
-		SelectSpigot (padapter, pdev->hotRecon);
+		SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
 		WriteCommand (padapter, WRITE_CMD);
 		StartTimer (padapter);
 		SelectSpigot (padapter, pdev->spigot);
@@ -1095,12 +1597,20 @@
 	padapter->reconPhase = RECON_PHASE_LAST;
 
 reconTimerExpiry:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /*
+     * Restore the original flags which will enable interrupts
+     * if and only if they were enabled on entry.
+     */
+    restore_flags (flags);
+#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:	Irq_Handler	:LOCAL
@@ -1122,15 +1632,28 @@
 	Scsi_Cmnd		   *SCpnt;
 	UCHAR				status;
 	UCHAR				status1;
+	ATAPI_STATUS		statusa;
+	ATAPI_REASON		reasona;
+	ATAPI_ERROR			errora;
 	int					z;
 	ULONG				zl;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    int					flags;
+#else /* version >= v2.1.95 */
     unsigned long		flags;
+#endif /* version >= v2.1.95 */
 
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /* Disable interrupts, if they aren't already disabled. */
+    save_flags (flags);
+    cli ();
+#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 
 //	DEB (printk ("\npci2220i recieved interrupt\n"));
 
@@ -1155,7 +1678,70 @@
 	padapter = HOSTDATA(shost);
 	pdev = padapter->pdev;
 	SCpnt = padapter->SCpnt;
+	outb_p (0x08, padapter->regDmaCmdStat);									// cancel interrupt from DMA engine
 
+	if ( padapter->atapi && SCpnt )
+		{
+		*(char *)&statusa = inb_p (padapter->regStatCmd);						// read the device status
+		*(char *)&reasona = inb_p (padapter->regSectCount);						// read the device interrupt reason
+	
+		if ( !statusa.bsy )
+			{
+			if ( statusa.drq )													// test for transfer phase
+				{
+				if ( !reasona.cod )												// test for data phase
+					{
+					z = (ULONG)inb_p (padapter->regLba8) | (ULONG)(inb_p (padapter->regLba16) << 8);
+					if ( padapter->reqSense )
+						insw (padapter->regData, SCpnt->sense_buffer, z / 2);
+					else
+						AtapiBusMaster (padapter, reasona.io, z);
+					goto irq_return;
+					}
+				if ( reasona.cod && !reasona.io )								// test for command packet phase
+					{
+					if ( padapter->reqSense )
+						AtapiRequestSense (padapter, pdev, SCpnt, TRUE);
+					else
+						AtapiSendCdb (padapter, pdev, padapter->atapiCdb);
+					goto irq_return;
+					}
+				}
+			else
+				{
+				if ( reasona.io && statusa.drdy )								// test for status phase
+					{
+					Atapi2Scsi (padapter, SCpnt);
+					if ( statusa.check )
+						{
+						*(UCHAR *)&errora = inb_p (padapter->regError);			// read the device error
+						if ( errora.senseKey )
+							{
+							if ( padapter->reqSense || AtapiRequestSense (padapter, pdev, SCpnt, FALSE) )
+								OpDone (padapter, DID_ERROR << 16);
+							}
+						else
+							{
+							if ( errora.ili || errora.abort )
+								OpDone (padapter, DID_ERROR << 16);
+							else
+								OpDone (padapter, DID_OK << 16);	
+							}
+						}
+					else
+						if ( padapter->reqSense )
+							{
+							DEB (printk ("PCI2242I: Sense codes - %X %X %X ", ((UCHAR *)SCpnt->sense_buffer)[0], ((UCHAR *)SCpnt->sense_buffer)[12], ((UCHAR *)SCpnt->sense_buffer)[13]));
+							OpDone (padapter, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2);
+							}
+						else
+							OpDone (padapter, DID_OK << 16);	
+					}
+				}
+			}		
+		goto irq_return;
+		}
+	
 	if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) )
 		{
 		DEB(printk ("\npci2220i Unsolicited interrupt\n"));
@@ -1163,7 +1749,6 @@
 		goto irq_return;
 		}
 	padapter->expectingIRQ = 0;
-	outb_p (0x08, padapter->regDmaCmdStat);									// cancel interrupt from DMA engine
 
 	if ( padapter->failinprog )
 		{
@@ -1178,7 +1763,7 @@
 		else
 			{
 			DEB (printk ("\npci2220i: restarting failed opertation."));
-			pdev->spigot = (padapter->survivor) ? 2 : 1;
+			pdev->spigot = (padapter->survivor) ? pdev->spigots[1] : pdev->spigots[0];
 			del_timer (&padapter->timer);
 			if ( padapter->reconPhase )
 				OpDone (padapter, DID_OK << 16);
@@ -1200,15 +1785,15 @@
 					{
 					if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
 						{
-						padapter->survivor = (pdev->spigot ^ 3) >> 1;
+						padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
 						DEB (printk ("\npci2220i: FAILURE 10"));
 						if ( InitFailover (padapter, pdev) )
 							OpDone (padapter, DecodeError (padapter, status));
 						goto irq_return;
 						}
-					if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
+					if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
 						{
-						padapter->survivor = (pdev->spigot) >> 1;
+						padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
 						DEB (printk ("\npci2220i: FAILURE 11"));
 						if ( InitFailover (padapter, pdev) )
 							OpDone (padapter, DecodeError (padapter, status));
@@ -1228,17 +1813,17 @@
 					OpDone (padapter, DecodeError (padapter, status));
 					goto irq_return;
 					}
-				SelectSpigot (padapter, pdev->hotRecon);
+				SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
 				if ( WaitDrq (padapter) )
 					{
 					del_timer (&padapter->timer);
-					padapter->survivor = (pdev->spigot) >> 1;
-				DEB (printk ("\npci2220i: FAILURE 12"));
+					padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+					DEB (printk ("\npci2220i: FAILURE 12"));
 					if ( InitFailover (padapter, pdev) )
 						OpDone (padapter, DecodeError (padapter, status));
 					goto irq_return;
 					}
-				SelectSpigot (padapter, pdev->spigot | 0x40);
+				SelectSpigot (padapter, pdev->spigot | SEL_COPY | padapter->bigD);
 				padapter->reconPhase = RECON_PHASE_COPY;
 				padapter->expectingIRQ = TRUE;
 				if ( padapter->timingPIO )
@@ -1247,11 +1832,22 @@
 					}
 				else
 					{
-					outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+					if ( (padapter->timingMode > 3) )
+						{
+						if ( padapter->bigD )
+							outl (BIGD_DATA_MODE3, padapter->regDmaAddrLoc);
+						else
+							outl (DALE_DATA_MODE3, padapter->regDmaAddrLoc);
+						}
+					else
+						outl (padapter->timingAddress, padapter->regDmaAddrLoc);
 					outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
 					outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount);
 					outb_p (8, padapter->regDmaDesc);						// read operation
-					outb_p (1, padapter->regDmaMode);						// no interrupt
+					if ( padapter->bigD )
+						outb_p (8, padapter->regDmaMode);					// no interrupt
+					else
+						outb_p (1, padapter->regDmaMode);					// no interrupt
 					outb_p (0x03, padapter->regDmaCmdStat);					// kick the DMA engine in gear
 					}
 				goto irq_return;
@@ -1260,13 +1856,14 @@
 				pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize;
 
 			case RECON_PHASE_UPDATE:
-				SelectSpigot (padapter, pdev->hotRecon | 0x80);
+				SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon] | SEL_IRQ_OFF);
 				status = inb_p (padapter->regStatCmd);						// read the device status
 				del_timer (&padapter->timer);
 				if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
 					{
-					padapter->survivor = (pdev->spigot) >> 1;
+					padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
 					DEB (printk ("\npci2220i: FAILURE 13"));
+					DEB (printk ("\n  status register = %X   error = %X", status, inb_p (padapter->regError)));
 					if ( InitFailover (padapter, pdev) )
 						OpDone (padapter, DecodeError (padapter, status));
 					goto irq_return;
@@ -1279,14 +1876,29 @@
 				del_timer (&padapter->timer);
 				if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
 					{
-					padapter->survivor = (pdev->spigot) >> 1;
-				DEB (printk ("\npci2220i: FAILURE 14"));
+					padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+					DEB (printk ("\npci2220i: FAILURE 14"));
 					if ( InitFailover (padapter, pdev) )
 						OpDone (padapter, DecodeError (padapter, status));
 					goto irq_return;
 					}
-				padapter->reconOn = FALSE;
-				pdev->hotRecon = 0;
+				pdev->reconOn = 0;
+				if ( padapter->bigD )
+					{
+					for ( z = 0;  z < padapter->numberOfDrives;  z++ )
+						{
+						if ( padapter->device[z].DiskMirror[0].status & UCBF_SURVIVOR )
+							{
+							Alarm (padapter, padapter->device[z].deviceID[0] ^ 2);
+							MuteAlarm (padapter);
+							}
+						if ( padapter->device[z].DiskMirror[1].status & UCBF_SURVIVOR )
+							{
+							Alarm (padapter, padapter->device[z].deviceID[1] ^ 2);
+							MuteAlarm (padapter);
+							}
+						}
+					}
 				OpDone (padapter, DID_OK << 16);
 				goto irq_return;
 
@@ -1305,9 +1917,9 @@
 					{
 					if ( pdev->raid )
 						{
-						padapter->survivor = (pdev->spigot ^ 3) >> 1;
+						padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
 						del_timer (&padapter->timer);
-				DEB (printk ("\npci2220i: FAILURE 15"));
+						DEB (printk ("\npci2220i: FAILURE 15"));
 						if ( !InitFailover (padapter, pdev) )
 							goto irq_return;
 						}
@@ -1315,10 +1927,9 @@
 					}
 				if ( padapter->timingPIO )
 					{
-					zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
-					insw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
-					padapter->sectorCount -= zl;
-					padapter->buffer += zl * BYTES_PER_SECTOR;
+					insw (padapter->regData, padapter->kBuffer, padapter->readCount / 2);
+					padapter->sectorCount -= padapter->readCount / BYTES_PER_SECTOR;
+					WalkScatGath (padapter, TRUE, padapter->readCount);
 					if ( !padapter->sectorCount )
 						{
 						status = 0;
@@ -1326,32 +1937,40 @@
 						}
 					}
 				else
+					{
+					if ( padapter->readCount )
+						WalkScatGath (padapter, TRUE, padapter->readCount);
 					BusMaster (padapter, 1, 1);
+					}
 				padapter->expectingIRQ = TRUE;
 				goto irq_return;
 				}
+			if ( padapter->readCount && !padapter->timingPIO )
+				WalkScatGath (padapter, TRUE, padapter->readCount);
 			status = 0;
 			break;
 
 		case WRITE_CMD:
-			SelectSpigot (padapter, pdev->spigot | 0x80);				
-			status = inb_p (padapter->regStatCmd);								// read the device status
 			if ( pdev->raid )
 				{
-				SelectSpigot (padapter, (pdev->spigot ^ 3) | 0x80);				
-				status1 = inb_p (padapter->regStatCmd);							// read the device status
+				SelectSpigot (padapter, pdev->spigots[0] | SEL_IRQ_OFF);				
+				status = inb_p (padapter->regStatCmd);								// read the device status
+				SelectSpigot (padapter, pdev->spigots[1] | SEL_IRQ_OFF);				
+				status1 = inb_p (padapter->regStatCmd);								// read the device status
 				}
 			else
+				SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);				
+				status = inb_p (padapter->regStatCmd);								// read the device status
 				status1 = 0;
 		
 			if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
 				{	
 				if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) )
 					{
-					padapter->survivor = (pdev->spigot ^ 3) >> 1;
+					padapter->survivor = 1;
 					del_timer (&padapter->timer);
-				SelectSpigot (padapter, pdev->spigot | 0x80);
-				DEB (printk ("\npci2220i: FAILURE 16  status = %X  error = %X", status, inb_p (padapter->regError)));
+					SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);
+					DEB (printk ("\npci2220i: FAILURE 16  status = %X  error = %X", status, inb_p (padapter->regError)));
 					if ( !InitFailover (padapter, pdev) )
 						goto irq_return;
 					}
@@ -1361,9 +1980,9 @@
 				{
 				if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
 					{	
-					padapter->survivor = pdev->spigot >> 1;
+					padapter->survivor = 0;
 					del_timer (&padapter->timer);
-				DEB (printk ("\npci2220i: FAILURE 17  status = %X  error = %X", status1, inb_p (padapter->regError)));
+					DEB (printk ("\npci2220i: FAILURE 17  status = %X  error = %X", status1, inb_p (padapter->regError)));
 					if ( !InitFailover (padapter, pdev) )
 						goto irq_return;
 					status = status1;
@@ -1371,15 +1990,15 @@
 					}
 				if ( padapter->sectorCount )
 					{
-					status = WriteDataBoth (padapter);
+					status = WriteDataBoth (padapter, pdev);
 					if ( status )
 						{
-						padapter->survivor = (status ^ 3) >> 1;
+						padapter->survivor = status >> 1;
 						del_timer (&padapter->timer);
-				DEB (printk ("\npci2220i: FAILURE 18"));
+						DEB (printk ("\npci2220i: FAILURE 18"));
 						if ( !InitFailover (padapter, pdev) )
 							goto irq_return;
-						SelectSpigot (padapter, status | 0x80);				
+						SelectSpigot (padapter, pdev->spigots[status] | SEL_IRQ_OFF);				
 						status = inb_p (padapter->regStatCmd);								// read the device status
 						break;
 						}
@@ -1391,7 +2010,7 @@
 				}
 			if ( padapter->sectorCount )	
 				{	
-				SelectSpigot (padapter, pdev->spigot);
+				SelectSpigot (padapter, pdev->spigot | padapter->bigD);
 				status = WriteData (padapter);
 				if ( status )
 					break;
@@ -1458,12 +2077,20 @@
 
 	OpDone (padapter, zl);
 irq_return:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+    /*
+     * Restore the original flags which will enable interrupts
+     * if and only if they were enabled on entry.
+     */
+    restore_flags (flags);
+#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:	Pci2220i_QueueCommand
@@ -1486,14 +2113,88 @@
 	PDEVICE_RAID1	pdr;
 
 	SCpnt->scsi_done = done;
-	padapter->buffer = SCpnt->request_buffer;
 	padapter->SCpnt = SCpnt;  									// Save this command data
+	padapter->readCount = 0;
+
+	if ( SCpnt->use_sg )
+		{
+		padapter->currentSgBuffer = ((struct scatterlist *)SCpnt->request_buffer)[0].address;
+		padapter->currentSgCount = ((struct scatterlist *)SCpnt->request_buffer)[0].length;
+		}
+	else
+		{
+		padapter->currentSgBuffer = SCpnt->request_buffer;
+		padapter->currentSgCount = SCpnt->request_bufflen;
+		}
+	padapter->nextSg = 1;
+
 	if ( !done )
 		{
 		printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);
 		return 0;
 		}
 	
+	if ( padapter->atapi )
+		{
+		UCHAR			zlo, zhi;
+
+		DEB (printk ("\nPCI2242I: ID %d, LUN %d opcode %X ", SCpnt->target, SCpnt->lun, *cdb));
+		padapter->pdev = pdev;
+		if ( !pdev->byte6 || SCpnt->lun )
+			{
+			OpDone (padapter, DID_BAD_TARGET << 16);
+			return 0;
+			}
+	
+		padapter->atapiSpecial = FALSE;
+		padapter->reqSense = FALSE;
+		memset (padapter->atapiCdb, 0, 16);
+		SelectSpigot (padapter, pdev->spigot);									// select the spigot
+		AtapiDevice (padapter, pdev->byte6);									// select the drive
+		if ( AtapiWaitReady (padapter, 100) )
+			{
+			OpDone (padapter, DID_NO_CONNECT << 16);
+			return 0;
+			}
+
+		switch ( cdb[0] ) 
+			{
+			case SCSIOP_MODE_SENSE:
+			case SCSIOP_MODE_SELECT:
+				Scsi2Atapi (padapter, SCpnt);
+				z = SCpnt->request_bufflen + 4;
+				break;
+			case SCSIOP_READ6:
+			case SCSIOP_WRITE6:
+				Scsi2Atapi (padapter, SCpnt);
+				z = SCpnt->request_bufflen;
+				break;
+			default:
+				memcpy (padapter->atapiCdb, cdb, SCpnt->cmd_len);
+				z = SCpnt->request_bufflen;
+				break;
+			}
+		if ( z > ATAPI_TRANSFER )
+			z = ATAPI_TRANSFER;
+	    zlo = (UCHAR)(z & 0xFF);
+	    zhi = (UCHAR)(z >> 8);
+
+	 	AtapiCountLo (padapter, zlo);						
+	   	AtapiCountHi (padapter, zhi);						
+	   	outb_p (0, padapter->regError);						
+		WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+		if ( pdev->cmdDrqInt )
+			return 0;
+
+		if ( AtapiWaitDrq (padapter, 500) )
+			{
+			OpDone (padapter, DID_ERROR << 16);
+			return 0;
+			}
+		AtapiSendCdb (padapter, pdev, padapter->atapiCdb);	
+		return 0;
+		}
+	
 	if ( padapter->reconPhase )
 		return 0;
 	if ( padapter->reconTimer.data )
@@ -1502,12 +2203,11 @@
 		padapter->reconTimer.data = 0;
 		}
 		
-	if ( !pdev->device || SCpnt->lun )
+	if ( (SCpnt->target >= padapter->numberOfDrives) || SCpnt->lun )
 		{
 		OpDone (padapter, DID_BAD_TARGET << 16);
 		return 0;
 		}
-
 	
 	switch ( *cdb )
 		{
@@ -1518,7 +2218,15 @@
 				switch ( cdb[3] ) 
 					{
 					case MY_SCSI_REBUILD:
-						padapter->reconOn = padapter->reconIsStarting = TRUE;
+						for ( z = 0;  z < padapter->numberOfDrives;  z++ )
+							{
+							pdev = &padapter->device[z];
+							if ( ((pdev->DiskMirror[0].status & UCBF_SURVIVOR) && (pdev->DiskMirror[1].status & UCBF_MIRRORED)) ||
+								 ((pdev->DiskMirror[1].status & UCBF_SURVIVOR) && (pdev->DiskMirror[0].status & UCBF_MIRRORED)) )
+								{
+								padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+								}
+							}
 						OpDone (padapter, DID_OK << 16);
 						break;
 					case MY_SCSI_ALARMMUTE:
@@ -1535,7 +2243,10 @@
 						if ( padapter->raidData[z] )
 							{
 							memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR));
-							pdr->TotalSectors = padapter->device[0].blocks;
+							if ( padapter->raidData[z]->reconstructPoint > padapter->raidData[z ^ 2]->reconstructPoint )
+								pdr->TotalSectors = padapter->raidData[z]->reconstructPoint;
+							else
+								pdr->TotalSectors = padapter->raidData[z ^ 2]->reconstructPoint;
 							}
 						else
 							memset (pdr, 0, sizeof (DEVICE_RAID1));
@@ -1598,6 +2309,7 @@
 
 	while ( padapter->demoFail )
 		{
+		pdev = padapter->pdev = &padapter->device[0];
 		padapter->demoFail = FALSE;
 		if ( !pdev->raid || 
 			 (pdev->DiskMirror[0].status & UCBF_SURVIVOR) || 
@@ -1610,7 +2322,7 @@
 		else
 			padapter->survivor = 0;
 				DEB (printk ("\npci2220i: FAILURE 19"));
-		if ( InitFailover (padapter, pdev ) )
+		if ( InitFailover (padapter, pdev) )
 			break;
 		return 0;
 		}
@@ -1618,14 +2330,14 @@
 	StartTimer (padapter);
 	if ( pdev->raid && (padapter->cmd == WRITE_CMD) )
 		{
-		rc = IdeCmdBoth (padapter);
+		rc = IdeCmdBoth (padapter, pdev);
 		if ( !rc )
-			rc = WriteDataBoth (padapter);
+			rc = WriteDataBoth (padapter, pdev);
 		if ( rc )
 			{
 			del_timer (&padapter->timer);
 			padapter->expectingIRQ = 0;
-			padapter->survivor = (rc ^ 3) >> 1;
+			padapter->survivor = rc >> 1;
 				DEB (printk ("\npci2220i: FAILURE 20"));
 			if ( InitFailover (padapter, pdev) )
 				{
@@ -1656,7 +2368,6 @@
 		}
 	return 0;
 	}
-
 static void internal_done(Scsi_Cmnd *SCpnt)
 	{
 	SCpnt->SCp.Status++;
@@ -1692,25 +2403,192 @@
  *	Returns:		Nothing.
  *
  ****************************************************************/
-VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
+static VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
 	{
 	ULONG	 oldremap;
 	UCHAR	 olddesc;
 	ULONG	 z;
 	UCHAR	*pd = (UCHAR *)pdata;
 
-	oldremap = inl (padapter->regRemap);									// save values to restore later
+	oldremap = inl (padapter->regRemap);							// save values to restore later
 	olddesc  = inb_p (padapter->regDesc);
 
-	outl (base | 1, padapter->regRemap);									// remap to Flash space as specified
-	outb_p (0x40, padapter->regDesc);										// describe remap region as 8 bit
-	for ( z = 0;  z < length;  z++)											// get "length" data count
-		*pd++ = inb_p (padapter->regBase + z);								// read in the data
+	outl (base | 1, padapter->regRemap);							// remap to Flash space as specified
+	outb_p (0x40, padapter->regDesc);								// describe remap region as 8 bit
+	for ( z = 0;  z < length;  z++)									// get "length" data count
+		*pd++ = inb_p (padapter->regBase + z);						// read in the data
 
-	outl (oldremap, padapter->regRemap);									// restore remap register values
+	outl (oldremap, padapter->regRemap);							// restore remap register values
 	outb_p (olddesc, padapter->regDesc);
 	}
 /****************************************************************
+ *	Name:			GetRegs
+ *
+ *	Description:	Initialize the regester information.
+ *
+ *	Parameters:		pshost		  - Pointer to SCSI host data structure.
+ *					bigd		  - PCI-2240I identifier
+ *					pcidev		  - Pointer to device data structure.
+ *					pci_bus		  - PCI bus number.
+ *					pci_device_fn - PCI device and function number.
+ *
+ *	Returns:		TRUE if failure to install.
+ *
+ ****************************************************************/
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcidev)
+#else
+static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, UCHAR pci_bus, UCHAR pci_device_fn)
+#endif
+	{
+	PADAPTER2220I	padapter;
+	int				setirq;
+	int				z;
+	USHORT			zr, zl;
+
+	padapter = HOSTDATA(pshost);
+	memset (padapter, 0, sizeof (ADAPTER2220I));
+	memset (&DaleSetup, 0, sizeof (DaleSetup));
+	memset (DiskMirror, 0, sizeof (DiskMirror));
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+	zr = pcidev->base_address[1] & 0xFFFE;
+	zl = pcidev->base_address[2] & 0xFFFE;
+#else
+	pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zr);
+	zr &= 0xFFFE;
+	pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zl);
+	zl &= 0xFFFE;
+#endif
+	padapter->basePort = zr;
+	padapter->regRemap		= zr + RTR_LOCAL_REMAP;					// 32 bit local space remap
+	padapter->regDesc		= zr + RTR_REGIONS;	  					// 32 bit local region descriptor
+	padapter->regRange		= zr + RTR_LOCAL_RANGE;					// 32 bit local range
+	padapter->regIrqControl	= zr + RTR_INT_CONTROL_STATUS;			// 16 bit interupt control and status
+	padapter->regScratchPad	= zr + RTR_MAILBOX;	  					// 16 byte scratchpad I/O base address
+
+	padapter->regBase		= zl;
+	padapter->regData		= zl + REG_DATA;						// data register I/O address
+	padapter->regError		= zl + REG_ERROR;						// error register I/O address
+	padapter->regSectCount	= zl + REG_SECTOR_COUNT;				// sector count register I/O address
+	padapter->regLba0		= zl + REG_LBA_0;						// least significant byte of LBA
+	padapter->regLba8		= zl + REG_LBA_8;						// next least significant byte of LBA
+	padapter->regLba16		= zl + REG_LBA_16;						// next most significan byte of LBA
+	padapter->regLba24		= zl + REG_LBA_24;						// head and most 4 significant bits of LBA
+	padapter->regStatCmd	= zl + REG_STAT_CMD;					// status on read and command on write register
+	padapter->regStatSel	= zl + REG_STAT_SEL;					// board status on read and spigot select on write register
+	padapter->regFail		= zl + REG_FAIL;
+	padapter->regAltStat	= zl + REG_ALT_STAT;
+
+	if ( bigd )
+		{
+		padapter->regDmaDesc	= zr + RTR_DMA0_DESC_PTR;			// address of the DMA discriptor register for direction of transfer
+		padapter->regDmaCmdStat	= zr + RTR_DMA_COMMAND_STATUS;		// Byte #0 of DMA command status register
+		padapter->regDmaAddrPci	= zr + RTR_DMA0_PCI_ADDR;			// 32 bit register for PCI address of DMA
+		padapter->regDmaAddrLoc	= zr + RTR_DMA0_LOCAL_ADDR;			// 32 bit register for local bus address of DMA
+		padapter->regDmaCount	= zr + RTR_DMA0_COUNT;				// 32 bit register for DMA transfer count
+		padapter->regDmaMode	= zr + RTR_DMA0_MODE + 1;			// 32 bit register for DMA mode control
+		padapter->bigD			= SEL_NEW_SPEED_1;					// set spigot speed control bit
+		}
+	else
+		{
+		padapter->regDmaDesc	= zl + RTL_DMA1_DESC_PTR;			// address of the DMA discriptor register for direction of transfer
+		padapter->regDmaCmdStat	= zl + RTL_DMA_COMMAND_STATUS + 1;	// Byte #1 of DMA command status register
+		padapter->regDmaAddrPci	= zl + RTL_DMA1_PCI_ADDR;			// 32 bit register for PCI address of DMA
+		padapter->regDmaAddrLoc	= zl + RTL_DMA1_LOCAL_ADDR;			// 32 bit register for local bus address of DMA
+		padapter->regDmaCount	= zl + RTL_DMA1_COUNT;				// 32 bit register for DMA transfer count
+		padapter->regDmaMode	= zl + RTL_DMA1_MODE + 1;			// 32 bit register for DMA mode control
+		}
+
+	padapter->numberOfDrives = inb_p (padapter->regScratchPad + BIGD_NUM_DRIVES);
+	if ( !bigd && !padapter->numberOfDrives )						// if no devices on this board
+		return TRUE;
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+	pshost->irq = pcidev->irq;
+#else
+	pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+#endif
+	setirq = 1;
+	for ( z = 0;  z < Installed;  z++ )								// scan for shared interrupts
+		{
+		if ( PsiHost[z]->irq == pshost->irq )						// if shared then, don't posses
+			setirq = 0;
+		}
+	if ( setirq )													// if not shared, posses
+		{
+		if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 )
+			{
+			if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 )
+				{
+				printk ("Unable to allocate IRQ for PCI-2220I controller.\n");
+				return TRUE;
+				}
+			}
+		padapter->irqOwned = pshost->irq;							// set IRQ as owned
+		}
+	if ( padapter->numberOfDrives )
+		padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC);
+	else
+		padapter->kBuffer = kmalloc (ATAPI_TRANSFER, GFP_DMA | GFP_ATOMIC);
+	if ( !padapter->kBuffer )
+		{
+		printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+		free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
+		free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
+		return TRUE;
+		}
+
+	PsiHost[Installed]	= pshost;									// save SCSI_HOST pointer
+
+	pshost->io_port		= padapter->basePort;
+	pshost->n_io_port	= 0xFF;
+	pshost->unique_id	= padapter->regBase;
+
+	outb_p (0x01, padapter->regRange);								// fix our range register because other drivers want to tromp on it
+
+	padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
+	if ( padapter->timingMode >= 2 )
+		{
+		if ( bigd )
+			padapter->timingAddress	= ModeArray2[padapter->timingMode - 2];
+		else
+			padapter->timingAddress	= ModeArray[padapter->timingMode - 2];
+		}
+	else
+		padapter->timingPIO = TRUE;
+
+	ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
+	ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
+
+	return FALSE;
+	}
+/****************************************************************
+ *	Name:			SetupFinish
+ *
+ *	Description:	Complete the driver initialization process for a card
+ *
+ *	Parameters:		padapter  - Pointer to SCSI host data structure.
+ *					str		  - Pointer to board type string.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+VOID SetupFinish (PADAPTER2220I padapter, char *str, int irq)
+	{
+	init_timer (&padapter->timer);
+	padapter->timer.function = TimerExpiry;
+	padapter->timer.data = (unsigned long)padapter;
+	init_timer (&padapter->reconTimer);
+	padapter->reconTimer.function = ReconTimerExpiry;
+	padapter->reconTimer.data = (unsigned long)padapter;
+	printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %X/%X  IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq);
+	printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
+	}	
+/****************************************************************
  *	Name:	Pci2220i_Detect
  *
  *	Description:	Detect and initialize our boards.
@@ -1722,204 +2600,284 @@
  ****************************************************************/
 int Pci2220i_Detect (Scsi_Host_Template *tpnt)
 	{
-	int					found = 0;
-	int					installed = 0;
 	struct Scsi_Host   *pshost;
 	PADAPTER2220I	    padapter;
+	POUR_DEVICE			pdev;
 	int					unit;
 	int					z;
-	USHORT				zs;
-	USHORT				raidon = FALSE;
-	int					setirq;
-	UCHAR				spigot1 = FALSE;
-	UCHAR				spigot2 = FALSE;
-	struct pci_dev	   *pdev = NULL;
+	USHORT				raidon;
+	UCHAR				spigot1, spigot2;
+	UCHAR				device;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+	struct pci_dev	   *pcidev = NULL;
+#else
+	int					found;
+	UCHAR				pci_bus, pci_device_fn;
+#endif
 
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	if ( !pci_present () )
+#else
+	if ( !pcibios_present () )
+#endif
 		{
 		printk ("pci2220i: PCI BIOS not present\n");
 		return 0;
 		}
 
-	while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pdev)) != NULL )
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+	while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL )
+#else
+	found = 0;
+	while ( !pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, found++, &pci_bus, &pci_device_fn) )
+#endif
 		{
 		pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
 		padapter = HOSTDATA(pshost);
-		memset (padapter, 0, sizeof (ADAPTER2220I));
 
-		zs = pdev->resource[1].start;
-		padapter->basePort = zs;
-		padapter->regRemap		= zs + RTR_LOCAL_REMAP;				// 32 bit local space remap
-		padapter->regDesc		= zs + RTR_REGIONS;	  				// 32 bit local region descriptor
-		padapter->regRange		= zs + RTR_LOCAL_RANGE;				// 32 bit local range
-		padapter->regIrqControl	= zs + RTR_INT_CONTROL_STATUS;		// 16 bit interupt control and status
-		padapter->regScratchPad	= zs + RTR_MAILBOX;	  				// 16 byte scratchpad I/O base address
-
-		zs = pdev->resource[2].start;
-		padapter->regBase		= zs;
-		padapter->regData		= zs + REG_DATA;					// data register I/O address
-		padapter->regError		= zs + REG_ERROR;					// error register I/O address
-		padapter->regSectCount	= zs + REG_SECTOR_COUNT;			// sector count register I/O address
-		padapter->regLba0		= zs + REG_LBA_0;					// least significant byte of LBA
-		padapter->regLba8		= zs + REG_LBA_8;					// next least significant byte of LBA
-		padapter->regLba16		= zs + REG_LBA_16;					// next most significan byte of LBA
-		padapter->regLba24		= zs + REG_LBA_24;					// head and most 4 significant bits of LBA
-		padapter->regStatCmd	= zs + REG_STAT_CMD;				// status on read and command on write register
-		padapter->regStatSel	= zs + REG_STAT_SEL;				// board status on read and spigot select on write register
-		padapter->regFail		= zs + REG_FAIL;
-		padapter->regAltStat	= zs + REG_ALT_STAT;
-
-		padapter->regDmaDesc	= zs + RTL_DMA1_DESC_PTR;			// address of the DMA discriptor register for direction of transfer
-		padapter->regDmaCmdStat	= zs + RTL_DMA_COMMAND_STATUS + 1;	// Byte #1 of DMA command status register
-		padapter->regDmaAddrPci	= zs + RTL_DMA1_PCI_ADDR;			// 32 bit register for PCI address of DMA
-		padapter->regDmaAddrLoc	= zs + RTL_DMA1_LOCAL_ADDR;			// 32 bit register for local bus address of DMA
-		padapter->regDmaCount	= zs + RTL_DMA1_COUNT;				// 32 bit register for DMA transfer count
-		padapter->regDmaMode	= zs + RTL_DMA1_MODE + 1;			// 32 bit register for DMA mode control
-
-		if ( !inb_p (padapter->regScratchPad + DALE_NUM_DRIVES) )	// if no devices on this board
-			goto unregister;
-
-		pshost->irq = pdev->irq;
-		setirq = 1;
-		for ( z = 0;  z < installed;  z++ )							// scan for shared interrupts
-			{
-			if ( PsiHost[z]->irq == pshost->irq )					// if shared then, don't posses
-				setirq = 0;
-			}
-		if ( setirq )												// if not shared, posses
-			{
-			if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 )
-				{
-				if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 )
-					{
-					printk ("Unable to allocate IRQ for PCI-2220I controller.\n");
-					goto unregister;
-					}
-				}
-			padapter->irqOwned = pshost->irq;						// set IRQ as owned
-			}
-		padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC);
-		if ( !padapter->kBuffer )
-			{
-			printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
-			free_irq (pshost->irq, padapter);
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+		if ( GetRegs (pshost, FALSE, pcidev) )
+#else
+		if ( GetRegs (pshost, FALSE, pci_bus, pci_device_fn) )
+#endif
 			goto unregister;
-			}
-		PsiHost[installed]	= pshost;								// save SCSI_HOST pointer
-
-		pshost->io_port		= padapter->basePort;
-		pshost->n_io_port	= 0xFF;
-		pshost->unique_id	= padapter->regBase;
-		pshost->max_id		= 4;
 
-		outb_p (0x01, padapter->regRange);							// fix our range register because other drivers want to tromp on it
-
-		padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
-		if ( padapter->timingMode >= 2 )
-			padapter->timingAddress	= ModeArray[padapter->timingMode - 2];
-		else
-			padapter->timingPIO = TRUE;
-			
-		ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
-		for ( z = 0;  z < inb_p (padapter->regScratchPad + DALE_NUM_DRIVES);  ++z )
+		pshost->max_id = padapter->numberOfDrives;
+		for ( z = 0;  z < padapter->numberOfDrives;  z++ )
 			{
 			unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
-			padapter->device[z].device	 = inb_p (padapter->regScratchPad + DALE_SCRATH_DEVICE_0 + unit);
-			padapter->device[z].byte6	 = (UCHAR)(((unit & 1) << 4) | 0xE0);
-			padapter->device[z].spigot	 = (UCHAR)(1 << (unit >> 1));
-			padapter->device[z].sectors	 = DaleSetup.setupDevice[unit].sectors;
-			padapter->device[z].heads	 = DaleSetup.setupDevice[unit].heads;
-			padapter->device[z].cylinders = DaleSetup.setupDevice[unit].cylinders;
-			padapter->device[z].blocks	 = DaleSetup.setupDevice[unit].blocks;
+			pdev = &padapter->device[z];
+			pdev->byte6		= (UCHAR)(((unit & 1) << 4) | 0xE0);
+			pdev->spigot	= (UCHAR)(1 << (unit >> 1));
+			pdev->sectors	= DaleSetup.setupDevice[unit].sectors;
+			pdev->heads		= DaleSetup.setupDevice[unit].heads;
+			pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+			pdev->blocks	= DaleSetup.setupDevice[unit].blocks;
 
 			if ( !z )
 				{
-				ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
 				DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS);		
 				DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS);		
 				if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) &&
 				     (DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) )
 					{			 
 					raidon = TRUE;
+					if ( unit > (unit ^ 2) )
+						unit = unit ^ 2;
 					}	
+				else
+					raidon = FALSE;
 
-				memcpy (padapter->device[z].DiskMirror, DiskMirror, sizeof (DiskMirror));
-				padapter->raidData[0] = &padapter->device[z].DiskMirror[0];
-				padapter->raidData[2] = &padapter->device[z].DiskMirror[1];
+				memcpy (pdev->DiskMirror, DiskMirror, sizeof (DiskMirror));
+				padapter->raidData[0] = &pdev->DiskMirror[0];
+				padapter->raidData[2] = &pdev->DiskMirror[1];
 				
-				if ( raidon )
-					{
-					padapter->device[z].lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
-					padapter->device[z].lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
+				spigot1 = spigot2 = FALSE;
+				pdev->spigots[0] = 1;
+				pdev->spigots[1] = 2;
+				pdev->lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
+				pdev->lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
 						
-					if ( !(DiskMirror[1].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[0] )
-						spigot1 = TRUE;
-					if ( !(DiskMirror[0].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[1] )
-						spigot2 = TRUE;
-					if ( DiskMirror[0].status & UCBF_SURVIVOR & DiskMirror[1].status & UCBF_SURVIVOR )
-						spigot1 = TRUE;
-
-					if ( spigot1 && (DiskMirror[0].status & UCBF_REBUILD) )
-						InlineReadSignature (padapter, &padapter->device[z], 0);
-					if ( spigot2 && (DiskMirror[1].status & UCBF_REBUILD) )
-						InlineReadSignature (padapter, &padapter->device[z], 1);
-
-					if ( spigot1 && spigot2 )
+				if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+					spigot1 = TRUE;
+				if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+					spigot2 = TRUE;
+				if ( pdev->DiskMirror[0].status & DiskMirror[1].status & UCBF_SURVIVOR )
+					spigot1 = TRUE;
+
+				if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+					InlineReadSignature (padapter, pdev, 0);
+				if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+					InlineReadSignature (padapter, pdev, 1);
+
+				if ( spigot1 && spigot2 && raidon )
+					{
+					pdev->raid = 1;
+					if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+						pdev->spigot = 2;
+					else
+						pdev->spigot = 1;
+					if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+						padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+					}
+				else
+					{
+					if ( spigot1 )
 						{
-						padapter->device[z].raid = 1;
-						if ( DiskMirror[0].status & UCBF_REBUILD )
-							padapter->device[z].spigot = 2;
-						else
-							padapter->device[z].spigot = 1;
-						if ( (DiskMirror[0].status & UCBF_REBUILD) || (DiskMirror[1].status & UCBF_REBUILD) )
-							{
-							padapter->reconOn = padapter->reconIsStarting = TRUE;
-							}
+						if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+							goto unregister;
+						pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+						pdev->spigot = 1;
 						}
 					else
 						{
-						if ( spigot1 )
-							{
-							if ( DiskMirror[0].status & UCBF_REBUILD )
-								goto unregister;
-							DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
-							padapter->device[z].spigot = 1;
-							}
-						else
+						if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+							goto unregister;
+						pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+						pdev->spigot = 2;
+						}
+					if ( DaleSetup.rebootRebuild && raidon )
+						padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+					}
+			
+				if ( raidon )
+					break;
+				}
+			}
+
+		SetupFinish (padapter, "2220", pshost->irq);
+	
+		if ( ++Installed < MAXADAPTER )
+			continue;
+		break;;
+unregister:;
+		scsi_unregister (pshost);
+		}
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+	while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_BIGD_1, pcidev)) != NULL )
+#else
+	found = 0;
+	while ( !pcibios_find_device (VENDOR_PSI, DEVICE_BIGD_1, found++, &pci_bus, &pci_device_fn) )
+#endif
+		{
+		pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
+		padapter = HOSTDATA(pshost);
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+		if ( GetRegs (pshost, TRUE, pcidev) )
+#else
+		if ( GetRegs (pshost, TRUE, pci_bus, pci_device_fn) )
+#endif
+			goto unregister1;
+
+		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
+			DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z);		
+
+		pshost->max_id = padapter->numberOfDrives;
+		padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE);
+		for ( z = 0;  z < padapter->numberOfDrives;  z++ )
+			{
+			unit = inb_p (padapter->regScratchPad + BIGD_DEVICE_0 + z);
+			pdev = &padapter->device[z];
+			pdev->byte6		= (UCHAR)(((unit & 1) << 4) | 0xE0);
+			pdev->spigot	= (UCHAR)(1 << (unit >> 1));
+			pdev->sectors	= DaleSetup.setupDevice[unit].sectors;
+			pdev->heads		= DaleSetup.setupDevice[unit].heads;
+			pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+			pdev->blocks	= DaleSetup.setupDevice[unit].blocks;
+			
+			if ( (DiskMirror[unit].signature == SIGNATURE) && (DiskMirror[unit ^ 2].signature == SIGNATURE) &&
+			     (DiskMirror[unit].pairIdentifier == (DiskMirror[unit ^ 2].pairIdentifier ^ 1)) )
+				{			 
+				raidon = TRUE;
+				if ( unit > (unit ^ 2) )
+					unit = unit ^ 2;
+				}	
+			else
+				raidon = FALSE;
+				
+			spigot1 = spigot2 = FALSE;
+			memcpy (&pdev->DiskMirror[0], &DiskMirror[unit], sizeof (DISK_MIRROR));
+			memcpy (&pdev->DiskMirror[1], &DiskMirror[unit ^ 2], sizeof (DISK_MIRROR));
+			padapter->raidData[unit]	 = &pdev->DiskMirror[0];
+			padapter->raidData[unit ^ 2] = &pdev->DiskMirror[1];
+			pdev->spigots[0] = 1 << (unit >> 1);
+			pdev->spigots[1] = 1 << ((unit ^ 2) >> 1);
+			pdev->deviceID[0] = unit;
+			pdev->deviceID[1] = unit ^ 2;
+			pdev->lastsectorlba[0] = InlineIdentify (padapter, pdev->spigots[0], unit & 1);
+			pdev->lastsectorlba[1] = InlineIdentify (padapter, pdev->spigots[1], unit & 1);
+
+			if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+				spigot1 = TRUE;
+			if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+				spigot2 = TRUE;
+			if ( pdev->DiskMirror[0].status & pdev->DiskMirror[1].status & UCBF_SURVIVOR )
+				spigot1 = TRUE;
+
+			if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+				InlineReadSignature (padapter, pdev, 0);
+			if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+				InlineReadSignature (padapter, pdev, 1);
+
+			if ( spigot1 && spigot2 && raidon )
+				{
+				pdev->raid = 1;
+				if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+					pdev->spigot = pdev->spigots[1];
+				else
+					pdev->spigot = pdev->spigots[0];
+				if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+					padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+				}
+			else
+				{
+				if ( spigot1 )
+					{
+					if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+						goto unregister1;
+					pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+					pdev->spigot = pdev->spigots[0];
+					}
+				else
+					{
+					if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+						goto unregister;
+					pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+					pdev->spigot = pdev->spigots[1];
+					}
+				if ( DaleSetup.rebootRebuild && raidon )
+					padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+				}
+			}
+		
+		if ( !padapter->numberOfDrives )									// If no ATA devices then scan ATAPI
+			{
+			unit = 0;
+			for ( spigot1 = 0;  spigot1 < 4;  spigot1++ )
+				{
+				for ( device = 0;  device < 2;  device++ )
+					{
+					DEB (printk ("\nPCI2242I: scanning for ID %d ", (spigot1 * 2) + device));
+					pdev = &(padapter->device[(spigot1 * 2) + device]);
+					pdev->byte6 = 0x0A | (device << 4);
+					pdev->spigot = 1 << spigot1;
+					if ( !AtapiReset (padapter, pdev) )
+						{
+						DEB (printk (" Device found "));
+						if ( !AtapiIdentify (padapter, pdev) )
 							{
-							if ( DiskMirror[1].status & UCBF_REBUILD )
-								goto unregister;
-							DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
-							padapter->device[z].spigot = 2;
+							DEB (printk (" Device verified"));
+							unit++;
+							continue;
 							}
-						if ( DaleSetup.rebootRebuil )
-							padapter->reconOn = padapter->reconIsStarting = TRUE;
 						}
-				
-					break;
+					pdev->spigot = pdev->byte6 = 0;
 					}
 				}
+
+			if ( unit )
+				{
+				padapter->atapi = TRUE;
+				padapter->timingAddress = DALE_DATA_MODE3;
+				outw_p (0x0900, padapter->regIrqControl);					// Turn our interrupts on
+				outw_p (0x0C41, padapter->regDmaMode - 1);					// setup for 16 bits, ready enabled, done IRQ enabled, no incriment
+				outb_p (0xFF, padapter->regFail);							// all fail lights and alarm off
+				pshost->max_id = 8;
+				}
 			}
-			
-		init_timer (&padapter->timer);
-		padapter->timer.function = TimerExpiry;
-		padapter->timer.data = (unsigned long)padapter;
-		init_timer (&padapter->reconTimer);
-		padapter->reconTimer.function = ReconTimerExpiry;
-		padapter->reconTimer.data = (unsigned long)padapter;
-		printk("\nPCI-2220I EIDE CONTROLLER: at I/O = %X/%X  IRQ = %d\n", padapter->basePort, padapter->regBase, pshost->irq);
-		printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
-		found++;
-		if ( ++installed < MAXADAPTER )
+		SetupFinish (padapter, "2240", pshost->irq);
+		
+		if ( ++Installed < MAXADAPTER )
 			continue;
 		break;;
-unregister:;
+unregister1:;
 		scsi_unregister (pshost);
-		found++;
 		}
-	
-	NumAdapters = installed;
-	return installed;
+
+	NumAdapters = Installed;
+	return Installed;
 	}
 /****************************************************************
  *	Name:	Pci2220i_Abort
@@ -1933,6 +2891,19 @@
  ****************************************************************/
 int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
 	{
+	PADAPTER2220I	padapter = HOSTDATA(SCpnt->host);			// Pointer to adapter control structure
+	POUR_DEVICE		pdev	 = &padapter->device[SCpnt->target];// Pointer to device information
+
+	if ( !padapter->SCpnt )
+		return SCSI_ABORT_NOT_RUNNING;
+	
+	if ( padapter->atapi )
+		{
+		if ( AtapiReset (padapter, pdev) )
+			return SCSI_ABORT_ERROR;
+		OpDone (padapter, DID_ABORT << 16);
+		return SCSI_ABORT_SUCCESS;
+		}
 	return SCSI_ABORT_SNOOZE;
 	}
 /****************************************************************
@@ -1952,6 +2923,15 @@
  ****************************************************************/
 int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
 	{
+	PADAPTER2220I	padapter = HOSTDATA(SCpnt->host);			// Pointer to adapter control structure
+	POUR_DEVICE		pdev	 = &padapter->device[SCpnt->target];// Pointer to device information
+
+	if ( padapter->atapi )
+		{
+		if ( AtapiReset (padapter, pdev) )
+			return SCSI_RESET_ERROR;
+		return SCSI_RESET_SUCCESS;
+		}
 	return SCSI_RESET_PUNT;
 	}
 /****************************************************************
@@ -1967,6 +2947,7 @@
 int Pci2220i_Release (struct Scsi_Host *pshost)
 	{
     PADAPTER2220I	padapter = HOSTDATA (pshost);
+	USHORT			z;
 
 	if ( padapter->reconOn )
 		{
@@ -1981,11 +2962,29 @@
 		}
 
 	// save RAID status on the board
-	outb_p (DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS);		
-	outb_p (DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS);		
+	if ( padapter->bigD )
+		{
+		outb_p (padapter->failRegister, padapter->regScratchPad + BIGD_ALARM_IMAGE);
+		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
+			{
+			if ( padapter->raidData )
+				outb_p (padapter->raidData[z]->status, padapter->regScratchPad + BIGD_RAID_0_STATUS + z);	
+			else
+				outb_p (0, padapter->regScratchPad + BIGD_RAID_0_STATUS);	
+			}
+		}
+	else
+		{
+		outb_p (padapter->device[0].DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS);		
+		outb_p (padapter->device[0].DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS);		
+		}
 
 	if ( padapter->irqOwned )
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+		free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
 		free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
     release_region (pshost->io_port, pshost->n_io_port);
 	kfree (padapter->kBuffer);
     scsi_unregister(pshost);
@@ -2011,11 +3010,14 @@
 	{
 	POUR_DEVICE	pdev;
 
-	pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
+	if ( !(HOSTDATA(disk->device->host))->atapi )
+		{
+		pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
 
-	geom[0] = pdev->heads;
-	geom[1] = pdev->sectors;
-	geom[2] = pdev->cylinders;
+		geom[0] = pdev->heads;
+		geom[1] = pdev->sectors;
+		geom[2] = pdev->cylinders;
+		}
 	return 0;
 	}
 
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2220i.h linux/drivers/scsi/pci2220i.h
--- v2.3.46/linux/drivers/scsi/pci2220i.h	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/pci2220i.h	Sun Feb 20 20:49:46 2000
@@ -21,265 +21,11 @@
 #ifndef _PCI2220I_H
 #define _PCI2220I_H
 
-#ifndef	PSI_EIDE_SCSIOP
-#define	PSI_EIDE_SCSIOP	1
-
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif 
 #define	LINUXVERSION(v,p,s)    (((v)<<16) + ((p)<<8) + (s))
 
-/************************************************/
-/*		Some defines that we like 				*/
-/************************************************/
-#define	CHAR		char
-#define	UCHAR		unsigned char
-#define	SHORT		short
-#define	USHORT		unsigned short
-#define	BOOL		unsigned short
-#define	LONG		long
-#define	ULONG		unsigned long
-#define	VOID		void
-
-#include "psi_dale.h"
-
-/************************************************/
-/*		Timeout konstants		 				*/
-/************************************************/
-#define	TIMEOUT_READY				100			// 100 mSec
-#define	TIMEOUT_DRQ					300			// 300 mSec
-#define	TIMEOUT_DATA				(3 * HZ)	// 3 seconds
-
-/************************************************/
-/*		Misc. macros			 				*/
-/************************************************/
-#define ANY2SCSI(up, p)					\
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up)					\
-( (((long)*(((UCHAR *)up))) << 16)		\
-+ (((long)(((UCHAR *)up)[1])) << 8)		\
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p)				\
-((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
-((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
-((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up)					\
-( (((long)(((UCHAR *)up)[0])) << 24)	\
-+ (((long)(((UCHAR *)up)[1])) << 16)	\
-+ (((long)(((UCHAR *)up)[2])) <<  8)	\
-+ ((long)(((UCHAR *)up)[3])) )
-
-#define	SelectSpigot(padapter,spigot)	outb_p (spigot, padapter->regStatSel)
-#define WriteCommand(padapter,cmd)		outb_p (cmd, padapter->regStatCmd)
-
-/************************************************/
-/*		SCSI CDB operation codes 				*/
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY		0x00
-#define SCSIOP_REZERO_UNIT			0x01
-#define SCSIOP_REWIND				0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
-#define SCSIOP_REQUEST_SENSE		0x03
-#define SCSIOP_FORMAT_UNIT			0x04
-#define SCSIOP_READ_BLOCK_LIMITS	0x05
-#define SCSIOP_REASSIGN_BLOCKS		0x07
-#define SCSIOP_READ6				0x08
-#define SCSIOP_RECEIVE				0x08
-#define SCSIOP_WRITE6				0x0A
-#define SCSIOP_PRINT				0x0A
-#define SCSIOP_SEND					0x0A
-#define SCSIOP_SEEK6				0x0B
-#define SCSIOP_TRACK_SELECT			0x0B
-#define SCSIOP_SLEW_PRINT			0x0B
-#define SCSIOP_SEEK_BLOCK			0x0C
-#define SCSIOP_PARTITION			0x0D
-#define SCSIOP_READ_REVERSE			0x0F
-#define SCSIOP_WRITE_FILEMARKS		0x10
-#define SCSIOP_FLUSH_BUFFER			0x10
-#define SCSIOP_SPACE				0x11
-#define SCSIOP_INQUIRY				0x12
-#define SCSIOP_VERIFY6				0x13
-#define SCSIOP_RECOVER_BUF_DATA		0x14
-#define SCSIOP_MODE_SELECT			0x15
-#define SCSIOP_RESERVE_UNIT			0x16
-#define SCSIOP_RELEASE_UNIT			0x17
-#define SCSIOP_COPY					0x18
-#define SCSIOP_ERASE				0x19
-#define SCSIOP_MODE_SENSE			0x1A
-#define SCSIOP_START_STOP_UNIT		0x1B
-#define SCSIOP_STOP_PRINT			0x1B
-#define SCSIOP_LOAD_UNLOAD			0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
-#define SCSIOP_SEND_DIAGNOSTIC		0x1D
-#define SCSIOP_MEDIUM_REMOVAL		0x1E
-#define SCSIOP_READ_CAPACITY		0x25
-#define SCSIOP_READ					0x28
-#define SCSIOP_WRITE				0x2A
-#define SCSIOP_SEEK					0x2B
-#define SCSIOP_LOCATE				0x2B
-#define SCSIOP_WRITE_VERIFY			0x2E
-#define SCSIOP_VERIFY				0x2F
-#define SCSIOP_SEARCH_DATA_HIGH		0x30
-#define SCSIOP_SEARCH_DATA_EQUAL	0x31
-#define SCSIOP_SEARCH_DATA_LOW		0x32
-#define SCSIOP_SET_LIMITS			0x33
-#define SCSIOP_READ_POSITION		0x34
-#define SCSIOP_SYNCHRONIZE_CACHE	0x35
-#define SCSIOP_COMPARE				0x39
-#define SCSIOP_COPY_COMPARE			0x3A
-#define SCSIOP_WRITE_DATA_BUFF		0x3B
-#define SCSIOP_READ_DATA_BUFF		0x3C
-#define SCSIOP_CHANGE_DEFINITION	0x40
-#define SCSIOP_READ_SUB_CHANNEL		0x42
-#define SCSIOP_READ_TOC				0x43
-#define SCSIOP_READ_HEADER			0x44
-#define SCSIOP_PLAY_AUDIO			0x45
-#define SCSIOP_PLAY_AUDIO_MSF		0x47
-#define SCSIOP_PLAY_TRACK_INDEX		0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
-#define SCSIOP_PAUSE_RESUME			0x4B
-#define SCSIOP_LOG_SELECT			0x4C
-#define SCSIOP_LOG_SENSE			0x4D
-#define SCSIOP_MODE_SELECT10		0x55
-#define SCSIOP_MODE_SENSE10			0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
-#define SCSIOP_MECHANISM_STATUS		0xBD
-#define SCSIOP_READ_CD				0xBE
-
-// IDE command definitions
-#define IDE_COMMAND_ATAPI_RESET		0x08
-#define IDE_COMMAND_READ			0x20
-#define IDE_COMMAND_WRITE			0x30
-#define IDE_COMMAND_RECALIBRATE		0x10
-#define IDE_COMMAND_SEEK			0x70
-#define IDE_COMMAND_SET_PARAMETERS	0x91
-#define IDE_COMMAND_VERIFY			0x40
-#define IDE_COMMAND_ATAPI_PACKET	0xA0
-#define IDE_COMMAND_ATAPI_IDENTIFY	0xA1
-#define	IDE_CMD_READ_MULTIPLE		0xC4
-#define	IDE_CMD_WRITE_MULTIPLE		0xC5
-#define	IDE_CMD_SET_MULTIPLE		0xC6
-#define IDE_COMMAND_IDENTIFY		0xEC
-
-// IDE status definitions
-#define IDE_STATUS_ERROR			0x01
-#define IDE_STATUS_INDEX			0x02
-#define IDE_STATUS_CORRECTED_ERROR	0x04
-#define IDE_STATUS_DRQ				0x08
-#define IDE_STATUS_DSC				0x10
-#define	IDE_STATUS_WRITE_FAULT		0x20
-#define IDE_STATUS_DRDY				0x40
-#define IDE_STATUS_BUSY				0x80
-
-// IDE error definitions
-#define	IDE_ERROR_AMNF				0x01
-#define	IDE_ERROR_TKONF				0x02
-#define	IDE_ERROR_ABRT				0x04
-#define	IDE_ERROR_MCR				0x08
-#define	IDE_ERROR_IDFN				0x10
-#define	IDE_ERROR_MC				0x20
-#define	IDE_ERROR_UNC				0x40
-#define	IDE_ERROR_BBK				0x80
-
-// SCSI read capacity structure
-typedef	struct _READ_CAPACITY_DATA
-	{
-	ULONG blks;				/* total blocks (converted to little endian) */
-	ULONG blksiz;			/* size of each (converted to little endian) */
-	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-typedef struct _INQUIRYDATA
-	{
-	UCHAR DeviceType			:5;
-	UCHAR DeviceTypeQualifier	:3;
-	UCHAR DeviceTypeModifier	:7;
-	UCHAR RemovableMedia		:1;
-    UCHAR Versions;
-    UCHAR ResponseDataFormat;
-    UCHAR AdditionalLength;
-    UCHAR Reserved[2];
-	UCHAR SoftReset				:1;
-	UCHAR CommandQueue			:1;
-	UCHAR Reserved2				:1;
-	UCHAR LinkedCommands		:1;
-	UCHAR Synchronous			:1;
-	UCHAR Wide16Bit				:1;
-	UCHAR Wide32Bit				:1;
-	UCHAR RelativeAddressing	:1;
-    UCHAR VendorId[8];
-    UCHAR ProductId[16];
-    UCHAR ProductRevisionLevel[4];
-    UCHAR VendorSpecific[20];
-    UCHAR Reserved3[40];
-	}	INQUIRYDATA, *PINQUIRYDATA;
-
-// IDE IDENTIFY data
-#pragma pack (1)
-#pragma align 1
-typedef struct _IDENTIFY_DATA
-	{
-    USHORT	GeneralConfiguration;		//  0
-    USHORT	NumberOfCylinders;			//  1
-    USHORT	Reserved1;					//  2
-    USHORT	NumberOfHeads;				//  3
-    USHORT	UnformattedBytesPerTrack;	//  4
-    USHORT	UnformattedBytesPerSector;	//  5
-    USHORT	SectorsPerTrack;			//  6
-	USHORT	NumBytesISG;				//  7 Byte Len - inter-sector gap
-	USHORT	NumBytesSync;				//  8          - sync field
-	USHORT	NumWordsVUS;				//  9 Len - Vendor Unique Info
-    USHORT	SerialNumber[10];			// 10
-    USHORT	BufferType;					// 20
-    USHORT	BufferSectorSize;			// 21
-    USHORT	NumberOfEccBytes;			// 22
-    USHORT	FirmwareRevision[4];		// 23
-    USHORT	ModelNumber[20];			// 27
-	USHORT	NumSectorsPerInt	:8;		// 47 Multiple Mode - Sec/Blk
-	USHORT	Reserved2			:8;		// 47
-	USHORT	DoubleWordMode;				// 48 flag for double word mode capable
-	USHORT	VendorUnique1		:8;		// 49
-	USHORT	SupportDMA			:1;		// 49 DMA supported
-	USHORT	SupportLBA			:1;		// 49 LBA supported
-	USHORT	SupportIORDYDisable	:1;		// 49 IORDY can be disabled
-	USHORT	SupportIORDY		:1;		// 49 IORDY supported
-	USHORT	ReservedPseudoDMA	:1;		// 49 reserved for pseudo DMA mode support
-	USHORT	Reserved3			:3;		// 49
-	USHORT	Reserved4;					// 50
-	USHORT	Reserved5			:8;		// 51 Transfer Cycle Timing - PIO
-	USHORT	PIOCycleTime		:8;		// 51 Transfer Cycle Timing - PIO
-	USHORT	Reserved6			:8;		// 52                       - DMA
-	USHORT	DMACycleTime		:8;		// 52                       - DMA
-	USHORT	Valid_54_58			:1;		// 53 words 54 - 58 are vaild
-	USHORT	Valid_64_70			:1;		// 53 words 64 - 70 are valid
-	USHORT	Reserved7			:14;	// 53
-	USHORT	LogNumCyl;					// 54 Current Translation - Num Cyl
-	USHORT	LogNumHeads;				// 55                       Num Heads
-	USHORT	LogSectorsPerTrack;			// 56                       Sec/Trk
-	ULONG	LogTotalSectors;			// 57                       Total Sec
-	USHORT	CurrentNumSecPerInt	:8;		// 59 current setting for number of sectors per interrupt
-	USHORT	ValidNumSecPerInt	:1;		// 59 Current setting is valid for number of sectors per interrupt
-	USHORT	Reserved8			:7;		// 59
-	ULONG	LBATotalSectors;			// 60 LBA Mode - Sectors
-	USHORT	DMASWordFlags;				// 62
-	USHORT	DMAMWordFlags;				// 63
-	USHORT	AdvancedPIOSupport  :8;		// 64 Flow control PIO transfer modes supported
-	USHORT	Reserved9			:8;		// 64
-	USHORT	MinMultiDMACycle;			// 65 minimum multiword DMA transfer cycle time per word
-	USHORT	RecomendDMACycle;			// 66 Manufacturer's recommende multiword DMA transfer cycle time
-	USHORT	MinPIOCycleWithoutFlow;		// 67 Minimum PIO transfer cycle time without flow control
-	USHORT	MinPIOCylceWithFlow;		// 68 Minimum PIO transfer cycle time with IORDY flow control
-	USHORT	ReservedSpace[256-69];		// 69
-	}	IDENTIFY_DATA, *PIDENTIFY_DATA;
-#pragma pack ()
-#pragma align 0
-#endif	// PSI_EIDE_SCSIOP
-
 // function prototypes
 int Pci2220i_Detect			(Scsi_Host_Template *tpnt);
 int Pci2220i_Command		(Scsi_Cmnd *SCpnt);
@@ -293,12 +39,15 @@
 	#define NULL 0
 #endif
 
+extern struct proc_dir_entry Proc_Scsi_Pci2220i;
+
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
 #define PCI2220I {															\
 		next:						NULL,									\
 		module:						NULL,									\
-		proc_name:					"pci2220i",					\
+		proc_dir:					&Proc_Scsi_Pci2220i,					\
 		proc_info:					NULL,	/* let's not bloat the kernel */\
-		name:						"PCI-2220I EIDE Disk Controller",		\
+		name:						"PCI-2220I/PCI-2240I",					\
 		detect:						Pci2220i_Detect,						\
 		release:					Pci2220i_Release,						\
 		info:						NULL,	/* let's not bloat the kernel */\
@@ -315,11 +64,34 @@
 		bios_param:					Pci2220i_BiosParam,						\
 		can_queue:					1,										\
 		this_id:					-1,										\
-		sg_tablesize:				SG_NONE,								\
+		sg_tablesize:				SG_ALL,								\
 		cmd_per_lun:				1,										\
 		present:					0,										\
 		unchecked_isa_dma:			0,										\
 		use_clustering:				DISABLE_CLUSTERING,						\
 		use_new_eh_code:			0										\
 		}
+#else
+#define PCI2220I { NULL, NULL,						\
+			&Proc_Scsi_Pci2220i,/* proc_dir_entry */\
+			NULL,		                			\
+			"PCI-2220I/PCI-2240I",					\
+			Pci2220i_Detect,						\
+			Pci2220i_Release,						\
+			NULL,	 								\
+			Pci2220i_Command,						\
+			Pci2220i_QueueCommand,					\
+			Pci2220i_Abort,							\
+			Pci2220i_Reset,							\
+			NULL,									\
+			Pci2220i_BiosParam,                 	\
+			1, 										\
+			-1, 									\
+			SG_ALL,		 						\
+			1, 										\
+			0, 										\
+			0, 										\
+			DISABLE_CLUSTERING }
+#endif
+
 #endif
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/psi_dale.h linux/drivers/scsi/psi_dale.h
--- v2.3.46/linux/drivers/scsi/psi_dale.h	Tue Apr 13 07:54:02 1999
+++ linux/drivers/scsi/psi_dale.h	Fri Feb 18 14:50:03 2000
@@ -20,16 +20,32 @@
  ****************************************************************************/
 
 /************************************************/
+/*		Some defines that we like 				*/
+/************************************************/
+#define	CHAR		char
+#define	UCHAR		unsigned char
+#define	SHORT		short
+#define	USHORT		unsigned short
+#define	BOOL		unsigned short
+#define	LONG		long
+#define	ULONG		unsigned long
+#define	VOID		void
+
+/************************************************/
 /*		Dale PCI setup							*/
 /************************************************/
 #define	VENDOR_PSI			0x1256
 #define	DEVICE_DALE_1		0x4401		/* 'D1' */
+#define	DEVICE_BIGD_1		0x4201		/* 'B1' */
+#define	DEVICE_BIGD_2		0x4202		/* 'B2' */
 
 /************************************************/
 /*		Misc konstants							*/
 /************************************************/
 #define	DALE_MAXDRIVES			4
+#define	BIGD_MAXDRIVES			8
 #define	SECTORSXFER				8
+#define	ATAPI_TRANSFER			8192
 #define	BYTES_PER_SECTOR		512
 #define	DEFAULT_TIMING_MODE		5
 
@@ -49,90 +65,136 @@
 /************************************************/
 /*		DALE Register address offsets			*/
 /************************************************/
-#define	REG_DATA						0x80
-#define	REG_ERROR						0x84
-#define	REG_SECTOR_COUNT				0x88
-#define	REG_LBA_0						0x8C
-#define	REG_LBA_8						0x90
-#define	REG_LBA_16						0x94
-#define	REG_LBA_24						0x98
-#define	REG_STAT_CMD					0x9C
-#define	REG_STAT_SEL					0xA0
-#define	REG_FAIL						0xB0
-#define	REG_ALT_STAT					0xB8
-#define	REG_DRIVE_ADRS					0xBC
-
-#define	DALE_DATA_SLOW					0x00040000L
-#define	DALE_DATA_MODE2					0x00040000L
-#define	DALE_DATA_MODE3					0x00050000L
-#define	DALE_DATA_MODE4					0x00060000L
-#define	DALE_DATA_MODE4P				0x00070000L
-
-#define RTR_LOCAL_RANGE					0x000
-#define RTR_LOCAL_REMAP					0x004
-#define RTR_EXP_RANGE					0x010
-#define RTR_EXP_REMAP					0x014
-#define RTR_REGIONS						0x018
-#define RTR_DM_MASK						0x01C
-#define RTR_DM_LOCAL_BASE				0x020
-#define RTR_DM_IO_BASE					0x024
-#define RTR_DM_PCI_REMAP				0x028
-#define RTR_DM_IO_CONFIG				0x02C
-#define RTR_MAILBOX						0x040
-#define RTR_LOCAL_DOORBELL				0x060
-#define RTR_PCI_DOORBELL				0x064
-#define RTR_INT_CONTROL_STATUS 			0x068
-#define RTR_EEPROM_CONTROL_STATUS		0x06C
-
-#define RTL_DMA0_MODE					0x00
-#define RTL_DMA0_PCI_ADDR				0x04
-#define RTL_DMA0_LOCAL_ADDR				0x08
-#define RTL_DMA0_COUNT					0x0C
-#define RTL_DMA0_DESC_PTR				0x10
-#define RTL_DMA1_MODE					0x14
-#define RTL_DMA1_PCI_ADDR				0x18
-#define RTL_DMA1_LOCAL_ADDR				0x1C
-#define RTL_DMA1_COUNT					0x20
-#define RTL_DMA1_DESC_PTR				0x24
-#define RTL_DMA_COMMAND_STATUS			0x28
-#define RTL_DMA_ARB0					0x2C
-#define RTL_DMA_ARB1					0x30
+#define	REG_DATA					0x80
+#define	REG_ERROR					0x84
+#define	REG_SECTOR_COUNT			0x88
+#define	REG_LBA_0					0x8C
+#define	REG_LBA_8					0x90
+#define	REG_LBA_16					0x94
+#define	REG_LBA_24					0x98
+#define	REG_STAT_CMD				0x9C
+#define	REG_STAT_SEL				0xA0
+#define	REG_FAIL					0xB0
+#define	REG_ALT_STAT				0xB8
+#define	REG_DRIVE_ADRS				0xBC
+
+#define	DALE_DATA_SLOW				0x00040000L
+#define	DALE_DATA_MODE2				0x00040000L
+#define	DALE_DATA_MODE3				0x00050000L
+#define	DALE_DATA_MODE4				0x00060000L
+#define	DALE_DATA_MODE5				0x00070000L
+
+#define	BIGD_DATA_SLOW				0x00000000L
+#define	BIGD_DATA_MODE0				0x00000000L
+#define	BIGD_DATA_MODE2				0x00000000L
+#define	BIGD_DATA_MODE3				0x00000008L
+#define	BIGD_DATA_MODE4				0x00000010L
+#define	BIGD_DATA_MODE5				0x00000020L
+
+#define RTR_LOCAL_RANGE				0x000
+#define RTR_LOCAL_REMAP				0x004
+#define RTR_EXP_RANGE				0x010
+#define RTR_EXP_REMAP				0x014
+#define RTR_REGIONS					0x018
+#define RTR_DM_MASK					0x01C
+#define RTR_DM_LOCAL_BASE			0x020
+#define RTR_DM_IO_BASE				0x024
+#define RTR_DM_PCI_REMAP			0x028
+#define RTR_DM_IO_CONFIG			0x02C
+#define RTR_MAILBOX					0x040
+#define RTR_LOCAL_DOORBELL			0x060
+#define RTR_PCI_DOORBELL			0x064
+#define RTR_INT_CONTROL_STATUS 		0x068
+#define RTR_EEPROM_CONTROL_STATUS	0x06C
+
+#define RTR_DMA0_MODE				0x0080
+#define RTR_DMA0_PCI_ADDR			0x0084
+#define RTR_DMA0_LOCAL_ADDR			0x0088
+#define RTR_DMA0_COUNT				0x008C
+#define RTR_DMA0_DESC_PTR			0x0090
+#define RTR_DMA1_MODE				0x0094
+#define RTR_DMA1_PCI_ADDR			0x0098
+#define RTR_DMA1_LOCAL_ADDR			0x009C
+#define RTR_DMA1_COUNT				0x00A0
+#define RTR_DMA1_DESC_PTR			0x00A4
+#define RTR_DMA_COMMAND_STATUS		0x00A8
+#define RTR_DMA_ARB0				0x00AC
+#define RTR_DMA_ARB1				0x00B0
+
+#define RTL_DMA0_MODE				0x00
+#define RTL_DMA0_PCI_ADDR			0x04
+#define RTL_DMA0_LOCAL_ADDR			0x08
+#define RTL_DMA0_COUNT				0x0C
+#define RTL_DMA0_DESC_PTR			0x10
+#define RTL_DMA1_MODE				0x14
+#define RTL_DMA1_PCI_ADDR			0x18
+#define RTL_DMA1_LOCAL_ADDR			0x1C
+#define RTL_DMA1_COUNT				0x20
+#define RTL_DMA1_DESC_PTR			0x24
+#define RTL_DMA_COMMAND_STATUS		0x28
+#define RTL_DMA_ARB0				0x2C
+#define RTL_DMA_ARB1				0x30
 
 /************************************************/
 /*		Dale Scratchpad locations				*/
 /************************************************/
-#define	DALE_CHANNEL_DEVICE_0			0		// device channel locations
-#define	DALE_CHANNEL_DEVICE_1			1
-#define	DALE_CHANNEL_DEVICE_2			2
-#define	DALE_CHANNEL_DEVICE_3			3
-
-#define	DALE_SCRATH_DEVICE_0			4		// device type codes
-#define	DALE_SCRATH_DEVICE_1			5
-#define DALE_SCRATH_DEVICE_2			6
-#define	DALE_SCRATH_DEVICE_3			7
-
-#define	DALE_RAID_0_STATUS				8
-#define DALE_RAID_1_STATUS				9
-
-#define	DALE_TIMING_MODE				12		// bus master timing mode (2, 3, 4, 5)
-#define	DALE_NUM_DRIVES					13		// number of addressable drives on this board
-#define	DALE_RAID_ON					14 		// RAID status On
-#define	DALE_LAST_ERROR					15		// Last error code from BIOS
+#define	DALE_CHANNEL_DEVICE_0		0		// device channel locations
+#define	DALE_CHANNEL_DEVICE_1		1
+#define	DALE_CHANNEL_DEVICE_2		2
+#define	DALE_CHANNEL_DEVICE_3		3
+
+#define	DALE_SCRATCH_DEVICE_0		4		// device type codes
+#define	DALE_SCRATCH_DEVICE_1		5
+#define DALE_SCRATCH_DEVICE_2		6
+#define	DALE_SCRATCH_DEVICE_3		7
+
+#define	DALE_RAID_0_STATUS			8
+#define DALE_RAID_1_STATUS			9
+
+#define	DALE_TIMING_MODE			12		// bus master timing mode (2, 3, 4, 5)
+#define	DALE_NUM_DRIVES				13		// number of addressable drives on this board
+#define	DALE_RAID_ON				14 		// RAID status On
+#define	DALE_LAST_ERROR				15		// Last error code from BIOS
+
+/************************************************/
+/*		BigD Scratchpad locations				*/
+/************************************************/
+#define	BIGD_DEVICE_0			0		// device channel locations
+#define	BIGD_DEVICE_1			1
+#define	BIGD_DEVICE_2			2
+#define	BIGD_DEVICE_3			3
+
+#define	BIGD_DEVICE_4			4		// device type codes
+#define	BIGD_DEVICE_5			5
+#define BIGD_DEVICE_6			6
+#define	BIGD_DEVICE_7			7
+
+#define	BIGD_ALARM_IMAGE		11		// ~image of alarm fail register		
+#define	BIGD_TIMING_MODE		12		// bus master timing mode (2, 3, 4, 5)
+#define	BIGD_NUM_DRIVES			13		// number of addressable drives on this board
+#define	BIGD_RAID_ON			14 		// RAID status is on for the whole board
+#define	BIGD_LAST_ERROR			15		// Last error code from BIOS
+
+#define	BIGD_RAID_0_STATUS		16
+#define BIGD_RAID_1_STATUS		17
+#define	BIGD_RAID_2_STATUS		18
+#define	BIGD_RAID_3_STATUS		19
+#define	BIGD_RAID_4_STATUS		20
+#define BIGD_RAID_5_STATUS		21
+#define	BIGD_RAID_6_STATUS		22
+#define	BIGD_RAID_7_STATUS		23
 
 /************************************************/
 /*		Dale cable select bits					*/
 /************************************************/
-#define	SEL_NONE						0x00
-#define	SEL_1							0x01
-#define	SEL_2							0x02
-
-/************************************************/
-/*		Programmable Interrupt Controller		*/
-/************************************************/
-#define	PIC1							0x20		// first 8259 base port address
-#define	PIC2							0xA0		// second 8259 base port address
-#define	INT_OCW1						1			// Operation Control Word 1: IRQ mask
-#define	EOI								0x20		// non-specific end-of-interrupt
+#define	SEL_NONE					0x00
+#define	SEL_1						0x01
+#define	SEL_2						0x02
+#define	SEL_3						0x04
+#define	SEL_4						0x08
+#define	SEL_NEW_SPEED_1				0x20
+#define	SEL_COPY					0x40
+#define	SEL_IRQ_OFF					0x80
 
 /************************************************/
 /*		Device/Geometry controls				*/
@@ -149,6 +211,18 @@
 #define	DEVICE_DASD_LBA				0x4				// LBA compatible device
 
 /************************************************/
+/*		BigD fail register bits					*/
+/************************************************/
+#define	FAIL_NONE				0x00
+#define	FAIL_0					0x01
+#define	FAIL_1					0x02
+#define	FAIL_2					0x04
+#define	FAIL_MULTIPLE			0x08
+#define	FAIL_GOOD				0x20
+#define	FAIL_AUDIBLE			0x40
+#define	FAIL_ANY				0x80
+
+/************************************************/
 /*		Setup Structure Definitions				*/
 /************************************************/
 typedef struct		// device setup parameters
@@ -168,11 +242,11 @@
 	BOOL			promptBIOS;
 	BOOL			fastFormat;
 	BOOL			shareInterrupt;
-	BOOL			rebootRebuil;
+	BOOL			rebootRebuild;
 	USHORT			timingMode;
 	USHORT			spare5;
 	USHORT			spare6;
-	SETUP_DEVICE	setupDevice[4];
+	SETUP_DEVICE	setupDevice[BIGD_MAXDRIVES];
 	}	SETUP, *PSETUP;
 
 /************************************************/
@@ -210,3 +284,281 @@
 #define	MY_SCSI_REBUILD		0x40			// byte 1 subcommand to reconstruct a mirrored pair
 #define MY_SCSI_DEMOFAIL	0x54			// byte 1 subcommand for RAID failure demonstration
 #define	MY_SCSI_ALARMMUTE	0x60			// byte 1 subcommand to mute any alarm currently on
+
+/************************************************/
+/*		Timeout konstants		 				*/
+/************************************************/
+#define	TIMEOUT_READY				100			// 100 mSec
+#define	TIMEOUT_DRQ					300			// 300 mSec
+#define	TIMEOUT_DATA				(3 * HZ)	// 3 seconds
+
+/************************************************/
+/*		Misc. macros			 				*/
+/************************************************/
+#define ANY2SCSI(up, p)					\
+((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
+((UCHAR *)up)[1] = ((ULONG)(p));
+
+#define SCSI2LONG(up)					\
+( (((long)*(((UCHAR *)up))) << 16)		\
++ (((long)(((UCHAR *)up)[1])) << 8)		\
++ ((long)(((UCHAR *)up)[2])) )
+
+#define XANY2SCSI(up, p)				\
+((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
+((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
+((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
+((UCHAR *)up)[3] = ((long)(p));
+
+#define XSCSI2LONG(up)					\
+( (((long)(((UCHAR *)up)[0])) << 24)	\
++ (((long)(((UCHAR *)up)[1])) << 16)	\
++ (((long)(((UCHAR *)up)[2])) <<  8)	\
++ ((long)(((UCHAR *)up)[3])) )
+
+#define	SelectSpigot(padapter,spigot)	outb_p (spigot, padapter->regStatSel)
+#define WriteCommand(padapter,cmd)		outb_p (cmd, padapter->regStatCmd)
+#define	AtapiDevice(padapter,b)			outb_p (b, padapter->regLba24);
+#define	AtapiCountLo(padapter,b)		outb_p (b, padapter->regLba8)
+#define	AtapiCountHi(padapter,b)		outb_p (b, padapter->regLba16)
+
+/************************************************/
+/*		SCSI CDB operation codes 				*/
+/************************************************/
+#define SCSIOP_TEST_UNIT_READY		0x00
+#define SCSIOP_REZERO_UNIT			0x01
+#define SCSIOP_REWIND				0x01
+#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
+#define SCSIOP_REQUEST_SENSE		0x03
+#define SCSIOP_FORMAT_UNIT			0x04
+#define SCSIOP_READ_BLOCK_LIMITS	0x05
+#define SCSIOP_REASSIGN_BLOCKS		0x07
+#define SCSIOP_READ6				0x08
+#define SCSIOP_RECEIVE				0x08
+#define SCSIOP_WRITE6				0x0A
+#define SCSIOP_PRINT				0x0A
+#define SCSIOP_SEND					0x0A
+#define SCSIOP_SEEK6				0x0B
+#define SCSIOP_TRACK_SELECT			0x0B
+#define SCSIOP_SLEW_PRINT			0x0B
+#define SCSIOP_SEEK_BLOCK			0x0C
+#define SCSIOP_PARTITION			0x0D
+#define SCSIOP_READ_REVERSE			0x0F
+#define SCSIOP_WRITE_FILEMARKS		0x10
+#define SCSIOP_FLUSH_BUFFER			0x10
+#define SCSIOP_SPACE				0x11
+#define SCSIOP_INQUIRY				0x12
+#define SCSIOP_VERIFY6				0x13
+#define SCSIOP_RECOVER_BUF_DATA		0x14
+#define SCSIOP_MODE_SELECT			0x15
+#define SCSIOP_RESERVE_UNIT			0x16
+#define SCSIOP_RELEASE_UNIT			0x17
+#define SCSIOP_COPY					0x18
+#define SCSIOP_ERASE				0x19
+#define SCSIOP_MODE_SENSE			0x1A
+#define SCSIOP_START_STOP_UNIT		0x1B
+#define SCSIOP_STOP_PRINT			0x1B
+#define SCSIOP_LOAD_UNLOAD			0x1B
+#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
+#define SCSIOP_SEND_DIAGNOSTIC		0x1D
+#define SCSIOP_MEDIUM_REMOVAL		0x1E
+#define SCSIOP_READ_CAPACITY		0x25
+#define SCSIOP_READ					0x28
+#define SCSIOP_WRITE				0x2A
+#define SCSIOP_SEEK					0x2B
+#define SCSIOP_LOCATE				0x2B
+#define SCSIOP_WRITE_VERIFY			0x2E
+#define SCSIOP_VERIFY				0x2F
+#define SCSIOP_SEARCH_DATA_HIGH		0x30
+#define SCSIOP_SEARCH_DATA_EQUAL	0x31
+#define SCSIOP_SEARCH_DATA_LOW		0x32
+#define SCSIOP_SET_LIMITS			0x33
+#define SCSIOP_READ_POSITION		0x34
+#define SCSIOP_SYNCHRONIZE_CACHE	0x35
+#define SCSIOP_COMPARE				0x39
+#define SCSIOP_COPY_COMPARE			0x3A
+#define SCSIOP_WRITE_DATA_BUFF		0x3B
+#define SCSIOP_READ_DATA_BUFF		0x3C
+#define SCSIOP_CHANGE_DEFINITION	0x40
+#define SCSIOP_READ_SUB_CHANNEL		0x42
+#define SCSIOP_READ_TOC				0x43
+#define SCSIOP_READ_HEADER			0x44
+#define SCSIOP_PLAY_AUDIO			0x45
+#define SCSIOP_PLAY_AUDIO_MSF		0x47
+#define SCSIOP_PLAY_TRACK_INDEX		0x48
+#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
+#define SCSIOP_PAUSE_RESUME			0x4B
+#define SCSIOP_LOG_SELECT			0x4C
+#define SCSIOP_LOG_SENSE			0x4D
+#define SCSIOP_MODE_SELECT10		0x55
+#define SCSIOP_MODE_SENSE10			0x5A
+#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
+#define SCSIOP_MECHANISM_STATUS		0xBD
+#define SCSIOP_READ_CD				0xBE
+
+// IDE command definitions
+#define IDE_COMMAND_ATAPI_RESET		0x08
+#define IDE_COMMAND_READ			0x20
+#define IDE_COMMAND_WRITE			0x30
+#define IDE_COMMAND_RECALIBRATE		0x10
+#define IDE_COMMAND_SEEK			0x70
+#define IDE_COMMAND_SET_PARAMETERS	0x91
+#define IDE_COMMAND_VERIFY			0x40
+#define IDE_COMMAND_ATAPI_PACKET	0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY	0xA1
+#define	IDE_CMD_READ_MULTIPLE		0xC4
+#define	IDE_CMD_WRITE_MULTIPLE		0xC5
+#define	IDE_CMD_SET_MULTIPLE		0xC6
+#define IDE_COMMAND_IDENTIFY		0xEC
+
+// IDE status definitions
+#define IDE_STATUS_ERROR			0x01
+#define IDE_STATUS_INDEX			0x02
+#define IDE_STATUS_CORRECTED_ERROR	0x04
+#define IDE_STATUS_DRQ				0x08
+#define IDE_STATUS_DSC				0x10
+#define	IDE_STATUS_WRITE_FAULT		0x20
+#define IDE_STATUS_DRDY				0x40
+#define IDE_STATUS_BUSY				0x80
+
+typedef struct _ATAPI_STATUS
+	{
+	CHAR	check		:1;
+	CHAR	reserved1	:1;
+	CHAR	corr		:1;
+	CHAR	drq			:1;
+	CHAR	dsc			:1;
+	CHAR	reserved2	:1;
+	CHAR	drdy		:1;
+	CHAR	bsy			:1;
+	}	ATAPI_STATUS;
+
+typedef struct _ATAPI_REASON
+	{
+	CHAR	cod			:1;
+	CHAR	io			:1;
+	CHAR	reserved1	:6;
+	}	ATAPI_REASON;
+
+typedef struct _ATAPI_ERROR
+	{
+	CHAR	ili			:1;
+	CHAR	eom			:1;
+	CHAR	abort		:1;
+	CHAR	mcr			:1;
+	CHAR	senseKey	:4;
+	}	ATAPI_ERROR;
+
+// IDE error definitions
+#define	IDE_ERROR_AMNF				0x01
+#define	IDE_ERROR_TKONF				0x02
+#define	IDE_ERROR_ABRT				0x04
+#define	IDE_ERROR_MCR				0x08
+#define	IDE_ERROR_IDFN				0x10
+#define	IDE_ERROR_MC				0x20
+#define	IDE_ERROR_UNC				0x40
+#define	IDE_ERROR_BBK				0x80
+
+// SCSI read capacity structure
+typedef	struct _READ_CAPACITY_DATA
+	{
+	ULONG blks;				/* total blocks (converted to little endian) */
+	ULONG blksiz;			/* size of each (converted to little endian) */
+	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+// SCSI inquiry data
+typedef struct _INQUIRYDATA
+	{
+	UCHAR DeviceType			:5;
+	UCHAR DeviceTypeQualifier	:3;
+	UCHAR DeviceTypeModifier	:7;
+	UCHAR RemovableMedia		:1;
+    UCHAR Versions;
+    UCHAR ResponseDataFormat;
+    UCHAR AdditionalLength;
+    UCHAR Reserved[2];
+	UCHAR SoftReset				:1;
+	UCHAR CommandQueue			:1;
+	UCHAR Reserved2				:1;
+	UCHAR LinkedCommands		:1;
+	UCHAR Synchronous			:1;
+	UCHAR Wide16Bit				:1;
+	UCHAR Wide32Bit				:1;
+	UCHAR RelativeAddressing	:1;
+    UCHAR VendorId[8];
+    UCHAR ProductId[16];
+    UCHAR ProductRevisionLevel[4];
+    UCHAR VendorSpecific[20];
+    UCHAR Reserved3[40];
+	}	INQUIRYDATA, *PINQUIRYDATA;
+
+// IDE IDENTIFY data
+#pragma pack (1)
+typedef struct _IDENTIFY_DATA
+	{
+    USHORT	GeneralConfiguration;		//  0
+    USHORT	NumberOfCylinders;			//  1
+    USHORT	Reserved1;					//  2
+    USHORT	NumberOfHeads;				//  3
+    USHORT	UnformattedBytesPerTrack;	//  4
+    USHORT	UnformattedBytesPerSector;	//  5
+    USHORT	SectorsPerTrack;			//  6
+	USHORT	NumBytesISG;				//  7 Byte Len - inter-sector gap
+	USHORT	NumBytesSync;				//  8          - sync field
+	USHORT	NumWordsVUS;				//  9 Len - Vendor Unique Info
+    USHORT	SerialNumber[10];			// 10
+    USHORT	BufferType;					// 20
+    USHORT	BufferSectorSize;			// 21
+    USHORT	NumberOfEccBytes;			// 22
+    USHORT	FirmwareRevision[4];		// 23
+    USHORT	ModelNumber[20];			// 27
+	USHORT	NumSectorsPerInt	:8;		// 47 Multiple Mode - Sec/Blk
+	USHORT	Reserved2			:8;		// 47
+	USHORT	DoubleWordMode;				// 48 flag for double word mode capable
+	USHORT	VendorUnique1		:8;		// 49
+	USHORT	SupportDMA			:1;		// 49 DMA supported
+	USHORT	SupportLBA			:1;		// 49 LBA supported
+	USHORT	SupportIORDYDisable	:1;		// 49 IORDY can be disabled
+	USHORT	SupportIORDY		:1;		// 49 IORDY supported
+	USHORT	ReservedPsuedoDMA	:1;		// 49 reserved for pseudo DMA mode support
+	USHORT	Reserved3			:3;		// 49
+	USHORT	Reserved4;					// 50
+	USHORT	Reserved5			:8;		// 51 Transfer Cycle Timing - PIO
+	USHORT	PIOCycleTime		:8;		// 51 Transfer Cycle Timing - PIO
+	USHORT	Reserved6			:8;		// 52                       - DMA
+	USHORT	DMACycleTime		:8;		// 52                       - DMA
+	USHORT	Valid_54_58			:1;		// 53 words 54 - 58 are vaild
+	USHORT	Valid_64_70			:1;		// 53 words 64 - 70 are valid
+	USHORT	Reserved7			:14;	// 53
+	USHORT	LogNumCyl;					// 54 Current Translation - Num Cyl
+	USHORT	LogNumHeads;				// 55                       Num Heads
+	USHORT	LogSectorsPerTrack;			// 56                       Sec/Trk
+	ULONG	LogTotalSectors;			// 57                       Total Sec
+	USHORT	CurrentNumSecPerInt	:8;		// 59 current setting for number of sectors per interrupt
+	USHORT	ValidNumSecPerInt	:1;		// 59 Current setting is valid for number of sectors per interrupt
+	USHORT	Reserved8			:7;		// 59
+	ULONG	LBATotalSectors;			// 60 LBA Mode - Sectors
+	USHORT	DMASWordFlags;				// 62
+	USHORT	DMAMWordFlags;				// 63
+	USHORT	AdvancedPIOSupport  :8;		// 64 Flow control PIO transfer modes supported
+	USHORT	Reserved9			:8;		// 64
+	USHORT	MinMultiDMACycle;			// 65 minimum multiword DMA transfer cycle time per word
+	USHORT	RecomendDMACycle;			// 66 Manufacturer's recommende multiword DMA transfer cycle time
+	USHORT	MinPIOCycleWithoutFlow;		// 67 Minimum PIO transfer cycle time without flow control
+	USHORT	MinPIOCylceWithFlow;		// 68 Minimum PIO transfer cycle time with IORDY flow control
+	USHORT	ReservedSpace[256-69];		// 69
+	}	IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+// ATAPI configuration bits
+typedef struct _ATAPI_GENERAL_0
+	{
+	USHORT	CmdPacketSize		:2;		// Command packet size
+	USHORT	Reserved1			:3;
+	USHORT	CmdDrqType			:2;
+	USHORT	Removable			:1;
+	USHORT	DeviceType			:5;
+	USHORT	Reserved2			:1;
+	USHORT	ProtocolType		:2;
+	}	ATAPI_GENERAL_0;
+
+#pragma pack ()
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.3.46/linux/drivers/scsi/qlogicfc.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/qlogicfc.c	Thu Feb 17 15:29:50 2000
@@ -64,7 +64,7 @@
 /* Configuration section **************************************************** */
 
 /* Set the following macro to 1 to reload the ISP2x00's firmware.  This is
-   version 1.15.37 of the isp2100's firmware and version 2.00.16 of the 
+   version 1.17.30 of the isp2100's firmware and version 2.00.40 of the 
    isp2200's firmware. 
 */
 
@@ -91,7 +91,7 @@
 /* #define TRACE_ISP             1 */
 
 
-#define DEFAULT_LOOP_COUNT	10000000
+#define DEFAULT_LOOP_COUNT	1000000000
 
 /* End Configuration section ************************************************ */
 
@@ -632,6 +632,17 @@
 #define QLOGICFC_MAX_LUN	128
 #define QLOGICFC_MAX_LOOP_ID	0x7d
 
+/* the following connection options only apply to the 2200.  i have only
+ * had success with LOOP_ONLY and P2P_ONLY.
+ */
+
+#define LOOP_ONLY              0
+#define P2P_ONLY               1
+#define LOOP_PREFERED          2
+#define P2P_PREFERED           3
+
+#define CONNECTION_PREFERENCE  LOOP_ONLY
+
 /* adapter_state values */
 #define AS_FIRMWARE_DEAD      -1
 #define AS_LOOP_DOWN           0
@@ -762,7 +773,7 @@
 			hostdata->queued = 0;
 			/* set up the control block */
 			hostdata->control_block.version = 0x1;
-			hostdata->control_block.firm_opts = 0x000e;
+			hostdata->control_block.firm_opts = 0x800e;
 			hostdata->control_block.max_frame_len = 2048;
 			hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN;
 			hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN;
@@ -780,6 +791,8 @@
 			hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req);
 			hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req);
 
+
+			hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4;
 			hostdata->adapter_state = AS_LOOP_DOWN;
 			hostdata->explore_timer.data = 1;
 			hostdata->host_id = hosts;
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.3.46/linux/drivers/scsi/qlogicisp.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/scsi/qlogicisp.c	Fri Feb 18 15:07:20 2000
@@ -810,8 +810,8 @@
 		sg = (struct scatterlist *) Cmnd->request_buffer;
 		ds = cmd->dataseg;
 
-		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg);
-		Cmnd->use_sg = sg_count;
+		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg,
+				      scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 
 		cmd->segment_cnt = cpu_to_le16(sg_count);
 
@@ -853,17 +853,22 @@
 			}
 			sg_count -= n;
 		}
-	} else {
+	} else if (Cmnd->request_bufflen) {
 		Cmnd->SCp.ptr = (char *)(unsigned long)
 			pci_map_single(hostdata->pci_dev,
 				       Cmnd->request_buffer,
-				       Cmnd->request_bufflen);
+				       Cmnd->request_bufflen,
+				       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 
 		cmd->dataseg[0].d_base =
 			cpu_to_le32((u32)(long)Cmnd->SCp.ptr);
 		cmd->dataseg[0].d_count =
 			cpu_to_le32((u32)Cmnd->request_bufflen);
 		cmd->segment_cnt = cpu_to_le16(1);
+	} else {
+		cmd->dataseg[0].d_base = 0;
+		cmd->dataseg[0].d_count = 0;
+		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
 	}
 
 	/* Committed, record Scsi_Cmd so we can find it later. */
@@ -974,11 +979,13 @@
 		if (Cmnd->use_sg)
 			pci_unmap_sg(hostdata->pci_dev,
 				     (struct scatterlist *)Cmnd->buffer,
-				     Cmnd->use_sg);
-		else
+				     Cmnd->use_sg,
+				     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		else if (Cmnd->request_bufflen)
 			pci_unmap_single(hostdata->pci_dev,
 					 (u32)((long)Cmnd->SCp.ptr),
-					 Cmnd->request_bufflen);
+					 Cmnd->request_bufflen,
+					 scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 
 		isp_outw(out_ptr, host, MBOX5);
 		(*Cmnd->scsi_done)(Cmnd);
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.3.46/linux/drivers/scsi/qlogicpti.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/qlogicpti.c	Fri Feb 18 15:07:20 2000
@@ -1036,7 +1036,7 @@
 		int sg_count;
 
 		sg = (struct scatterlist *) Cmnd->buffer;
-		sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg);
+		sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
 
 		ds = cmd->dataseg;
 		cmd->segment_cnt = sg_count;
@@ -1078,7 +1078,8 @@
 		Cmnd->SCp.ptr = (char *)(unsigned long)
 			sbus_map_single(qpti->sdev,
 					Cmnd->request_buffer,
-					Cmnd->request_bufflen);
+					Cmnd->request_bufflen,
+					scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
 
 		cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
 		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
@@ -1413,11 +1414,13 @@
 		if (Cmnd->use_sg) {
 			sbus_unmap_sg(qpti->sdev,
 				      (struct scatterlist *)Cmnd->buffer,
-				      Cmnd->use_sg);
+				      Cmnd->use_sg,
+				      scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
 		} else {
 			sbus_unmap_single(qpti->sdev,
 					  (__u32)((unsigned long)Cmnd->SCp.ptr),
-					  Cmnd->request_bufflen);
+					  Cmnd->request_bufflen,
+					  scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
 		}
 		qpti->cmd_count[Cmnd->target]--;
 		sbus_writew(out_ptr, qpti->qregs + MBOX5);
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.3.46/linux/drivers/scsi/scsi.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/scsi.c	Fri Feb 18 15:07:20 2000
@@ -224,6 +224,8 @@
 {
 	DECLARE_MUTEX_LOCKED(sem);
 	
+        if (buffer != NULL && SCpnt->sc_data_direction == SCSI_DATA_NONE)
+                BUG();
 	SCpnt->request.sem = &sem;
 	SCpnt->request.rq_status = RQ_SCSI_BUSY;
 	scsi_do_cmd (SCpnt, (void *) cmnd,
@@ -248,6 +250,73 @@
 static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED;
 
 /*
+ * Function:    scsi_allocate_request
+ *
+ * Purpose:     Allocate a request descriptor.
+ *
+ * Arguments:   device    - device for which we want a request
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Pointer to request block.
+ *
+ * Notes:       With the new queueing code, it becomes important
+ *              to track the difference between a command and a
+ *              request.  A request is a pending item in the queue that
+ *              has not yet reached the top of the queue.
+ */
+
+Scsi_Request *scsi_allocate_request(Scsi_Device * device)
+{
+  	Scsi_Request *SRpnt = NULL;
+  
+  	if (!device)
+  		panic("No device passed to scsi_allocate_request().\n");
+  
+	SRpnt = (Scsi_Request *) kmalloc(sizeof(Scsi_Request), GFP_ATOMIC);
+	if( SRpnt == NULL )
+	{
+		return NULL;
+	}
+
+	memset(SRpnt, 0, sizeof(Scsi_Request));
+	SRpnt->sr_device = device;
+	SRpnt->sr_host = device->host;
+	SRpnt->sr_magic = SCSI_REQ_MAGIC;
+	SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
+
+	return SRpnt;
+}
+
+/*
+ * Function:    scsi_release_request
+ *
+ * Purpose:     Release a request descriptor.
+ *
+ * Arguments:   device    - device for which we want a request
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Pointer to request block.
+ *
+ * Notes:       With the new queueing code, it becomes important
+ *              to track the difference between a command and a
+ *              request.  A request is a pending item in the queue that
+ *              has not yet reached the top of the queue.  We still need
+ *              to free a request when we are done with it, of course.
+ */
+void scsi_release_request(Scsi_Request * req)
+{
+	if( req->sr_command != NULL )
+	{
+		scsi_release_command(req->sr_command);
+		req->sr_command = NULL;
+	}
+
+	kfree(req);
+}
+
+/*
  * Function:    scsi_allocate_device
  *
  * Purpose:     Allocate a command descriptor.
@@ -269,6 +338,9 @@
  *              command block, this function will interrupt and return
  *              NULL in the event that a signal arrives that needs to
  *              be handled.
+ *
+ *              This function is deprecated, and drivers should be
+ *              rewritten to use Scsi_Request instead of Scsi_Cmnd.
  */
 
 Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, 
@@ -417,6 +489,10 @@
 	SCpnt->transfersize = 0;	/* No default transfer size */
 	SCpnt->cmd_len = 0;
 
+	SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN;
+	SCpnt->sc_request = NULL;
+	SCpnt->sc_magic = SCSI_CMND_MAGIC;
+
         SCpnt->result = 0;
 	SCpnt->underflow = 0;	/* Do not flag underflow conditions */
 	SCpnt->resid = 0;
@@ -451,6 +527,9 @@
  *              gets hidden in this function.  Upper level drivers don't
  *              have any chickens to wave in the air to get things to
  *              work reliably.
+ *
+ *              This function is deprecated, and drivers should be
+ *              rewritten to use Scsi_Request instead of Scsi_Cmnd.
  */
 void scsi_release_command(Scsi_Cmnd * SCpnt)
 {
@@ -645,6 +724,215 @@
  * drivers go for the same host at the same time.
  */
 
+void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd ,
+ 		  void *buffer, unsigned bufflen, 
+ 		  int timeout, int retries)
+{
+	DECLARE_MUTEX_LOCKED(sem);
+	
+	SRpnt->sr_request.sem = &sem;
+	SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
+	scsi_do_req (SRpnt, (void *) cmnd,
+		buffer, bufflen, scsi_wait_done, timeout, retries);
+	down (&sem);
+	SRpnt->sr_request.sem = NULL;
+	if( SRpnt->sr_command != NULL )
+	{
+		scsi_release_command(SRpnt->sr_command);
+		SRpnt->sr_command = NULL;
+	}
+
+}
+ 
+/*
+ * Function:    scsi_do_req
+ *
+ * Purpose:     Queue a SCSI request
+ *
+ * Arguments:   SRpnt     - command descriptor.
+ *              cmnd      - actual SCSI command to be performed.
+ *              buffer    - data buffer.
+ *              bufflen   - size of data buffer.
+ *              done      - completion function to be run.
+ *              timeout   - how long to let it run before timeout.
+ *              retries   - number of retries we allow.
+ *
+ * Lock status: With the new queueing code, this is SMP-safe, and no locks
+ *              need be held upon entry.   The old queueing code the lock was
+ *              assumed to be held upon entry.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:       Prior to the new queue code, this function was not SMP-safe.
+ *              Also, this function is now only used for queueing requests
+ *              for things like ioctls and character device requests - this
+ *              is because we essentially just inject a request into the
+ *              queue for the device. Normal block device handling manipulates
+ *              the queue directly.
+ */
+void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd,
+	      void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *),
+		 int timeout, int retries)
+{
+	Scsi_Device * SDpnt = SRpnt->sr_device;
+	struct Scsi_Host *host = SDpnt->host;
+
+	ASSERT_LOCK(&io_request_lock, 0);
+
+	SCSI_LOG_MLQUEUE(4,
+			 {
+			 int i;
+			 int target = SDpnt->id;
+			 printk("scsi_do_req (host = %d, channel = %d target = %d, "
+		    "buffer =%p, bufflen = %d, done = %p, timeout = %d, "
+				"retries = %d)\n"
+				"command : ", host->host_no, SDpnt->channel, target, buffer,
+				bufflen, done, timeout, retries);
+			 for (i = 0; i < 10; ++i)
+			 printk("%02x  ", ((unsigned char *) cmnd)[i]);
+			 printk("\n");
+			 });
+
+	if (!host) {
+		panic("Invalid or not present host.\n");
+	}
+
+	/*
+	 * If the upper level driver is reusing these things, then
+	 * we should release the low-level block now.  Another one will
+	 * be allocated later when this request is getting queued.
+	 */
+	if( SRpnt->sr_command != NULL )
+	{
+		scsi_release_command(SRpnt->sr_command);
+		SRpnt->sr_command = NULL;
+	}
+
+	/*
+	 * We must prevent reentrancy to the lowlevel host driver.  This prevents
+	 * it - we enter a loop until the host we want to talk to is not busy.
+	 * Race conditions are prevented, as interrupts are disabled in between the
+	 * time we check for the host being not busy, and the time we mark it busy
+	 * ourselves.
+	 */
+
+
+	/*
+	 * Our own function scsi_done (which marks the host as not busy, disables
+	 * the timeout counter, etc) will be called by us or by the
+	 * scsi_hosts[host].queuecommand() function needs to also call
+	 * the completion function for the high level driver.
+	 */
+
+	memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd, 
+	       sizeof(SRpnt->sr_cmnd));
+	SRpnt->sr_bufflen = bufflen;
+	SRpnt->sr_buffer = buffer;
+	SRpnt->sr_allowed = retries;
+	SRpnt->sr_done = done;
+	SRpnt->sr_timeout_per_command = timeout;
+
+	memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd, 
+	       sizeof(SRpnt->sr_cmnd));
+
+	if (SRpnt->sr_cmd_len == 0)
+		SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]);
+
+	/*
+	 * At this point, we merely set up the command, stick it in the normal
+	 * request queue, and return.  Eventually that request will come to the
+	 * top of the list, and will be dispatched.
+	 */
+	scsi_insert_special_req(SRpnt, 0);
+
+	SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
+}
+ 
+/*
+ * Function:    scsi_init_cmd_from_req
+ *
+ * Purpose:     Queue a SCSI command
+ * Purpose:     Initialize a Scsi_Cmnd from a Scsi_Request
+ *
+ * Arguments:   SCpnt     - command descriptor.
+ *              SRpnt     - Request from the queue.
+ *
+ * Lock status: None needed.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:       Mainly transfer data from the request structure to the
+ *              command structure.  The request structure is allocated
+ *              using the normal memory allocator, and requests can pile
+ *              up to more or less any depth.  The command structure represents
+ *              a consumable resource, as these are allocated into a pool
+ *              when the SCSI subsystem initializes.  The preallocation is
+ *              required so that in low-memory situations a disk I/O request
+ *              won't cause the memory manager to try and write out a page.
+ *              The request structure is generally used by ioctls and character
+ *              devices.
+ */
+void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt)
+{
+	struct Scsi_Host *host = SCpnt->host;
+
+	ASSERT_LOCK(&io_request_lock, 0);
+
+	SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+	SRpnt->sr_command = SCpnt;
+
+	if (!host) {
+		panic("Invalid or not present host.\n");
+	}
+
+	SCpnt->cmd_len = SRpnt->sr_cmd_len;
+	SCpnt->use_sg = SRpnt->sr_use_sg;
+
+	memcpy((void *) &SCpnt->request, (const void *) &SRpnt->sr_request,
+	       sizeof(SRpnt->sr_request));
+	memcpy((void *) SCpnt->data_cmnd, (const void *) SRpnt->sr_cmnd, 
+	       sizeof(SCpnt->data_cmnd));
+	SCpnt->reset_chain = NULL;
+	SCpnt->serial_number = 0;
+	SCpnt->serial_number_at_timeout = 0;
+	SCpnt->bufflen = SRpnt->sr_bufflen;
+	SCpnt->buffer = SRpnt->sr_buffer;
+	SCpnt->flags = 0;
+	SCpnt->retries = 0;
+	SCpnt->allowed = SRpnt->sr_allowed;
+	SCpnt->done = SRpnt->sr_done;
+	SCpnt->timeout_per_command = SRpnt->sr_timeout_per_command;
+
+	SCpnt->sc_data_direction = SRpnt->sr_data_direction;
+
+	SCpnt->sglist_len = SRpnt->sr_sglist_len;
+	SCpnt->underflow = SRpnt->sr_underflow;
+
+	SCpnt->sc_request = SRpnt;
+
+	memcpy((void *) SCpnt->cmnd, (const void *) SRpnt->sr_cmnd, 
+	       sizeof(SCpnt->cmnd));
+	/* Zero the sense buffer.  Some host adapters automatically request
+	 * sense on error.  0 is not a valid sense code.
+	 */
+	memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+	SCpnt->request_buffer = SRpnt->sr_buffer;
+	SCpnt->request_bufflen = SRpnt->sr_bufflen;
+	SCpnt->old_use_sg = SCpnt->use_sg;
+	if (SCpnt->cmd_len == 0)
+		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	SCpnt->old_cmd_len = SCpnt->cmd_len;
+	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
+
+	/* Start the timer ticking.  */
+
+	SCpnt->internal_timeout = NORMAL_TIMEOUT;
+	SCpnt->abort_reason = 0;
+	SCpnt->result = 0;
+
+	SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
+}
+
 /*
  * Function:    scsi_do_cmd
  *
@@ -739,6 +1027,7 @@
 	if (SCpnt->cmd_len == 0)
 		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	SCpnt->old_cmd_len = SCpnt->cmd_len;
+	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
 
 	/* Start the timer ticking.  */
 
@@ -998,6 +1287,7 @@
 	SCpnt->request_bufflen = SCpnt->bufflen;
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
+	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
 
         /*
          * Zero the sense information from the last time we tried
@@ -1019,6 +1309,7 @@
 {
 	struct Scsi_Host *host;
 	Scsi_Device *device;
+	Scsi_Request * SRpnt;
 	unsigned long flags;
 
 	ASSERT_LOCK(&io_request_lock, 0);
@@ -1063,6 +1354,20 @@
 	/* We can get here with use_sg=0, causing a panic in the upper level (DB) */
 	SCpnt->use_sg = SCpnt->old_use_sg;
 
+       /*
+	* If there is an associated request structure, copy the data over before we call the
+	* completion function.
+	*/
+	SRpnt = SCpnt->sc_request;
+	if( SRpnt != NULL ) {
+	       SRpnt->sr_result = SRpnt->sr_command->result;
+	       if( SRpnt->sr_result != 0 ) {
+		       memcpy(SRpnt->sr_sense_buffer,
+			      SRpnt->sr_command->sense_buffer,
+			      sizeof(SRpnt->sr_sense_buffer));
+	       }
+	}
+
 	SCpnt->done(SCpnt);
 }
 
@@ -1098,6 +1403,7 @@
 		kfree((char *) SCpnt);
 	}
 	SDpnt->has_cmdblocks = 0;
+	SDpnt->queue_depth = 0;
 	spin_unlock_irqrestore(&device_request_lock, flags);
 }
 
@@ -2187,11 +2493,12 @@
 	printk("Dump of scsi host parameters:\n");
 	i = 0;
 	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
-		printk(" %d %d %d : %d\n",
+		printk(" %d %d %d : %d %d\n",
 		       shpnt->host_failed,
 		       shpnt->host_busy,
 		       atomic_read(&shpnt->host_active),
-		       shpnt->host_blocked);
+		       shpnt->host_blocked,
+		       shpnt->host_self_blocked);
 
 	}
 
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.3.46/linux/drivers/scsi/scsi.h	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/scsi.h	Sun Feb 20 20:49:29 2000
@@ -32,6 +32,54 @@
 #include <asm/io.h>
 
 /*
+ * These are the values that the SCpnt->sc_data_direction and 
+ * SRpnt->sr_data_direction can take.  These need to be set
+ * The SCSI_DATA_UNKNOWN value is essentially the default.
+ * In the event that the command creator didn't bother to
+ * set a value, you will see SCSI_DATA_UNKNOWN.
+ */
+#define SCSI_DATA_UNKNOWN       0
+#define SCSI_DATA_WRITE         1
+#define SCSI_DATA_READ          2
+#define SCSI_DATA_NONE          3
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE))
+#define scsi_to_pci_dma_dir(scsi_dir)	((int)(scsi_dir))
+#else
+extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir)
+{
+        if (scsi_dir == SCSI_DATA_UNKNOWN)
+                return PCI_DMA_BIDIRECTIONAL;
+        if (scsi_dir == SCSI_DATA_WRITE)
+                return PCI_DMA_TODEVICE;
+        if (scsi_dir == SCSI_DATA_READ)
+                return PCI_DMA_FROMDEVICE;
+        return PCI_DMA_NONE;
+}
+#endif
+#endif
+
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE))
+#define scsi_to_sbus_dma_dir(scsi_dir)	((int)(scsi_dir))
+#else
+extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir)
+{
+        if (scsi_dir == SCSI_DATA_UNKNOWN)
+                return SBUS_DMA_BIDIRECTIONAL;
+        if (scsi_dir == SCSI_DATA_WRITE)
+                return SBUS_DMA_TODEVICE;
+        if (scsi_dir == SCSI_DATA_READ)
+                return SBUS_DMA_FROMDEVICE;
+        return SBUS_DMA_NONE;
+}
+#endif
+#endif
+
+/*
  * Some defs, in case these are not defined elsewhere.
  */
 #ifndef TRUE
@@ -304,6 +352,7 @@
 #define SUGGEST_MASK        0xf0
 
 #define MAX_COMMAND_SIZE    12
+#define SCSI_SENSE_BUFFERSIZE   64
 
 /*
  *  SCSI command sets
@@ -357,6 +406,10 @@
  */
 typedef struct scsi_device Scsi_Device;
 typedef struct scsi_cmnd Scsi_Cmnd;
+typedef struct scsi_request Scsi_Request;
+
+#define SCSI_CMND_MAGIC 0xE25C23A5
+#define SCSI_REQ_MAGIC  0x75F6D354
 
 /*
  * Here is where we prototype most of the mid-layer.
@@ -445,10 +498,25 @@
 			void (*done) (struct scsi_cmnd *),
 			int timeout, int retries);
 extern void scsi_wait_cmd(Scsi_Cmnd *, const void *cmnd,
+  			  void *buffer, unsigned bufflen,
+  			  int timeout, int retries);
+extern int scsi_dev_init(void);
+
+/*
+ * Newer request-based interfaces.
+ */
+extern Scsi_Request *scsi_allocate_request(Scsi_Device *);
+extern void scsi_release_request(Scsi_Request *);
+extern void scsi_wait_req(Scsi_Request *, const void *cmnd,
 			  void *buffer, unsigned bufflen,
 			  int timeout, int retries);
-extern int scsi_dev_init(void);
 
+extern void scsi_do_req(Scsi_Request *, const void *cmnd,
+			void *buffer, unsigned bufflen,
+			void (*done) (struct scsi_cmnd *),
+			int timeout, int retries);
+extern int scsi_insert_special_req(Scsi_Request * SRpnt, int);
+extern void scsi_init_cmd_from_req(Scsi_Cmnd *, Scsi_Request *);
 
 
 /*
@@ -467,6 +535,7 @@
  */
 extern void print_command(unsigned char *);
 extern void print_sense(const char *, Scsi_Cmnd *);
+extern void print_req_sense(const char *, Scsi_Request *);
 extern void print_driverbyte(int scsiresult);
 extern void print_hostbyte(int scsiresult);
 extern void print_status (int status);
@@ -570,6 +639,39 @@
 	volatile int phase;
 } Scsi_Pointer;
 
+/*
+ * This is essentially a slimmed down version of Scsi_Cmnd.  The point of
+ * having this is that requests that are injected into the queue as result
+ * of things like ioctls and character devices shouldn't be using a
+ * Scsi_Cmnd until such a time that the command is actually at the head
+ * of the queue and being sent to the driver.
+ */
+struct scsi_request {
+	int     sr_magic;
+	int     sr_result;	/* Status code from lower level driver */
+	unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE];		/* obtained by REQUEST SENSE
+						 * when CHECK CONDITION is
+						 * received on original command 
+						 * (auto-sense) */
+
+	struct Scsi_Host *sr_host;
+	Scsi_Device *sr_device;
+	Scsi_Cmnd *sr_command;
+	struct request sr_request;	/* A copy of the command we are
+				   working on */
+	unsigned sr_bufflen;	/* Size of data buffer */
+	void *sr_buffer;		/* Data buffer */
+	int sr_allowed;
+	unsigned char sr_data_direction;
+	unsigned char sr_cmd_len;
+	unsigned char sr_cmnd[MAX_COMMAND_SIZE];
+	void (*sr_done) (struct scsi_cmnd *);	/* Mid-level done function */
+	int sr_timeout_per_command;
+	unsigned short sr_use_sg;	/* Number of pieces of scatter-gather */
+	unsigned short sr_sglist_len;	/* size of malloc'd scatter-gather list */
+	unsigned sr_underflow;	/* Return error if less than
+				   this amount is transfered */
+};
 
 /*
  * FIXME(eric) - one of the great regrets that I have is that I failed to define
@@ -580,6 +682,7 @@
  * go back and retrofit at least some of the elements here with with the prefix.
  */
 struct scsi_cmnd {
+	int     sc_magic;
 /* private: */
 	/*
 	 * This information is private to the scsi mid-layer.  Wrapping it in a
@@ -589,6 +692,7 @@
 	unsigned short state;
 	unsigned short owner;
 	Scsi_Device *device;
+	Scsi_Request *sc_request;
 	struct scsi_cmnd *next;
 	struct scsi_cmnd *reset_chain;
 
@@ -632,6 +736,8 @@
 	unsigned char channel;
 	unsigned char cmd_len;
 	unsigned char old_cmd_len;
+	unsigned char sc_data_direction;
+	unsigned char sc_old_data_direction;
 
 	/* These elements define the operation we are about to perform */
 	unsigned char cmnd[MAX_COMMAND_SIZE];
@@ -667,7 +773,7 @@
 	struct request request;	/* A copy of the command we are
 				   working on */
 
-	unsigned char sense_buffer[64];		/* obtained by REQUEST SENSE
+	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];		/* obtained by REQUEST SENSE
 						 * when CHECK CONDITION is
 						 * received on original command 
 						 * (auto-sense) */
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.3.46/linux/drivers/scsi/scsi_error.c	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/scsi_error.c	Wed Feb 16 20:21:45 2000
@@ -408,6 +408,7 @@
 	SCpnt->request_bufflen = SCpnt->bufflen;
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
+	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
 
 	scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
 
@@ -464,6 +465,7 @@
 	SCpnt->request_bufflen = 256;
 	SCpnt->use_sg = 0;
 	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	SCpnt->sc_data_direction = SCSI_DATA_READ;
 
 	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
 
@@ -486,6 +488,7 @@
 	SCpnt->request_bufflen = SCpnt->bufflen;
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
+	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
 
 	/*
 	 * Hey, we are done.  Let's look to see what happened.
@@ -531,6 +534,7 @@
 	SCpnt->use_sg = 0;
 	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+	SCpnt->sc_data_direction = SCSI_DATA_NONE;
 
 	/* Last chance to have valid sense data */
 	if (!scsi_sense_valid(SCpnt))
@@ -551,6 +555,7 @@
 	SCpnt->request_bufflen = SCpnt->bufflen;
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
+	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
 
 	/*
 	 * Hey, we are done.  Let's look to see what happened.
@@ -730,6 +735,7 @@
 	 * things.
 	 */
 	SCpnt->use_sg = SCpnt->old_use_sg;
+	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
 	*SClist = SCpnt;
 }
 
@@ -1245,6 +1251,7 @@
 		request_queue_t *q;
 		if ((host->can_queue > 0 && (host->host_busy >= host->can_queue))
 		    || (host->host_blocked)
+		    || (host->host_self_blocked)
 		    || (SDpnt->device_blocked)) {
 			break;
 		}
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.3.46/linux/drivers/scsi/scsi_ioctl.c	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/scsi_ioctl.c	Wed Feb 16 20:21:45 2000
@@ -105,6 +105,7 @@
                 return -EINTR;
         }
 
+	SCpnt->sc_data_direction = SCSI_DATA_NONE;
         scsi_wait_cmd(SCpnt, cmd, NULL, 0, timeout, retries);
 
 	SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
@@ -197,6 +198,7 @@
 	int inlen, outlen, cmdlen;
 	int needed, buf_needed;
 	int timeout, retries, result;
+	int data_direction;
 
 	if (!sic)
 		return -EINVAL;
@@ -232,8 +234,21 @@
 		if (!buf)
 			return -ENOMEM;
 		memset(buf, 0, buf_needed);
-	} else
+		if( inlen == 0 ) {
+			data_direction = SCSI_DATA_WRITE;
+		} else if (outlen == 0 ) {
+			data_direction = SCSI_DATA_READ;
+		} else {
+			/*
+			 * Can this ever happen?
+			 */
+			data_direction = SCSI_DATA_UNKNOWN;
+		}
+
+	} else {
 		buf = NULL;
+		data_direction = SCSI_DATA_NONE;
+	}
 
 	/*
 	 * Obtain the command from the user's address space.
@@ -288,6 +303,7 @@
                 return -EINTR;
         }
 
+	SCpnt->sc_data_direction = data_direction;
         scsi_wait_cmd(SCpnt, cmd, buf, needed, timeout, retries);
 
 	/* 
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- v2.3.46/linux/drivers/scsi/scsi_lib.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/scsi_lib.c	Thu Feb 17 11:39:28 2000
@@ -121,6 +121,74 @@
 }
 
 /*
+ * Function:    scsi_insert_special_req()
+ *
+ * Purpose:     Insert pre-formed request into request queue.
+ *
+ * Arguments:   SRpnt   - request that is ready to be queued.
+ *              at_head - boolean.  True if we should insert at head
+ *                        of queue, false if we should insert at tail.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       This function is called from character device and from
+ *              ioctl types of functions where the caller knows exactly
+ *              what SCSI command needs to be issued.   The idea is that
+ *              we merely inject the command into the queue (at the head
+ *              for now), and then call the queue request function to actually
+ *              process it.
+ */
+int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
+{
+	unsigned long flags;
+	request_queue_t *q;
+
+	ASSERT_LOCK(&io_request_lock, 0);
+
+	/*
+	 * The SCpnt already contains a request structure - we will doctor the
+	 * thing up with the appropriate values and use that in the actual
+	 * request queue.
+	 */
+	q = &SRpnt->sr_device->request_queue;
+	SRpnt->sr_request.cmd = SPECIAL;
+	SRpnt->sr_request.special = (void *) SRpnt;
+
+	/*
+	 * We have the option of inserting the head or the tail of the queue.
+	 * Typically we use the tail for new ioctls and so forth.  We use the
+	 * head of the queue for things like a QUEUE_FULL message from a
+	 * device, or a host that is unable to accept a particular command.
+	 */
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	if (at_head) {
+		list_add(&SRpnt->sr_request.queue, &q->queue_head);
+	} else {
+		/*
+		 * FIXME(eric) - we always insert at the tail of the
+		 * list.  Otherwise ioctl commands would always take
+		 * precedence over normal I/O.  An ioctl on a busy
+		 * disk might be delayed indefinitely because the
+		 * request might not float high enough in the queue
+		 * to be scheduled.
+		 */
+		list_add_tail(&SRpnt->sr_request.queue, &q->queue_head);
+	}
+
+	/*
+	 * Now hit the requeue function for the queue.  If the host is
+	 * already busy, so be it - we have nothing special to do.  If
+	 * the host can queue it, then send it off.  
+	 */
+	q->request_fn(q);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+}
+
+/*
  * Function:    scsi_init_cmd_errh()
  *
  * Purpose:     Initialize SCpnt fields related to error handling.
@@ -160,6 +228,7 @@
 	 */
 	SCpnt->old_use_sg = SCpnt->use_sg;
 	SCpnt->old_cmd_len = SCpnt->cmd_len;
+	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
 	memcpy((void *) SCpnt->data_cmnd,
 	       (const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
 	SCpnt->buffer = SCpnt->request_buffer;
@@ -257,6 +326,7 @@
 			if (((SHpnt->can_queue > 0)
 			     && (SHpnt->host_busy >= SHpnt->can_queue))
 			    || (SHpnt->host_blocked)
+			    || (SHpnt->host_self_blocked)
 			    || (SDpnt->device_blocked)) {
 				break;
 			}
@@ -278,7 +348,8 @@
 		for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
 			request_queue_t *q;
 			if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
-			    || (SHpnt->host_blocked)) {
+			    || (SHpnt->host_blocked) 
+			    || (SHpnt->host_self_blocked)) {
 				break;
 			}
 			if (SDpnt->device_blocked || !SDpnt->starved) {
@@ -759,6 +830,7 @@
 {
 	struct request *req;
 	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	Scsi_Device *SDpnt;
 	struct Scsi_Host *SHpnt;
 	struct Scsi_Device_Template *STpnt;
@@ -789,13 +861,24 @@
 	 */
 	while (1 == 1) {
 		/*
+		 * Check this again - each time we loop through we will have
+		 * released the lock and grabbed it again, so each time
+		 * we need to check to see if the queue is plugged or not.
+		 */
+		if (SHpnt->in_recovery
+		    || q->plugged) {
+			return;
+		}
+
+		/*
 		 * If the device cannot accept another request, then quit.
 		 */
 		if (SDpnt->device_blocked) {
 			break;
 		}
 		if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
-		    || (SHpnt->host_blocked)) {
+		    || (SHpnt->host_blocked) 
+		    || (SHpnt->host_self_blocked)) {
 			/*
 			 * If we are unable to process any commands at all for this
 			 * device, then we consider it to be starved.  What this means
@@ -862,6 +945,14 @@
 		if (req->cmd == SPECIAL) {
 			STpnt = NULL;
 			SCpnt = (Scsi_Cmnd *) req->special;
+			SRpnt = (Scsi_Request *) req->special;
+
+			if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
+				SCpnt = scsi_allocate_device(SRpnt->sr_device, 
+							     FALSE, FALSE);
+				scsi_init_cmd_from_req(SCpnt, SRpnt);
+			}
+
 		} else {
 			STpnt = scsi_get_request_dev(req);
 			if (!STpnt) {
@@ -986,6 +1077,85 @@
 		 * the request queue and try to find another command.
 		 */
 		spin_lock_irq(&io_request_lock);
+	}
+}
+
+/*
+ * Function:    scsi_block_requests()
+ *
+ * Purpose:     Utility function used by low-level drivers to prevent further
+ *		commands from being queued to the device.
+ *
+ * Arguments:   SHpnt       - Host in question
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes:       There is no timer nor any other means by which the requests
+ *		get unblocked other than the low-level driver calling
+ *		scsi_unblock_requests().
+ */
+void scsi_block_requests(struct Scsi_Host * SHpnt)
+{
+	SHpnt->host_self_blocked = TRUE;
+}
+
+/*
+ * Function:    scsi_unblock_requests()
+ *
+ * Purpose:     Utility function used by low-level drivers to allow further
+ *		commands from being queued to the device.
+ *
+ * Arguments:   SHpnt       - Host in question
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes:       There is no timer nor any other means by which the requests
+ *		get unblocked other than the low-level driver calling
+ *		scsi_unblock_requests().
+ *
+ *		This is done as an API function so that changes to the
+ *		internals of the scsi mid-layer won't require wholesale
+ *		changes to drivers that use this feature.
+ */
+void scsi_unblock_requests(struct Scsi_Host * SHpnt)
+{
+	SHpnt->host_self_blocked = FALSE;
+}
+
+
+/*
+ * Function:    scsi_report_bus_reset()
+ *
+ * Purpose:     Utility function used by low-level drivers to report that
+ *		they have observed a bus reset on the bus being handled.
+ *
+ * Arguments:   SHpnt       - Host in question
+ *		channel     - channel on which reset was observed.
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes:       This only needs to be called if the reset is one which
+ *		originates from an unknown location.  Resets originated
+ *		by the mid-level itself don't need to call this, but there
+ *		should be no harm.
+ *
+ *		The main purpose of this is to make sure that a CHECK_CONDITION
+ *		is properly treated.
+ */
+void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel)
+{
+	Scsi_Device *SDloop;
+	for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {
+		if (channel == SDloop->channel) {
+			SDloop->was_reset = 1;
+			SDloop->expecting_cc_ua = 1;
+		}
 	}
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c
--- v2.3.46/linux/drivers/scsi/scsi_obsolete.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/scsi_obsolete.c	Fri Feb 18 15:07:20 2000
@@ -231,6 +231,8 @@
 	SCpnt->use_sg = 0;
 	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	SCpnt->result = 0;
+	SCpnt->sc_data_direction = SCSI_DATA_READ;
+
         /*
          * Ugly, ugly.  The newer interfaces all assume that the lock
          * isn't held.  Mustn't disappoint, or we deadlock the system.
@@ -374,6 +376,7 @@
 	if (SCpnt->flags & WAS_SENSE) {
 		SCpnt->use_sg = SCpnt->old_use_sg;
 		SCpnt->cmd_len = SCpnt->old_cmd_len;
+		SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
 	}
 	switch (host_byte(result)) {
 	case DID_OK:
@@ -633,6 +636,7 @@
 			SCpnt->request_bufflen = SCpnt->bufflen;
 			SCpnt->use_sg = SCpnt->old_use_sg;
 			SCpnt->cmd_len = SCpnt->old_cmd_len;
+			SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
 			SCpnt->result = 0;
                         /*
                          * Ugly, ugly.  The newer interfaces all
@@ -649,6 +653,7 @@
 	}
 
 	if (status == CMD_FINISHED) {
+		Scsi_Request *SRpnt;
 #ifdef DEBUG
 		printk("Calling done function - at address %p\n", SCpnt->done);
 #endif
@@ -658,6 +663,7 @@
 		SCpnt->result = result | ((exit & 0xff) << 24);
 		SCpnt->use_sg = SCpnt->old_use_sg;
 		SCpnt->cmd_len = SCpnt->old_cmd_len;
+		SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
                 /*
                  * The upper layers assume the lock isn't held.  We mustn't
                  * disappoint them.  When the new error handling code is in
@@ -665,6 +671,16 @@
                  * it isn't an issue.
                  */
                 spin_unlock_irq(&io_request_lock);
+		SRpnt = SCpnt->sc_request;
+		if( SRpnt != NULL ) {
+			SRpnt->sr_result = SRpnt->sr_command->result;
+			if( SRpnt->sr_result != 0 ) {
+				memcpy(SRpnt->sr_sense_buffer,
+				       SRpnt->sr_command->sense_buffer,
+				       sizeof(SRpnt->sr_sense_buffer));
+			}
+		}
+
 		SCpnt->done(SCpnt);
                 spin_lock_irq(&io_request_lock);
 	}
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- v2.3.46/linux/drivers/scsi/scsi_scan.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/scsi_scan.c	Fri Feb 18 15:07:20 2000
@@ -502,6 +502,7 @@
 	SCpnt->target = SDpnt->id;
 	SCpnt->lun = SDpnt->lun;
 	SCpnt->channel = SDpnt->channel;
+	SCpnt->sc_data_direction = SCSI_DATA_NONE;
 
 	scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
 	          (void *) NULL,
@@ -539,6 +540,7 @@
 	scsi_cmd[4] = 255;
 	scsi_cmd[5] = 0;
 	SCpnt->cmd_len = 0;
+	SCpnt->sc_data_direction = SCSI_DATA_READ;
 
 	scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
 	          (void *) scsi_result,
@@ -703,6 +705,7 @@
 		scsi_cmd[4] = 0x2a;
 		scsi_cmd[5] = 0;
 		SCpnt->cmd_len = 0;
+		SCpnt->sc_data_direction = SCSI_DATA_READ;
 		scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
 	        	(void *) scsi_result, 0x2a,
 	        	SCSI_TIMEOUT, 3);
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- v2.3.46/linux/drivers/scsi/scsi_syms.c	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/scsi_syms.c	Wed Feb 16 20:21:45 2000
@@ -28,16 +28,11 @@
 
 #include "sd.h"
 #include <scsi/scsicam.h>
+
 /*
  * This source file contains the symbol table used by scsi loadable
  * modules.
  */
-
-extern void print_command(unsigned char *command);
-extern void print_sense(const char *devclass, Scsi_Cmnd * SCpnt);
-
-extern const char *const scsi_device_types[];
-
 EXPORT_SYMBOL(scsi_register_module);
 EXPORT_SYMBOL(scsi_unregister_module);
 EXPORT_SYMBOL(scsi_free);
@@ -53,6 +48,7 @@
 EXPORT_SYMBOL(scsi_ioctl);
 EXPORT_SYMBOL(print_command);
 EXPORT_SYMBOL(print_sense);
+EXPORT_SYMBOL(print_req_sense);
 EXPORT_SYMBOL(print_msg);
 EXPORT_SYMBOL(print_status);
 EXPORT_SYMBOL(scsi_dma_free_sectors);
@@ -66,6 +62,15 @@
 #if defined(CONFIG_SCSI_LOGGING)	/* { */
 EXPORT_SYMBOL(scsi_logging_level);
 #endif
+
+EXPORT_SYMBOL(scsi_allocate_request);
+EXPORT_SYMBOL(scsi_release_request);
+EXPORT_SYMBOL(scsi_wait_req);
+EXPORT_SYMBOL(scsi_do_req);
+
+EXPORT_SYMBOL(scsi_report_bus_reset);
+EXPORT_SYMBOL(scsi_block_requests);
+EXPORT_SYMBOL(scsi_unblock_requests);
 
 EXPORT_SYMBOL(scsi_get_host_dev);
 EXPORT_SYMBOL(scsi_free_host_dev);
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.46/linux/drivers/scsi/sd.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/sd.c	Fri Feb 18 15:07:20 2000
@@ -309,9 +309,11 @@
 			return 0;
 		}
 		SCpnt->cmnd[0] = WRITE_6;
+		SCpnt->sc_data_direction = SCSI_DATA_WRITE;
 		break;
 	case READ:
 		SCpnt->cmnd[0] = READ_6;
+		SCpnt->sc_data_direction = SCSI_DATA_READ;
 		break;
 	default:
 		panic("Unknown sd command %d\n", SCpnt->request.cmd);
@@ -695,6 +697,7 @@
 			SCpnt->cmd_len = 0;
 			SCpnt->sense_buffer[0] = 0;
 			SCpnt->sense_buffer[2] = 0;
+			SCpnt->sc_data_direction = SCSI_DATA_READ;
 
 			scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
 				0/*512*/, SD_TIMEOUT, MAX_RETRIES);
@@ -706,6 +709,22 @@
 				break;
 		}
 
+		/*
+		 * If the drive has indicated to us that it doesn't have
+		 * any media in it, don't bother with any of the rest of
+		 * this crap.
+		 */
+		if( the_result != 0
+		    && ((driver_byte(the_result) & DRIVER_SENSE) != 0)
+		    && SCpnt->sense_buffer[2] == UNIT_ATTENTION
+		    && SCpnt->sense_buffer[12] == 0x3A ) {
+			rscsi_disks[i].capacity = 0x1fffff;
+			sector_size = 512;
+			rscsi_disks[i].device->changed = 1;
+			rscsi_disks[i].ready = 0;
+			break;
+		}
+
 		/* Look for non-removable devices that return NOT_READY.
 		 * Issue command to spin up drive for these cases. */
 		if (the_result && !rscsi_disks[i].device->removable &&
@@ -722,6 +741,7 @@
 				SCpnt->sense_buffer[0] = 0;
 				SCpnt->sense_buffer[2] = 0;
 
+				SCpnt->sc_data_direction = SCSI_DATA_READ;
 				scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
 					    0/*512*/, SD_TIMEOUT, MAX_RETRIES);
 			}
@@ -752,6 +772,7 @@
 		SCpnt->sense_buffer[0] = 0;
 		SCpnt->sense_buffer[2] = 0;
 
+		SCpnt->sc_data_direction = SCSI_DATA_READ;
 		scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
 			    8, SD_TIMEOUT, MAX_RETRIES);
 
@@ -903,6 +924,7 @@
 		SCpnt->sense_buffer[2] = 0;
 
 		/* same code as READCAPA !! */
+		SCpnt->sc_data_direction = SCSI_DATA_READ;
 		scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
 			    512, SD_TIMEOUT, MAX_RETRIES);
 
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.3.46/linux/drivers/scsi/sr.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/sr.c	Wed Feb 16 20:21:45 2000
@@ -89,7 +89,6 @@
 void get_sectorsize(int);
 void get_capabilities(int);
 
-void requeue_sr_request(Scsi_Cmnd * SCpnt);
 static int sr_media_change(struct cdrom_device_info *, int);
 static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
 
@@ -327,9 +326,11 @@
 			return 0;
 		}
 		SCpnt->cmnd[0] = WRITE_10;
+		SCpnt->sc_data_direction = SCSI_DATA_WRITE;
 		break;
 	case READ:
 		SCpnt->cmnd[0] = READ_10;
+		SCpnt->sc_data_direction = SCSI_DATA_READ;
 		break;
 	default:
 		panic("Unknown sr command %d\n", SCpnt->request.cmd);
@@ -464,36 +465,37 @@
 	unsigned char *buffer;
 	int the_result, retries;
 	int sector_size;
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 
 	buffer = (unsigned char *) scsi_malloc(512);
 
 
-	SCpnt = scsi_allocate_device(scsi_CDs[i].device, 1, FALSE);
+	SRpnt = scsi_allocate_request(scsi_CDs[i].device);
 
 	retries = 3;
 	do {
 		cmd[0] = READ_CAPACITY;
 		cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
 		memset((void *) &cmd[2], 0, 8);
-		SCpnt->request.rq_status = RQ_SCSI_BUSY;	/* Mark as really busy */
-		SCpnt->cmd_len = 0;
+		SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;	/* Mark as really busy */
+		SRpnt->sr_cmd_len = 0;
 
 		memset(buffer, 0, 8);
 
 		/* Do the command and wait.. */
 
-		scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
 			      512, SR_TIMEOUT, MAX_RETRIES);
 
-		the_result = SCpnt->result;
+		the_result = SRpnt->sr_result;
 		retries--;
 
 	} while (the_result && retries);
 
 
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 
 	if (the_result) {
 		scsi_CDs[i].capacity = 0x1fffff;
@@ -570,7 +572,7 @@
 	cmd[2] = 0x2a;
 	cmd[4] = 128;
 	cmd[3] = cmd[5] = 0;
-	rc = sr_do_ioctl(i, cmd, buffer, 128, 1);
+	rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ);
 
 	if (-EINVAL == rc) {
 		/* failed, drive has'nt this mode page */
@@ -635,19 +637,19 @@
  */
 static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
 {
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
 	unsigned char *buffer = cgc->buffer;
 	int buflen;
 
 	/* get the device */
-	SCpnt = scsi_allocate_device(device, 1, FALSE);
-	if (SCpnt == NULL)
+	SRpnt = scsi_allocate_request(device);
+	if (SRpnt == NULL)
 		return -ENODEV;	/* this just doesn't seem right /axboe */
 
 	/* use buffer for ISA DMA */
 	buflen = (cgc->buflen + 511) & ~511;
-	if (cgc->buffer && SCpnt->host->unchecked_isa_dma &&
+	if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma &&
 	    (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
 		buffer = scsi_malloc(buflen);
 		if (buffer == NULL) {
@@ -660,20 +662,25 @@
 	cgc->cmd[1] |= device->lun << 5;
 
 	/* do the locking and issue the command */
-	SCpnt->request.rq_dev = cdi->dev;
+	SRpnt->sr_request.rq_dev = cdi->dev;
 	/* scsi_wait_cmd sets the command length */
-	SCpnt->cmd_len = 0;
+	SRpnt->sr_cmd_len = 0;
 
-	scsi_wait_cmd(SCpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
+	/*
+	 * FIXME(eric) - need to set the data direction here.
+	 */
+	SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
+
+	scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
 		      SR_TIMEOUT, MAX_RETRIES);
 
-	if ((cgc->stat = SCpnt->result))
-		cgc->sense = (struct request_sense *) SCpnt->sense_buffer;
+	if ((cgc->stat = SRpnt->sr_result))
+		cgc->sense = (struct request_sense *) SRpnt->sr_sense_buffer;
 
 	/* release */
-	SCpnt->request.rq_dev = MKDEV(0, 0);
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	SRpnt->sr_request.rq_dev = MKDEV(0, 0);
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 
 	/* write DMA buffer back if used */
 	if (buffer && (buffer != cgc->buffer)) {
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v2.3.46/linux/drivers/scsi/sr.h	Tue Dec 14 01:27:24 1999
+++ linux/drivers/scsi/sr.h	Wed Feb 16 20:21:45 2000
@@ -36,7 +36,7 @@
 
 extern Scsi_CD *scsi_CDs;
 
-int sr_do_ioctl(int, unsigned char *, void *, unsigned, int);
+int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int);
 
 int sr_lock_door(struct cdrom_device_info *, int);
 int sr_tray_move(struct cdrom_device_info *, int);
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.3.46/linux/drivers/scsi/sr_ioctl.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/sr_ioctl.c	Wed Feb 16 20:21:45 2000
@@ -34,20 +34,21 @@
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
 
-int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet)
+int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite)
 {
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	Scsi_Device *SDev;
         struct request *req;
 	int result, err = 0, retries = 0;
 	char *bounce_buffer;
 
 	SDev = scsi_CDs[target].device;
-	SCpnt = scsi_allocate_device(scsi_CDs[target].device, 1, FALSE);
+	SRpnt = scsi_allocate_request(scsi_CDs[target].device);
+	SRpnt->sr_data_direction = readwrite;
 
 	/* use ISA DMA buffer if necessary */
-	SCpnt->request.buffer = buffer;
-	if (buffer && SCpnt->host->unchecked_isa_dma &&
+	SRpnt->sr_request.buffer = buffer;
+	if (buffer && SRpnt->sr_host->unchecked_isa_dma &&
 	    (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) {
 		bounce_buffer = (char *) scsi_malloc((buflength + 511) & ~511);
 		if (bounce_buffer == NULL) {
@@ -62,21 +63,21 @@
 		return -ENODEV;
 
 
-	scsi_wait_cmd(SCpnt, (void *) sr_cmd, (void *) buffer, buflength,
+	scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength,
 		      IOCTL_TIMEOUT, IOCTL_RETRIES);
 
-        req = &SCpnt->request;
-        if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) {
-                memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
-                scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511);
-                SCpnt->buffer = req->buffer;
+	req = &SRpnt->sr_request;
+	if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
+		memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen);
+		scsi_free(SRpnt->sr_buffer, (SRpnt->sr_bufflen + 511) & ~511);
+		SRpnt->sr_buffer = req->buffer;
         }
 
-	result = SCpnt->result;
+	result = SRpnt->sr_result;
 
 	/* Minimal error checking.  Ignore cases we know about, and report the rest. */
 	if (driver_byte(result) != 0) {
-		switch (SCpnt->sense_buffer[2] & 0xf) {
+		switch (SRpnt->sr_sense_buffer[2] & 0xf) {
 		case UNIT_ATTENTION:
 			scsi_CDs[target].device->changed = 1;
 			if (!quiet)
@@ -86,8 +87,8 @@
 			err = -ENOMEDIUM;
 			break;
 		case NOT_READY:	/* This happens if there is no disc in drive */
-			if (SCpnt->sense_buffer[12] == 0x04 &&
-			    SCpnt->sense_buffer[13] == 0x01) {
+			if (SRpnt->sr_sense_buffer[12] == 0x04 &&
+			    SRpnt->sr_sense_buffer[13] == 0x01) {
 				/* sense: Logical unit is in process of becoming ready */
 				if (!quiet)
 					printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
@@ -104,7 +105,7 @@
 			if (!quiet)
 				printk(KERN_INFO "sr%d: CDROM not ready.  Make sure there is a disc in the drive.\n", target);
 #ifdef DEBUG
-			print_sense("sr", SCpnt);
+			print_req_sense("sr", SRpnt);
 #endif
 			err = -ENOMEDIUM;
 			break;
@@ -112,8 +113,8 @@
 			if (!quiet)
 				printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
 				       "REQUEST.\n", target);
-			if (SCpnt->sense_buffer[12] == 0x20 &&
-			    SCpnt->sense_buffer[13] == 0x00) {
+			if (SRpnt->sr_sense_buffer[12] == 0x20 &&
+			    SRpnt->sr_sense_buffer[13] == 0x00) {
 				/* sense: Invalid command operation code */
 				err = -EDRIVE_CANT_DO_THIS;
 			} else {
@@ -121,20 +122,20 @@
 			}
 #ifdef DEBUG
 			print_command(sr_cmd);
-			print_sense("sr", SCpnt);
+			print_req_sense("sr", SRpnt);
 #endif
 			break;
 		default:
 			printk(KERN_ERR "sr%d: CDROM (ioctl) error, command: ", target);
 			print_command(sr_cmd);
-			print_sense("sr", SCpnt);
+			print_req_sense("sr", SRpnt);
 			err = -EIO;
 		}
 	}
-	result = SCpnt->result;
+	result = SRpnt->sr_result;
 	/* Wake up a process waiting for device */
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 	return err;
 }
 
@@ -148,7 +149,7 @@
 	sr_cmd[0] = GPCMD_TEST_UNIT_READY;
 	sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1);
+	return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE);
 }
 
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
@@ -160,7 +161,7 @@
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
 
-	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0);
+	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE);
 }
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
@@ -237,7 +238,7 @@
 	sr_cmd[8] = 24;
 	sr_cmd[9] = 0;
 
-	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
+	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ);
 
 	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
 	mcn->medium_catalog_number[13] = 0;
@@ -266,7 +267,7 @@
 	sr_cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
 	sr_cmd[3] = speed & 0xff;	/* LSB */
 
-	if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0))
+	if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE))
 		return -EIO;
 	return 0;
 }
@@ -296,7 +297,7 @@
 			sr_cmd[8] = 12;		/* LSB of length */
 			sr_cmd[9] = 0;
 
-			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
+			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ);
 
 			tochdr->cdth_trk0 = buffer[2];
 			tochdr->cdth_trk1 = buffer[3];
@@ -317,7 +318,7 @@
 			sr_cmd[8] = 12;		/* LSB of length */
 			sr_cmd[9] = 0;
 
-			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
+			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ);
 
 			tocentry->cdte_ctrl = buffer[5] & 0xf;
 			tocentry->cdte_adr = buffer[5] >> 4;
@@ -390,7 +391,7 @@
 		cmd[9] = 0x10;
 		break;
 	}
-	return sr_do_ioctl(minor, cmd, dest, blksize, 0);
+	return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
 }
 
 /*
@@ -428,7 +429,7 @@
 	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
 	cmd[5] = (unsigned char) lba & 0xff;
 	cmd[8] = 1;
-	rc = sr_do_ioctl(minor, cmd, dest, blksize, 0);
+	rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
 
 	return rc;
 }
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.3.46/linux/drivers/scsi/sr_vendor.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/sr_vendor.c	Wed Feb 16 20:21:45 2000
@@ -132,7 +132,7 @@
 	modesel->density = density;
 	modesel->block_length_med = (blocklength >> 8) & 0xff;
 	modesel->block_length_lo = blocklength & 0xff;
-	if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0))) {
+	if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE))) {
 		scsi_CDs[minor].device->sector_size = blocklength;
 	}
 #ifdef DEBUG
@@ -176,7 +176,7 @@
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
 		cmd[8] = 12;
 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
 		if (rc != 0)
 			break;
 		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
@@ -200,7 +200,7 @@
 			cmd[0] = 0xde;
 			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
 			cmd[2] = 0xb0;
-			rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1);
+			rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ);
 			if (rc != 0)
 				break;
 			if (buffer[14] != 0 && buffer[14] != 0xb0) {
@@ -224,7 +224,7 @@
 			memset(cmd, 0, MAX_COMMAND_SIZE);
 			cmd[0] = 0xc7;
 			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
-			rc = sr_do_ioctl(minor, cmd, buffer, 4, 1);
+			rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ);
 			if (rc == -EINVAL) {
 				printk(KERN_INFO "sr%d: Hmm, seems the drive "
 				       "doesn't support multisession CD's\n", minor);
@@ -249,7 +249,7 @@
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
 		cmd[8] = 0x04;
 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1);
+		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ);
 		if (rc != 0) {
 			break;
 		}
@@ -263,7 +263,7 @@
 		cmd[6] = rc & 0x7f;	/* number of last session */
 		cmd[8] = 0x0c;
 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
 		if (rc != 0) {
 			break;
 		}
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.46/linux/drivers/scsi/st.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/st.c	Sun Feb 20 20:20:42 2000
@@ -11,7 +11,7 @@
    Copyright 1992 - 2000 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Fri Feb 11 19:43:57 2000 by makisara@kai.makisara.local
+   Last modified: Sat Feb 19 17:22:34 2000 by makisara@kai.makisara.local
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -169,16 +169,15 @@
 
 
 
-
 /* Convert the result to success code */
-static int st_chk_result(Scsi_Cmnd * SCpnt)
+static int st_chk_result(Scsi_Request * SRpnt)
 {
-	int dev = TAPE_NR(SCpnt->request.rq_dev);
-	int result = SCpnt->result;
-	unsigned char *sense = SCpnt->sense_buffer, scode;
+	int dev = TAPE_NR(SRpnt->sr_request.rq_dev);
+	int result = SRpnt->sr_result;
+	unsigned char *sense = SRpnt->sr_sense_buffer, scode;
 	DEB(const char *stp;)
 
-	if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
+	if (!result)
 		return 0;
 
 	if (driver_byte(result) & DRIVER_SENSE)
@@ -192,11 +191,11 @@
         if (debugging) {
                 printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
 		       dev, result,
-		       SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
-		       SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
-		       SCpnt->request_bufflen);
+		       SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
+		       SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
+		       SRpnt->sr_bufflen);
 		if (driver_byte(result) & DRIVER_SENSE)
-			print_sense("st", SCpnt);
+			print_req_sense("st", SRpnt);
 	} else ) /* end DEB */
 		if (!(driver_byte(result) & DRIVER_SENSE) ||
 		    ((sense[0] & 0x70) == 0x70 &&
@@ -205,11 +204,11 @@
                      /* scode != UNIT_ATTENTION && */
 		     scode != BLANK_CHECK &&
 		     scode != VOLUME_OVERFLOW &&
-		     SCpnt->data_cmnd[0] != MODE_SENSE &&
-		     SCpnt->data_cmnd[0] != TEST_UNIT_READY)) {	/* Abnormal conditions for tape */
+		     SRpnt->sr_cmnd[0] != MODE_SENSE &&
+		     SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) {	/* Abnormal conditions for tape */
 		if (driver_byte(result) & DRIVER_SENSE) {
 			printk(KERN_WARNING "st%d: Error with sense data: ", dev);
-			print_sense("st", SCpnt);
+			print_req_sense("st", SRpnt);
 		} else
 			printk(KERN_WARNING
 			       "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
@@ -220,8 +219,8 @@
 	if ((sense[0] & 0x70) == 0x70 &&
 	    scode == RECOVERED_ERROR
 #if ST_RECOVERED_WRITE_FATAL
-	    && SCpnt->data_cmnd[0] != WRITE_6
-	    && SCpnt->data_cmnd[0] != WRITE_FILEMARKS
+	    && SRpnt->sr_cmnd[0] != WRITE_6
+	    && SRpnt->sr_cmnd[0] != WRITE_FILEMARKS
 #endif
 	    ) {
 		scsi_tapes[dev].recover_count++;
@@ -229,9 +228,9 @@
 
                 DEB(
 		if (debugging) {
-			if (SCpnt->data_cmnd[0] == READ_6)
+			if (SRpnt->sr_cmnd[0] == READ_6)
 				stp = "read";
-			else if (SCpnt->data_cmnd[0] == WRITE_6)
+			else if (SRpnt->sr_cmnd[0] == WRITE_6)
 				stp = "write";
 			else
 				stp = "ioctl";
@@ -268,13 +267,13 @@
 				remainder = 0;
 			if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
 			    remainder > 0)
-				(STp->buffer)->last_result = SCpnt->result;	/* Error */
+				(STp->buffer)->midlevel_result = SCpnt->result; /* Error */
 			else
-				(STp->buffer)->last_result = INT_MAX;	/* OK */
+				(STp->buffer)->midlevel_result = INT_MAX;	/* OK */
 		} else
-			(STp->buffer)->last_result = SCpnt->result;
+			(STp->buffer)->midlevel_result = SCpnt->result;
 		SCpnt->request.rq_status = RQ_SCSI_DONE;
-		(STp->buffer)->last_SCpnt = SCpnt;
+		(STp->buffer)->last_SRpnt = SCpnt->sc_request;
 		DEB( STp->write_pending = 0; )
 
 		up(SCpnt->request.sem);
@@ -289,47 +288,49 @@
 /* Do the scsi command. Waits until command performed if do_wait is true.
    Otherwise write_behind_check() is used to check that the command
    has finished. */
-static Scsi_Cmnd *
- st_do_scsi(Scsi_Cmnd * SCpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
-	    int timeout, int retries, int do_wait)
+static Scsi_Request *
+ st_do_scsi(Scsi_Request * SRpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
+	    int direction, int timeout, int retries, int do_wait)
 {
 	unsigned char *bp;
 
-	if (SCpnt == NULL)
-		SCpnt = scsi_allocate_device(STp->device, 1, TRUE);
-		if (SCpnt == NULL) {
+	if (SRpnt == NULL)
+		SRpnt = scsi_allocate_request(STp->device);
+		if (SRpnt == NULL) {
 			DEBC( printk(KERN_ERR "st%d: Can't get SCSI request.\n",
 				     TAPE_NR(STp->devt)); );
 			if (signal_pending(current))
-				(STp->buffer)->last_result_fatal = (-EINTR);
+				(STp->buffer)->syscall_result = (-EINTR);
 			else
-				(STp->buffer)->last_result_fatal = (-EBUSY);
+				(STp->buffer)->syscall_result = (-EBUSY);
 			return NULL;
 		}
 
-	cmd[1] |= (SCpnt->lun << 5) & 0xe0;
+	cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
 	init_MUTEX_LOCKED(&STp->sem);
-	SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+	SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
 	    (STp->buffer)->use_sg : 0;
-	if (SCpnt->use_sg) {
+	if (SRpnt->sr_use_sg) {
 		bp = (char *) &((STp->buffer)->sg[0]);
-		if ((STp->buffer)->sg_segs < SCpnt->use_sg)
-			SCpnt->use_sg = (STp->buffer)->sg_segs;
+		if ((STp->buffer)->sg_segs < SRpnt->sr_use_sg)
+			SRpnt->sr_use_sg = (STp->buffer)->sg_segs;
 	} else
 		bp = (STp->buffer)->b_data;
-	SCpnt->cmd_len = 0;
-	SCpnt->request.sem = &(STp->sem);
-	SCpnt->request.rq_status = RQ_SCSI_BUSY;
-	SCpnt->request.rq_dev = STp->devt;
+	SRpnt->sr_data_direction = direction;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_request.sem = &(STp->sem);
+	SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
+	SRpnt->sr_request.rq_dev = STp->devt;
 
-	scsi_do_cmd(SCpnt, (void *) cmd, bp, bytes,
+	scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
 		    st_sleep_done, timeout, retries);
 
 	if (do_wait) {
-		down(SCpnt->request.sem);
-		(STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
+		down(SRpnt->sr_request.sem);
+		SRpnt->sr_request.sem = NULL;
+		(STp->buffer)->syscall_result = st_chk_result(SRpnt);
 	}
-	return SCpnt;
+	return SRpnt;
 }
 
 
@@ -349,9 +350,10 @@
         ) /* end DEB */
 
 	down(&(STp->sem));
+	(STp->buffer)->last_SRpnt->sr_request.sem = NULL;
 
-	(STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt);
-	scsi_release_command((STp->buffer)->last_SCpnt);
+	(STp->buffer)->syscall_result = st_chk_result((STp->buffer)->last_SRpnt);
+	scsi_release_request((STp->buffer)->last_SRpnt);
 
 	if (STbuffer->writing < STbuffer->buffer_bytes)
 #if 0
@@ -380,7 +382,7 @@
    it messes up the block number). */
 static int cross_eof(Scsi_Tape * STp, int forward)
 {
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	unsigned char cmd[MAX_COMMAND_SIZE];
 
 	cmd[0] = SPACE;
@@ -395,18 +397,19 @@
         DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",
 		   TAPE_NR(STp->devt), forward ? "forward" : "backward"));
 
-	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
-	if (!SCpnt)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
+			   STp->timeout, MAX_RETRIES, TRUE);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
 
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 
-	if ((STp->buffer)->last_result != 0)
+	if ((STp->buffer)->midlevel_result != 0)
 		printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
 		   TAPE_NR(STp->devt), forward ? "forward" : "backward");
 
-	return (STp->buffer)->last_result_fatal;
+	return (STp->buffer)->syscall_result;
 }
 
 
@@ -416,16 +419,16 @@
 	int offset, transfer, blks;
 	int result;
 	unsigned char cmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	ST_partstat *STps;
 
 	if ((STp->buffer)->writing) {
 		write_behind_check(STp);
-		if ((STp->buffer)->last_result_fatal) {
+		if ((STp->buffer)->syscall_result) {
                         DEBC(printk(ST_DEB_MSG
                                        "st%d: Async write error (flush) %x.\n",
-				       TAPE_NR(STp->devt), (STp->buffer)->last_result))
-			if ((STp->buffer)->last_result == INT_MAX)
+				       TAPE_NR(STp->devt), (STp->buffer)->midlevel_result))
+			if ((STp->buffer)->midlevel_result == INT_MAX)
 				return (-ENOSPC);
 			return (-EIO);
 		}
@@ -452,16 +455,16 @@
 		cmd[3] = blks >> 8;
 		cmd[4] = blks;
 
-		SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout,
-                                   MAX_WRITE_RETRIES, TRUE);
-		if (!SCpnt)
-			return (STp->buffer)->last_result_fatal;
+		SRpnt = st_do_scsi(NULL, STp, cmd, transfer, SCSI_DATA_WRITE,
+				   STp->timeout, MAX_WRITE_RETRIES, TRUE);
+		if (!SRpnt)
+			return (STp->buffer)->syscall_result;
 
 		STps = &(STp->ps[STp->partition]);
-		if ((STp->buffer)->last_result_fatal != 0) {
-			if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-			    (SCpnt->sense_buffer[2] & 0x40) &&
-			    (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) {
+		if ((STp->buffer)->syscall_result != 0) {
+			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+			    (SRpnt->sr_sense_buffer[2] & 0x40) &&
+			    (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
 				STp->dirty = 0;
 				(STp->buffer)->buffer_bytes = 0;
 				result = (-ENOSPC);
@@ -477,8 +480,8 @@
 			STp->dirty = 0;
 			(STp->buffer)->buffer_bytes = 0;
 		}
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 	}
 	return result;
 }
@@ -585,7 +588,7 @@
 	int i, need_dma_buffer, new_session = FALSE;
 	int retval;
 	unsigned char cmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	Scsi_Tape *STp;
 	ST_mode *STm;
 	ST_partstat *STps;
@@ -636,7 +639,7 @@
 		STp->buffer = st_buffers[i];
 	(STp->buffer)->in_use = 1;
 	(STp->buffer)->writing = 0;
-	(STp->buffer)->last_result_fatal = 0;
+	(STp->buffer)->syscall_result = 0;
 	(STp->buffer)->use_sg = STp->device->host->sg_tablesize;
 
 	/* Compute the usable buffer size for this SCSI adapter */
@@ -663,24 +666,24 @@
 	memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
 	cmd[0] = TEST_UNIT_READY;
 
-	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
-			   TRUE);
-	if (!SCpnt) {
-		retval = (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
+			   MAX_READY_RETRIES, TRUE);
+	if (!SRpnt) {
+		retval = (STp->buffer)->syscall_result;
 		goto err_out;
 	}
 
-	if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-	    (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {	/* New media? */
+	if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+	    (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {	/* New media? */
 
 		/* Flush the queued UNIT ATTENTION sense data */
 		for (i=0; i < 10; i++) {
                         memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
                         cmd[0] = TEST_UNIT_READY;
-                        SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout,
-                                           MAX_READY_RETRIES, TRUE);
-                        if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
-                            (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
+                        SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+					   STp->long_timeout, MAX_READY_RETRIES, TRUE);
+                        if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+                            (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
                                 break;
 		}
 
@@ -701,16 +704,16 @@
 		new_session = TRUE;
 	}
 
-	if ((STp->buffer)->last_result_fatal != 0) {
+	if ((STp->buffer)->syscall_result != 0) {
 		if ((STp->device)->scsi_level >= SCSI_2 &&
-		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-		    (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
-		    SCpnt->sense_buffer[12] == 0x3a) {	/* Check ASC */
+		    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+		    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
+		    SRpnt->sr_sense_buffer[12] == 0x3a) {	/* Check ASC */
 			STp->ready = ST_NO_TAPE;
 		} else
 			STp->ready = ST_NOT_READY;
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 		STp->density = 0;	/* Clear the erroneous "residue" */
 		STp->write_prot = 0;
 		STp->block_size = 0;
@@ -726,10 +729,10 @@
 		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
 		cmd[0] = READ_BLOCK_LIMITS;
 
-		SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES,
-                                   TRUE);
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
+				   MAX_READY_RETRIES, TRUE);
 
-		if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
+		if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
 			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
 			    ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
 			STp->min_block = ((STp->buffer)->b_data[4] << 8) |
@@ -749,12 +752,13 @@
 	cmd[0] = MODE_SENSE;
 	cmd[4] = 12;
 
-	SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE);
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
+			   MAX_READY_RETRIES, TRUE);
 
-	if ((STp->buffer)->last_result_fatal != 0) {
+	if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
 		STp->block_size = ST_DEFAULT_BLOCK;	/* Educated guess (?) */
-		(STp->buffer)->last_result_fatal = 0;	/* Prevent error propagation */
+		(STp->buffer)->syscall_result = 0;	/* Prevent error propagation */
 		STp->drv_write_prot = 0;
 	} else {
                 DEBC(printk(ST_DEB_MSG
@@ -779,14 +783,14 @@
 		    !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
 			printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n",
                                dev, STp->block_size);
-			scsi_release_command(SCpnt);
+			scsi_release_request(SRpnt);
 			retval = (-EIO);
 			goto err_out;
 		}
 		STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
 	}
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
         STp->inited = TRUE;
 
 	if (STp->block_size > 0)
@@ -863,7 +867,7 @@
 {
 	int result = 0, result2;
 	static unsigned char cmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	Scsi_Tape *STp;
 	ST_mode *STm;
 	ST_partstat *STps;
@@ -907,29 +911,29 @@
 		cmd[0] = WRITE_FILEMARKS;
 		cmd[4] = 1 + STp->two_fm;
 
-		SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout,
-				   MAX_WRITE_RETRIES, TRUE);
-		if (!SCpnt) {
-			result = (STp->buffer)->last_result_fatal;
+		SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
+				   STp->timeout, MAX_WRITE_RETRIES, TRUE);
+		if (!SRpnt) {
+			result = (STp->buffer)->syscall_result;
 			goto out;
 		}
 
-		if ((STp->buffer)->last_result_fatal != 0 &&
-		    ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
-		     (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
-		     ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
-		      (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
-		       SCpnt->sense_buffer[5] |
-		       SCpnt->sense_buffer[6]) == 0))) {
+		if ((STp->buffer)->syscall_result != 0 &&
+		    ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+		     (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 ||
+		     ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
+		      (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
+		       SRpnt->sr_sense_buffer[5] |
+		       SRpnt->sr_sense_buffer[6]) == 0))) {
 			/* Filter out successful write at EOM */
-			scsi_release_command(SCpnt);
-			SCpnt = NULL;
+			scsi_release_request(SRpnt);
+			SRpnt = NULL;
 			printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
 			if (result == 0)
 				result = (-EIO);
 		} else {
-			scsi_release_command(SCpnt);
-			SCpnt = NULL;
+			scsi_release_request(SRpnt);
+			SRpnt = NULL;
 			if (STps->drv_file >= 0)
 				STps->drv_file++;
 			STps->drv_block = 0;
@@ -1016,7 +1020,7 @@
 	int doing_write = 0;
 	static unsigned char cmd[MAX_COMMAND_SIZE];
 	const char *b_point;
-	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Request *SRpnt = NULL;
 	Scsi_Tape *STp;
 	ST_mode *STm;
 	ST_partstat *STps;
@@ -1111,10 +1115,10 @@
 
 	if ((STp->buffer)->writing) {
 		write_behind_check(STp);
-		if ((STp->buffer)->last_result_fatal) {
+		if ((STp->buffer)->syscall_result) {
                         DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n",
-                                    dev, (STp->buffer)->last_result));
-			if ((STp->buffer)->last_result == INT_MAX)
+                                    dev, (STp->buffer)->midlevel_result));
+			if ((STp->buffer)->midlevel_result == INT_MAX)
 				STps->eof = ST_EOM_OK;
 			else
 				STps->eof = ST_EOM_ERROR;
@@ -1168,9 +1172,9 @@
 
 		i = append_to_buffer(b_point, STp->buffer, do_count);
 		if (i) {
-			if (SCpnt != NULL) {
-				scsi_release_command(SCpnt);
-				SCpnt = NULL;
+			if (SRpnt != NULL) {
+				scsi_release_request(SRpnt);
+				SRpnt = NULL;
 			}
 			return i;
 		}
@@ -1186,23 +1190,23 @@
 		cmd[3] = blks >> 8;
 		cmd[4] = blks;
 
-		SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout,
-				   MAX_WRITE_RETRIES, TRUE);
-		if (!SCpnt)
-			return (STp->buffer)->last_result_fatal;
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
+				   STp->timeout, MAX_WRITE_RETRIES, TRUE);
+		if (!SRpnt)
+			return (STp->buffer)->syscall_result;
 
-		if ((STp->buffer)->last_result_fatal != 0) {
+		if ((STp->buffer)->syscall_result != 0) {
                         DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev));
-			if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-			    (SCpnt->sense_buffer[2] & 0x40)) {
+			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+			    (SRpnt->sr_sense_buffer[2] & 0x40)) {
 				if (STp->block_size != 0 &&
-                                    (SCpnt->sense_buffer[0] & 0x80) != 0)
-					transfer = (SCpnt->sense_buffer[3] << 24) |
-					    (SCpnt->sense_buffer[4] << 16) |
-					    (SCpnt->sense_buffer[5] << 8) |
-                                                SCpnt->sense_buffer[6];
+                                    (SRpnt->sr_sense_buffer[0] & 0x80) != 0)
+					transfer = (SRpnt->sr_sense_buffer[3] << 24) |
+					    (SRpnt->sr_sense_buffer[4] << 16) |
+					    (SRpnt->sr_sense_buffer[5] << 8) |
+                                                SRpnt->sr_sense_buffer[6];
 				else if (STp->block_size == 0 &&
-					 (SCpnt->sense_buffer[2] & 0x0f) ==
+					 (SRpnt->sr_sense_buffer[2] & 0x0f) ==
                                          VOLUME_OVERFLOW)
 					transfer = do_count;
 				else
@@ -1239,8 +1243,8 @@
 				retval = (-EIO);
 			}
 
-			scsi_release_command(SCpnt);
-			SCpnt = NULL;
+			scsi_release_request(SRpnt);
+			SRpnt = NULL;
 			(STp->buffer)->buffer_bytes = 0;
 			STp->dirty = 0;
 			if (count < total)
@@ -1264,9 +1268,9 @@
 		STp->dirty = 1;
 		i = append_to_buffer(b_point, STp->buffer, count);
 		if (i) {
-			if (SCpnt != NULL) {
-				scsi_release_command(SCpnt);
-				SCpnt = NULL;
+			if (SRpnt != NULL) {
+				scsi_release_request(SRpnt);
+				SRpnt = NULL;
 			}
 			return i;
 		}
@@ -1274,10 +1278,10 @@
 		count = 0;
 	}
 
-	if (doing_write && (STp->buffer)->last_result_fatal != 0) {
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
-		return (STp->buffer)->last_result_fatal;
+	if (doing_write && (STp->buffer)->syscall_result != 0) {
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
+		return (STp->buffer)->syscall_result;
 	}
 
 	if (STm->do_async_writes &&
@@ -1302,14 +1306,15 @@
 		cmd[4] = blks;
 		DEB( STp->write_pending = 1; )
 
-		SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout,
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing,
+				   SCSI_DATA_WRITE, STp->timeout,
 				   MAX_WRITE_RETRIES, FALSE);
-		if (SCpnt == NULL)
-			return (STp->buffer)->last_result_fatal;
+		if (SRpnt == NULL)
+			return (STp->buffer)->syscall_result;
 
-	} else if (SCpnt != NULL) {
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+	} else if (SRpnt != NULL) {
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 	}
 	STps->at_sm &= (total == 0);
 	if (total > 0)
@@ -1321,11 +1326,11 @@
 /* Read data from the tape. Returns zero in the normal case, one if the
    eof status has changed, and the negative error code in case of a
    fatal error. Otherwise updates the buffer and the eof state. */
-static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
+static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt)
 {
 	int transfer, blks, bytes;
 	static unsigned char cmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	Scsi_Tape *STp;
 	ST_mode *STm;
 	ST_partstat *STps;
@@ -1362,49 +1367,51 @@
 	cmd[3] = blks >> 8;
 	cmd[4] = blks;
 
-	SCpnt = *aSCpnt;
-	SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE);
-	*aSCpnt = SCpnt;
-	if (!SCpnt)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = *aSRpnt;
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, SCSI_DATA_READ,
+			   STp->timeout, MAX_RETRIES, TRUE);
+	*aSRpnt = SRpnt;
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
 
 	(STp->buffer)->read_pointer = 0;
 	STps->at_sm = 0;
 
 	/* Something to check */
-	if ((STp->buffer)->last_result_fatal) {
+	if ((STp->buffer)->syscall_result) {
 		retval = 1;
 		DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
                             dev,
-                            SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
-                            SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
-                            SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
-                            SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]));
-		if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) {	/* extended sense */
+                            SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
+                            SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
+                            SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
+                            SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]));
+		if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {	/* extended sense */
 
-			if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
-				SCpnt->sense_buffer[2] &= 0xcf;	/* No need for EOM in this case */
+			if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
+				SRpnt->sr_sense_buffer[2] &= 0xcf;	/* No need for EOM in this case */
 
-			if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
+			if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
 				/* Compute the residual count */
-				if ((SCpnt->sense_buffer[0] & 0x80) != 0)
-					transfer = (SCpnt->sense_buffer[3] << 24) |
-					    (SCpnt->sense_buffer[4] << 16) |
-					    (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+				if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
+					transfer = (SRpnt->sr_sense_buffer[3] << 24) |
+					    (SRpnt->sr_sense_buffer[4] << 16) |
+					    (SRpnt->sr_sense_buffer[5] << 8) |
+					    SRpnt->sr_sense_buffer[6];
 				else
 					transfer = 0;
 				if (STp->block_size == 0 &&
-				    (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
+				    (SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
 					transfer = bytes;
 
-				if (SCpnt->sense_buffer[2] & 0x20) {	/* ILI */
+				if (SRpnt->sr_sense_buffer[2] & 0x20) {	/* ILI */
 					if (STp->block_size == 0) {
 						if (transfer <= 0)
 							transfer = 0;
 						(STp->buffer)->buffer_bytes = bytes - transfer;
 					} else {
-						scsi_release_command(SCpnt);
-						SCpnt = *aSCpnt = NULL;
+						scsi_release_request(SRpnt);
+						SRpnt = *aSRpnt = NULL;
 						if (transfer == blks) {	/* We did not get anything, error */
 							printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
 							if (STps->drv_block >= 0)
@@ -1423,7 +1430,7 @@
 						if (st_int_ioctl(inode, MTBSR, 1))
 							return (-EIO);
 					}
-				} else if (SCpnt->sense_buffer[2] & 0x80) {	/* FM overrides EOM */
+				} else if (SRpnt->sr_sense_buffer[2] & 0x80) {	/* FM overrides EOM */
 					if (STps->eof != ST_FM_HIT)
 						STps->eof = ST_FM_HIT;
 					else
@@ -1436,7 +1443,7 @@
                                         DEBC(printk(ST_DEB_MSG
                                                     "st%d: EOF detected (%d bytes read).\n",
                                                     dev, (STp->buffer)->buffer_bytes));
-				} else if (SCpnt->sense_buffer[2] & 0x40) {
+				} else if (SRpnt->sr_sense_buffer[2] & 0x40) {
 					if (STps->eof == ST_FM)
 						STps->eof = ST_EOD_1;
 					else
@@ -1457,7 +1464,7 @@
                                             "st%d: Tape error while reading.\n", dev));
 				STps->drv_block = (-1);
 				if (STps->eof == ST_FM &&
-				    (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
+				    (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) {
                                         DEBC(printk(ST_DEB_MSG
                                                     "st%d: Zero returned for first BLANK CHECK after EOF.\n",
                                                     dev));
@@ -1468,7 +1475,7 @@
 		}
 		/* End of extended sense test */ 
 		else {		/* Non-extended sense */
-			retval = (STp->buffer)->last_result_fatal;
+			retval = (STp->buffer)->syscall_result;
 		}
 
 	}
@@ -1494,7 +1501,7 @@
 	ssize_t total;
 	ssize_t i, transfer;
 	int special;
-	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Request *SRpnt = NULL;
 	Scsi_Tape *STp;
 	ST_mode *STm;
 	ST_partstat *STps;
@@ -1587,10 +1594,10 @@
 
 		/* Get new data if the buffer is empty */
 		if ((STp->buffer)->buffer_bytes == 0) {
-			special = read_tape(inode, count - total, &SCpnt);
+			special = read_tape(inode, count - total, &SRpnt);
 			if (special < 0) {	/* No need to continue read */
-				if (SCpnt != NULL) {
-					scsi_release_command(SCpnt);
+				if (SRpnt != NULL) {
+					scsi_release_request(SRpnt);
 				}
 				return special;
 			}
@@ -1609,9 +1616,9 @@
 			    (STp->buffer)->buffer_bytes : count - total;
 			i = from_buffer(STp->buffer, buf, transfer);
 			if (i) {
-				if (SCpnt != NULL) {
-					scsi_release_command(SCpnt);
-					SCpnt = NULL;
+				if (SRpnt != NULL) {
+					scsi_release_request(SRpnt);
+					SRpnt = NULL;
 				}
 				return i;
 			}
@@ -1626,9 +1633,9 @@
 	}			/* for (total = 0, special = 0;
                                    total < count && !special; ) */
 
-	if (SCpnt != NULL) {
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+	if (SRpnt != NULL) {
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 	}
 
 	/* Change the eof state if no data from tape or buffer */
@@ -1830,7 +1837,7 @@
 {
 	int dev;
 	unsigned char cmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Request *SRpnt = NULL;
 
 	if (STp->ready != ST_READY)
 		return (-EIO);
@@ -1842,17 +1849,18 @@
 	cmd[2] = COMPRESSION_PAGE;
 	cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
 
-	SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
-	if (SCpnt == NULL)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
+			   STp->timeout, 0, TRUE);
+	if (SRpnt == NULL)
+		return (STp->buffer)->syscall_result;
 
-	dev = TAPE_NR(SCpnt->request.rq_dev);
+	dev = TAPE_NR(SRpnt->sr_request.rq_dev);
 
-	if ((STp->buffer)->last_result_fatal != 0) {
+	if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n",
                             dev));
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 		return (-EIO);
 	}
         DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
@@ -1861,8 +1869,8 @@
 	/* Check if compression can be changed */
 	if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 		return (-EIO);
 	}
 
@@ -1880,19 +1888,20 @@
 	(STp->buffer)->b_data[0] = 0;	/* Reserved data length */
 	(STp->buffer)->b_data[1] = 0;	/* Reserved media type byte */
 	(STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
-	SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+			   STp->timeout, 0, TRUE);
 
-	if ((STp->buffer)->last_result_fatal != 0) {
+	if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev));
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 		return (-EIO);
 	}
         DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
 		       dev, state));
 
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 	STp->compression_changed = TRUE;
 	return 0;
 }
@@ -1907,10 +1916,11 @@
 	int i, ioctl_result;
 	int chg_eof = TRUE;
 	unsigned char cmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 	Scsi_Tape *STp;
 	ST_partstat *STps;
-	int fileno, blkno, at_sm, undone, datalen;
+	int fileno, blkno, at_sm, undone;
+	int datalen = 0, direction = SCSI_DATA_NONE;
 	int dev = TAPE_NR(inode->i_rdev);
 
 	STp = &(scsi_tapes[dev]);
@@ -1927,7 +1937,6 @@
 	at_sm = STps->at_sm;
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
-	datalen = 0;
 	switch (cmd_in) {
 	case MTFSFM:
 		chg_eof = FALSE;	/* Changed from the FSF after this */
@@ -2169,6 +2178,7 @@
 		}
 		cmd[0] = MODE_SELECT;
 		cmd[4] = datalen = 12;
+		direction = SCSI_DATA_WRITE;
 
 		memset((STp->buffer)->b_data, 0, 12);
 		if (cmd_in == MTSETDRVBUFFER)
@@ -2215,15 +2225,16 @@
 		return (-ENOSYS);
 	}
 
-	SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
-	if (!SCpnt)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
+			   timeout, MAX_RETRIES, TRUE);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
 
-	ioctl_result = (STp->buffer)->last_result_fatal;
+	ioctl_result = (STp->buffer)->syscall_result;
 
 	if (!ioctl_result) {	/* SCSI command successful */
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 		STps->drv_block = blkno;
 		STps->drv_file = fileno;
 		STps->at_sm = at_sm;
@@ -2272,7 +2283,7 @@
 	} else { /* SCSI command was not completely successful. Don't return
                     from this block without releasing the SCSI command block! */
 
-		if (SCpnt->sense_buffer[2] & 0x40) {
+		if (SRpnt->sr_sense_buffer[2] & 0x40) {
 			if (cmd_in != MTBSF && cmd_in != MTBSFM &&
 			    cmd_in != MTBSR && cmd_in != MTBSS)
 				STps->eof = ST_EOM_OK;
@@ -2280,14 +2291,14 @@
 		}
 
 		undone = (
-				 (SCpnt->sense_buffer[3] << 24) +
-				 (SCpnt->sense_buffer[4] << 16) +
-				 (SCpnt->sense_buffer[5] << 8) +
-				 SCpnt->sense_buffer[6]);
+				 (SRpnt->sr_sense_buffer[3] << 24) +
+				 (SRpnt->sr_sense_buffer[4] << 16) +
+				 (SRpnt->sr_sense_buffer[5] << 8) +
+				 SRpnt->sr_sense_buffer[6]);
 		if (cmd_in == MTWEOF &&
-		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-		    (SCpnt->sense_buffer[2] & 0x4f) == 0x40 &&
-		 ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) {
+		    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+		    (SRpnt->sr_sense_buffer[2] & 0x4f) == 0x40 &&
+		 ((SRpnt->sr_sense_buffer[0] & 0x80) == 0 || undone == 0)) {
 			ioctl_result = 0;	/* EOF written succesfully at EOM */
 			if (fileno >= 0)
 				fileno++;
@@ -2308,7 +2319,7 @@
 			STps->drv_block = 0;
 			STps->eof = ST_NOEOF;
 		} else if (cmd_in == MTFSR) {
-			if (SCpnt->sense_buffer[2] & 0x80) {	/* Hit filemark */
+			if (SRpnt->sr_sense_buffer[2] & 0x80) {	/* Hit filemark */
 				if (STps->drv_file >= 0)
 					STps->drv_file++;
 				STps->drv_block = 0;
@@ -2321,7 +2332,7 @@
 				STps->eof = ST_NOEOF;
 			}
 		} else if (cmd_in == MTBSR) {
-			if (SCpnt->sense_buffer[2] & 0x80) {	/* Hit filemark */
+			if (SRpnt->sr_sense_buffer[2] & 0x80) {	/* Hit filemark */
 				STps->drv_file--;
 				STps->drv_block = (-1);
 			} else {
@@ -2338,14 +2349,14 @@
 		} else if (chg_eof)
 			STps->eof = ST_NOEOF;
 
-		if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+		if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
 			STps->eof = ST_EOD;
 
 		if (cmd_in == MTLOCK)
 			STp->door_locked = ST_LOCK_FAILS;
 
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
 	}
 
 	return ioctl_result;
@@ -2362,7 +2373,7 @@
 	int dev = TAPE_NR(inode->i_rdev);
 	int result;
 	unsigned char scmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 
 	STp = &(scsi_tapes[dev]);
 	if (STp->ready != ST_READY)
@@ -2377,11 +2388,12 @@
 		if (!logical && !STp->scsi2_logical)
 			scmd[1] = 1;
 	}
-	SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
-	if (!SCpnt)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(NULL, STp, scmd, 20, SCSI_DATA_READ, STp->timeout,
+			   MAX_READY_RETRIES, TRUE);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
 
-	if ((STp->buffer)->last_result_fatal != 0 ||
+	if ((STp->buffer)->syscall_result != 0 ||
 	    (STp->device->scsi_level >= SCSI_2 &&
 	     ((STp->buffer)->b_data[0] & 4) != 0)) {
 		*block = *partition = 0;
@@ -2407,8 +2419,8 @@
                 DEBC(printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
                             *block, *partition));
 	}
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 
 	return result;
 }
@@ -2426,7 +2438,7 @@
 	unsigned int blk;
 	int timeout;
 	unsigned char scmd[MAX_COMMAND_SIZE];
-	Scsi_Cmnd *SCpnt;
+	Scsi_Request *SRpnt;
 
 	STp = &(scsi_tapes[dev]);
 	if (STp->ready != ST_READY)
@@ -2483,13 +2495,14 @@
 	timeout = STp->timeout;
 #endif
 
-	SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE);
-	if (!SCpnt)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE,
+			   timeout, MAX_READY_RETRIES, TRUE);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
 
 	STps->drv_block = STps->drv_file = (-1);
 	STps->eof = ST_NOEOF;
-	if ((STp->buffer)->last_result_fatal != 0) {
+	if ((STp->buffer)->syscall_result != 0) {
 		result = (-EIO);
 		if (STp->can_partitions &&
 		    (STp->device)->scsi_level >= SCSI_2 &&
@@ -2511,8 +2524,8 @@
 		result = 0;
 	}
 
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 
 	return result;
 }
@@ -2561,7 +2574,7 @@
 {
 	int dev = TAPE_NR(inode->i_rdev), result;
 	Scsi_Tape *STp;
-	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Request *SRpnt = NULL;
 	unsigned char cmd[MAX_COMMAND_SIZE];
 
 	STp = &(scsi_tapes[dev]);
@@ -2574,14 +2587,15 @@
 	cmd[2] = PART_PAGE;
 	cmd[4] = 200;
 
-	SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE);
-	if (SCpnt == NULL)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, 200, SCSI_DATA_READ, STp->timeout,
+			   MAX_READY_RETRIES, TRUE);
+	if (SRpnt == NULL)
+		return (STp->buffer)->syscall_result;
 
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 
-	if ((STp->buffer)->last_result_fatal != 0) {
+	if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n",
                             dev));
 		result = (-EIO);
@@ -2601,7 +2615,7 @@
 	int dev = TAPE_NR(inode->i_rdev), result;
 	int length;
 	Scsi_Tape *STp;
-	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Request *SRpnt = NULL;
 	unsigned char cmd[MAX_COMMAND_SIZE], *bp;
 
 	if ((result = nbr_partitions(inode)) < 0)
@@ -2638,15 +2652,15 @@
 	cmd[1] = 0x10;
 	cmd[4] = length + MODE_HEADER_LENGTH;
 
-	SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout,
-			   MAX_READY_RETRIES, TRUE);
-	if (SCpnt == NULL)
-		return (STp->buffer)->last_result_fatal;
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+			   STp->long_timeout, MAX_READY_RETRIES, TRUE);
+	if (SRpnt == NULL)
+		return (STp->buffer)->syscall_result;
 
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
 
-	if ((STp->buffer)->last_result_fatal != 0) {
+	if ((STp->buffer)->syscall_result != 0) {
 		printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
 		result = (-EIO);
 	} else
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.3.46/linux/drivers/scsi/st.h	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/st.h	Sun Feb 20 20:20:42 2000
@@ -19,9 +19,9 @@
 	int buffer_bytes;
 	int read_pointer;
 	int writing;
-	int last_result;
-	int last_result_fatal;
-	Scsi_Cmnd *last_SCpnt;
+	int midlevel_result;
+	int syscall_result;
+	Scsi_Request *last_SRpnt;
 	unsigned char *b_data;
 	unsigned short use_sg;	/* zero or number of segments for this adapter */
 	unsigned short sg_segs;	/* total number of allocated segments */
diff -u --recursive --new-file v2.3.46/linux/drivers/sound/ac97_codec.h linux/drivers/sound/ac97_codec.h
--- v2.3.46/linux/drivers/sound/ac97_codec.h	Sun Feb 13 19:29:04 2000
+++ linux/drivers/sound/ac97_codec.h	Thu Feb 17 09:30:35 2000
@@ -107,13 +107,13 @@
 /* OSS interface to the ac97s.. */
 #define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\
 	SOUND_MASK_LINE|SOUND_MASK_CD|\
-	SOUND_MIXER_ALTPCM|SOUND_MASK_IGAIN|\
+	SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\
 	SOUND_MASK_LINE1|SOUND_MASK_VIDEO)
 
 #define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
 	SOUND_MASK_BASS|SOUND_MASK_TREBLE|\
 	SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\
-	SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT)
+	SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT)
 
 #define AC97_RECORD_MASK (SOUND_MASK_MIC|\
 	SOUND_MASK_CD|SOUND_MASK_VIDEO|\
diff -u --recursive --new-file v2.3.46/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.46/linux/drivers/sound/es1370.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sound/es1370.c	Sun Feb 20 20:16:30 2000
@@ -2466,6 +2466,10 @@
 		return -1;
 	if (pcidev->irq == 0) 
 		return -1;
+	if (!pci_dma_supported(pcidev, 0xffffffff)) {
+		printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
+		return -1;
+	}
 	if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) {
 		printk(KERN_WARNING "es1370: out of memory\n");
 		return -1;
@@ -2589,7 +2593,7 @@
        dev->driver_data = NULL;
 }
 
-static const struct pci_device_id id_table[] __devinitdata = {
+static struct pci_device_id id_table[] __devinitdata = {
 	{ PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
 	{ 0, 0, 0, 0, 0, 0 }
 };
@@ -2608,8 +2612,10 @@
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
 	printk(KERN_INFO "es1370: version v0.33 time " __TIME__ " " __DATE__ "\n");
-	if (!pci_register_driver(&es1370_driver))
+	if (!pci_register_driver(&es1370_driver)) {
+		pci_unregister_driver(&es1370_driver);
 		return -ENODEV;
+	}
         return 0;
 
 }
diff -u --recursive --new-file v2.3.46/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.46/linux/drivers/sound/es1371.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sound/es1371.c	Sun Feb 20 20:16:30 2000
@@ -2624,6 +2624,10 @@
 		return -1;
 	if (pcidev->irq == 0) 
 		return -1;
+	if (!pci_dma_supported(pcidev, 0xffffffff)) {
+		printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n");
+		return -1;
+	}
 	if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) {
 		printk(KERN_WARNING "es1371: out of memory\n");
 		return -1;
@@ -2788,7 +2792,7 @@
 	dev->driver_data = NULL;
 }
 
-static const struct pci_device_id id_table[] __devinitdata = {
+static struct pci_device_id id_table[] __devinitdata = {
 	{ PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
 	{ PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
 	{ PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
@@ -2809,8 +2813,10 @@
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
 	printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n");
-	if (!pci_register_driver(&es1371_driver))
+	if (!pci_register_driver(&es1371_driver)) {
+		pci_unregister_driver(&es1371_driver);
 		return -ENODEV;
+	}
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.46/linux/drivers/sound/esssolo1.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sound/esssolo1.c	Sun Feb 20 20:17:31 2000
@@ -67,7 +67,7 @@
  *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
  *                       Integrated (aka redid 8-)) APM support patch by Zach Brown
  *    07.02.2000   0.13  Use pci_alloc_consistent and pci_register_driver
- *
+ *    19.02.2000   0.14  Use pci_dma_supported to determine if recording should be disabled
  */
 
 /*****************************************************************************/
@@ -412,7 +412,7 @@
 	db->mapped = db->ready = 0;
 }
 
-static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long dmamask)
+static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db)
 {
 	int order;
 	unsigned bytespersec;
@@ -422,7 +422,6 @@
 	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
 	if (!db->rawbuf) {
 		db->ready = db->mapped = 0;
-		s->dev->dma_mask = dmamask;
                 for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
 			if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
 				break;
@@ -469,7 +468,10 @@
 	int c;
 
 	stop_adc(s);
-	if ((c = prog_dmabuf(s, &s->dma_adc, 0xffffff)))
+	/* check if PCI implementation supports 24bit busmaster DMA */
+	if (s->dev->dma_mask > 0xffffff)
+		return -EIO;
+	if ((c = prog_dmabuf(s, &s->dma_adc)))
 		return c;
 	va = s->dma_adc.dmaaddr;
 	if ((va & ~((1<<24)-1)))
@@ -494,7 +496,7 @@
 	int c;
 
 	stop_dac(s);
-	if ((c = prog_dmabuf(s, &s->dma_dac, 0xffffffff)))
+	if ((c = prog_dmabuf(s, &s->dma_dac)))
 		return c;
 	memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
 	va = s->dma_dac.dmaaddr;
@@ -2193,6 +2195,8 @@
 static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct solo1_state *s;
+	struct pm_dev *pmdev;
+	dma_addr_t dma_mask;
 
 	if (!RSRCISIOREGION(pcidev, 0) ||
 	    !RSRCISIOREGION(pcidev, 1) ||
@@ -2201,6 +2205,14 @@
 		return -1;
 	if (pcidev->irq == 0)
 		return -1;
+	if (pci_dma_supported(pcidev, 0x00ffffff)) {
+		dma_mask = 0x00ffffff; /* this enables playback and recording */
+	} else if (pci_dma_supported(pcidev, 0xffffffff)) {
+		dma_mask = 0xffffffff; /* this enables only playback, as the recording BMDMA can handle only 24bits  */
+	} else {
+		printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
+		return -1;
+	}
 	if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
 		printk(KERN_WARNING "solo1: out of memory\n");
 		return -1;
@@ -2258,7 +2270,7 @@
 		goto err;
 	/* store it in the driver field */
 	pcidev->driver_data = s;
-	pcidev->dma_mask = 0xffffff;  /* pessimistic; play can handle 32bit addrs */
+	pcidev->dma_mask = dma_mask;
 	/* put it into driver list */
 	list_add_tail(&s->devs, &devs);
 
@@ -2318,7 +2330,7 @@
 	dev->driver_data = NULL;
 }
 
-static const struct pci_device_id id_table[] __devinitdata = {
+static struct pci_device_id id_table[] __devinitdata = {
 	{ PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
 	{ 0, 0, 0, 0, 0, 0 }
 };
@@ -2337,9 +2349,11 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.13 time " __TIME__ " " __DATE__ "\n");
-	if (!pci_register_driver(&solo1_driver))
+	printk(KERN_INFO "solo1: version v0.14 time " __TIME__ " " __DATE__ "\n");
+	if (!pci_register_driver(&solo1_driver)) {
+		pci_unregister_driver(&solo1_driver);
                 return -ENODEV;
+	}
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.3.46/linux/drivers/sound/sb_card.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/sb_card.c	Fri Feb 18 16:50:49 2000
@@ -17,10 +17,15 @@
  * 06-01-2000 Refined and bugfixed ISA PnP support, added
  *  CMI 8330 support - Alessandro Zummo <azummo@ita.flashnet.it>
  *
- *
  * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump
  *  Alessandro Zummo <azummo@ita.flashnet.it>
  *
+ * 11-02-2000 Added Soundblaster AWE 32 PnP support, refined PnP code
+ *  Alessandro Zummo <azummo@ita.flashnet.it>
+ *
+ * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup.
+ *  Alessandro Zummo <azummo@ita.flashnet.it>
+ *
  */
 
 #include <linux/config.h>
@@ -134,7 +139,8 @@
 
 struct pci_dev 	*sb_dev 	= NULL, 
 				*wss_dev 	= NULL, 
-				*jp_dev 	= NULL, 
+				*jp_dev 	= NULL,
+/*				*ide_dev	= NULL, */
 				*mpu_dev 	= NULL, 
 				*wt_dev 	= NULL;
 /*
@@ -156,9 +162,10 @@
 int sm_games	= 0;		/* Mixer - see sb_mixer.c */
 int acer 	= 0;		/* Do acer notebook init */
 
-#ifdef CONFIG_ISAPNP
+#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
 int isapnp 		= 1;
 int isapnpjump 		= 0;
+int nosbwave	= 0;		/* This option will be removed when the new awe_wave driver will be in the kernel tree */
 #else
 int isapnp 		= 0;
 #endif
@@ -179,11 +186,13 @@
 MODULE_PARM(esstype, 	"i");
 MODULE_PARM(acer, 	"i");
 
-#ifdef CONFIG_ISAPNP
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 MODULE_PARM(isapnp, 	"i");
 MODULE_PARM(isapnpjump, "i");
+MODULE_PARM(nosbwave,	"i");
 MODULE_PARM_DESC(isapnp,	"When set to 0, Plug & Play support will be disabled");
 MODULE_PARM_DESC(isapnpjump, 	"Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
+MODULE_PARM_DESC(nosbwave,		"Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver.");
 #endif
 
 MODULE_PARM_DESC(io, 		"Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
@@ -202,79 +211,86 @@
 
 void *smw_free = NULL;
 
-#ifdef CONFIG_ISAPNP
+#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
 
 /* That's useful. */
 
-static int check_base(char *devname, char *resname, struct resource *res)
+#define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start)
+
+static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev)
 {
-	if (check_region(res->start, res->end - res->start))
+	int err;
+
+	if(dev->active)
 	{
-		printk(KERN_ERR "sb: %s %s error, i/o at %#lx already in use\n", devname, resname, res->start);
-		return 0;
+		printk(KERN_INFO "sb: %s %s already in use\n", devname, resname);
+		return(NULL);
 	}
 
-	printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, res->start);
-	return 1;
-}
+	if((err = dev->activate(dev)) < 0)
+	{
+		printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err);
 
+		dev->deactivate(dev);
+
+		return(NULL);
+	}
+	return(dev);
+}
 
 /* Card's specific initialization functions
  */
 
-static struct pci_dev *sb_init_generic(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
 {
-	if((sb_dev = isapnp_find_dev(card,
-				card->vendor,
-				card->device,
-				NULL)))
+	if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
 	{
 		sb_dev->prepare(sb_dev);
-		sb_dev->activate(sb_dev);
 
-		if (!sb_dev->resource[0].start)
-			return(NULL);
-
-		hw_config->io_base 	= sb_dev->resource[0].start;
-		hw_config->irq 		= sb_dev->irq_resource[0].start;
-		hw_config->dma 		= sb_dev->dma_resource[0].start;
-		hw_config->dma2 	= sb_dev->dma_resource[1].start;
-		mpu_config->io_base     = sb_dev->resource[1].start;
+		if((sb_dev = activate_dev("Soundblaster", "sb", sb_dev)))
+		{
+			hw_config->io_base 	= sb_dev->resource[0].start;
+			hw_config->irq 		= sb_dev->irq_resource[0].start;
+			hw_config->dma 		= sb_dev->dma_resource[0].start;
+			hw_config->dma2 	= sb_dev->dma_resource[1].start;
+			mpu_config->io_base = sb_dev->resource[1].start;
+		}
 	}
 	return(sb_dev);
 }
 
-static struct pci_dev *sb_init_ess(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
 {
-	if((sb_dev = isapnp_find_dev(card,
-				card->vendor,
-				card->device,
-				NULL)))
+	if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
 	{
 		sb_dev->prepare(sb_dev);
-		sb_dev->activate(sb_dev);
-
-		if (!sb_dev->resource[0].start)
-			return(NULL);
 
-		hw_config->io_base 	= sb_dev->resource[0].start;
-		hw_config->irq 		= sb_dev->irq_resource[0].start;
-		hw_config->dma 		= sb_dev->dma_resource[0].start;
-		hw_config->dma2 	= sb_dev->dma_resource[1].start;
-		mpu_config->io_base     = sb_dev->resource[2].start;
+		if((sb_dev = activate_dev("ESS", "sb", sb_dev)))
+		{
+			hw_config->io_base 	= sb_dev->resource[0].start;
+			hw_config->irq 		= sb_dev->irq_resource[0].start;
+			hw_config->dma 		= sb_dev->dma_resource[0].start;
+			hw_config->dma2 	= sb_dev->dma_resource[1].start;
+			mpu_config->io_base = sb_dev->resource[2].start;
+		}
 	}
 	return(sb_dev);
 }
 
-static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
 {
-	/* What a stupid chip... where did they get all those @@@ ?*/
-
-	printk(KERN_INFO "sb: CMI8330 detected\n");
+	/* 
+	 *  The CMI8330/C3D is a very 'stupid' chip... where did they get al those @@@ ?
+	 *  It's ISAPnP section is badly designed and has many flaws, i'll do my best
+	 *  to workaround them. I strongly suggest you to buy a real soundcard.
+	 *  The CMI8330 on my motherboard has also the bad habit to activate 
+	 *  the rear channel of my amplifier instead of the front one.
+	 */
 
-	/* Soundblaster compatible logical device. */
+	/*  @X@0001:Soundblaster.
+	 */
 
-	if((sb_dev = isapnp_find_dev(card,
+	if((sb_dev = isapnp_find_dev(bus,
 				ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
 	{
 #ifdef CMI8330_DMA0BAD
@@ -283,11 +299,11 @@
 		sb_dev->prepare(sb_dev);
 		
 		/*  This device doesn't work with DMA 0, so we must allocate
-			it to prevent PnP routines to assign it to the card.
-
-			I know i could have inlined the following lines, but it's cleaner
-			this way.
-		*/
+		 *	it to prevent PnP routines to assign it to the card.
+		 *
+		 *	I know i could have inlined the following lines, but it's cleaner
+		 *  this way.
+		 */
 	
 #ifdef CMI8330_DMA0BAD
 		if(sb_dev->dma_resource[0].start == 0)
@@ -300,69 +316,72 @@
 		}
 #endif
 
-		if(sb_dev->activate(sb_dev) >= 0)
+		if((sb_dev = activate_dev("CMI8330", "sb", sb_dev)))
 		{
 			hw_config->io_base 	= sb_dev->resource[0].start;
 			hw_config->irq 		= sb_dev->irq_resource[0].start;
 			hw_config->dma 		= sb_dev->dma_resource[0].start;
 			hw_config->dma2 	= sb_dev->dma_resource[1].start;
 
-			check_base("CMI8330", "sb", &sb_dev->resource[0]);
+			show_base("CMI8330", "sb", &sb_dev->resource[0]);
 		}
-		else
-			printk(KERN_ERR "sb: CMI8330 sb config failed (out of resources?)\n");
 
 #ifdef CMI8330_DMA0BAD
 		if(dmahack)
 			free_dma(0);
 #endif
+
+		if(!sb_dev) return(NULL);
+
 	}
 	else
-		printk(KERN_ERR "sb: CMI8330 panic! sb base not found\n");
+		printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n");
+
+	/*  @H@0001:mpu
+	 */
 
-	if((mpu_dev = isapnp_find_dev(card,
+#ifdef CONFIG_MIDI
+	if((mpu_dev = isapnp_find_dev(bus,
 				ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
 	{
 		mpu_dev->prepare(mpu_dev);
 
-		/* This disables the interrupt on this resource. Do we need it ? */
+		/*  This disables the interrupt on this resource. Do we need it ?
+		 */
 
 		mpu_dev->irq_resource[0].flags = 0;
 
-		if(mpu_dev->activate(mpu_dev) >= 0)
+		if((mpu_dev = activate_dev("CMI8330", "mpu", mpu_dev)))
 		{
-			if( check_base("CMI8330", "mpu", &mpu_dev->resource[0]) ) 
-				mpu_config->io_base = mpu_dev->resource[0].start;
+			show_base("CMI8330", "mpu", &mpu_dev->resource[0]);
+			mpu_config->io_base = mpu_dev->resource[0].start;
 		}
-		else
-			printk(KERN_ERR "sb: CMI8330 mpu config failed (out of resources?)\n");
 	}
 	else
-		printk(KERN_ERR "sb: CMI8330 panic! mpu not found\n");
+		printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n");
+#endif
 
 
-	/* Gameport. */
+	/*  @P@:Gameport
+	 */
 
-	if((jp_dev = isapnp_find_dev(card,
+	if((jp_dev = isapnp_find_dev(bus,
 				ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
 	{
 		jp_dev->prepare(jp_dev);
 		
-		if(jp_dev->activate(jp_dev) >= 0)
-		{
-			check_base("CMI8330", "gameport", &jp_dev->resource[0]);
-		}
-		else
-			printk(KERN_ERR "sb: CMI8330 gameport config failed (out of resources?)\n");
+
+		if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev)))
+			show_base("CMI8330", "gameport", &jp_dev->resource[0]);
 	}
 	else
-		printk(KERN_ERR "sb: CMI8330 panic! gameport not found\n");
+		printk(KERN_ERR "sb: CMI8330 panic: gameport not found\n");
 
-
-	/* OPL3 support */
+	/*  @@@0001:OPL3 
+	 */
 
 #if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
-	if((wss_dev = isapnp_find_dev(card,
+	if((wss_dev = isapnp_find_dev(bus,
 				ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
 	{
 		wss_dev->prepare(wss_dev);
@@ -372,15 +391,11 @@
 		wss_dev->irq_resource[0].flags = 0;
 		wss_dev->dma_resource[0].flags = 0;
 
-		if(wss_dev->activate(wss_dev) >= 0)
-		{
-			check_base("CMI8330", "opl3", &wss_dev->resource[1]);
-		}
-		else
-			printk(KERN_ERR "sb: CMI8330 opl3 config failed (out of resources?)\n");
+		if((wss_dev = activate_dev("CMI8330", "opl3", wss_dev)))
+			show_base("CMI8330", "opl3", &wss_dev->resource[1]);
 	}
 	else
-		printk(KERN_ERR "sb: CMI8330 panic! opl3 not found\n");
+		printk(KERN_ERR "sb: CMI8330 panic: opl3 not found\n");
 #endif
 
 	printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
@@ -388,18 +403,25 @@
 	return(sb_dev);
 }
 
-static struct pci_dev *sb_init_awe64(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
-{
-	printk(KERN_INFO "sb: SoundBlaster AWE 64 detected\n");
-
-	/* CTL0042:Audio. */
+/* Specific support for awe will be dropped when:
+ * a) The new awe_wawe driver with PnP support will be introduced in the kernel
+ * b) The joystick driver will support PnP
+ */
 
-	if((sb_dev = isapnp_find_dev(card,
-				ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)))
+static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
+{
+	/*  CTL0042:Audio SB64
+	 *  CTL0031:Audio SB32
+	 *  CTL0045:Audio SB64
+	 */
+
+	if(	(sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) || 
+		(sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) ||
+		(sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL))	)
 	{
 		sb_dev->prepare(sb_dev);
 		
-		if(sb_dev->activate(sb_dev) >= 0)
+		if((sb_dev = activate_dev("AWE", "sb", sb_dev)))
 		{
 			hw_config->io_base 	= sb_dev->resource[0].start;
 			hw_config->irq 		= sb_dev->irq_resource[0].start;
@@ -408,87 +430,144 @@
 
 			mpu_config->io_base	= sb_dev->resource[1].start;
 
-			check_base("AWE64", "sb", 	&sb_dev->resource[0]);
-			check_base("AWE64", "mpu", 	&sb_dev->resource[1]);
-			check_base("AWE64", "opl3",	&sb_dev->resource[2]);
+			show_base("AWE", "sb", 		&sb_dev->resource[0]);
+			show_base("AWE", "mpu", 	&sb_dev->resource[1]);
+			show_base("AWE", "opl3",	&sb_dev->resource[2]);
 		}
 		else
-			printk(KERN_ERR "sb: AWE64 sb config failed (out of resources?)\n");
+			return(NULL);
 	}
 	else
-		printk(KERN_ERR "sb: AWE64 panic! sb base not found\n");
+		printk(KERN_ERR "sb: AWE panic: sb base not found\n");
 
 
-	/* CTL7002:Game */
+	/*  CTL7002:Game SB64
+	 *  CTL7001:Game SB32
+	 */
 
-	if((jp_dev = isapnp_find_dev(card,
-				ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)))
+	if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) ||
+		(jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) )
 	{
 		jp_dev->prepare(jp_dev);
 		
-		if(jp_dev->activate(jp_dev) >= 0)
+		if((jp_dev = activate_dev("AWE", "gameport", jp_dev)))
+			show_base("AWE", "gameport", &jp_dev->resource[0]);
+	}
+	else
+		printk(KERN_ERR "sb: AWE panic: gameport not found\n");
+
+
+	/*  CTL0022:WaveTable SB64
+	 *  CTL0021:WaveTable SB32
+	 */
+
+	if( nosbwave == 0 &&
+	   	( (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) ||
+		  (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) ||
+		  (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) ))
+	{
+		wt_dev->prepare(wt_dev);
+		
+		if((wt_dev = activate_dev("AWE", "wavetable", wt_dev)))
 		{
-			check_base("AWE64", "gameport", &jp_dev->resource[0]);
+			show_base("AWE", "wavetable", &wt_dev->resource[0]);
+			show_base("AWE", "wavetable", &wt_dev->resource[1]);
+			show_base("AWE", "wavetable", &wt_dev->resource[2]);
 		}
-		else
-			printk(KERN_ERR "sb: AWE64 gameport config failed (out of resources?)\n");
 	}
 	else
-		printk(KERN_ERR "sb: AWE64 panic! gameport not found\n");
+		printk(KERN_ERR "sb: AWE panic: wavetable not found\n");
 
 
-	/* CTL0022:WaveTable */
+	/*  CTL2011:IDE SB32/64
+	 */
 
-	if((wt_dev = isapnp_find_dev(card,
-				ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)))
+/* No reasons to enable this... or not? */
+/*
+	if( (ide_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x2011), NULL)) )
 	{
-		wt_dev->prepare(wt_dev);
+		ide_dev->prepare(ide_dev);
 		
-		if(wt_dev->activate(wt_dev) >= 0)
+		if((ide_dev = activate_dev("AWE", "IDE", ide_dev)))
 		{
-			check_base("AWE64", "wavetable", &wt_dev->resource[0]);
-			check_base("AWE64", "wavetable", &wt_dev->resource[1]);
-			check_base("AWE64", "wavetable", &wt_dev->resource[2]);
+			show_base("AWE", "IDE 1", &ide_dev->resource[0]);
+			show_base("AWE", "IDE 2", &ide_dev->resource[1]);
 		}
-		else
-			printk(KERN_ERR "sb: AWE64 wavetable config failed (out of resources?)\n");
 	}
 	else
-		printk(KERN_ERR "sb: AWE64 panic! wavetable not found\n");
+		printk(KERN_ERR "sb: AWE panic: IDE not found\n");
+*/
 
-	printk(KERN_INFO "sb: AWE64 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
+	printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
 
 	return(sb_dev);
 }
 
+#define SBF_DEV	0x01
 
-static struct { unsigned short vendor, function; struct pci_dev * (*initfunc)(struct pci_bus *, struct address_info *, struct address_info *); char *name; }
+
+static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
 isapnp_sb_list[] __initdata = {
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), &sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), &sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), &sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), &sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), &sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), &sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), &sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), &sb_init_awe64,	"Sound Blaster AWE 64" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), &sb_init_ess,		"ESS 1868" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), &sb_init_ess,		"ESS 1868" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), &sb_init_ess,		"ESS 1869" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), &sb_init_ess,		"ESS 1878" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), &sb_init_ess,		"ESS 1879" },
-	{ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), &sb_init_cmi, 	"CMI 8330 SoundPRO" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic,	"Sound Blaster 16" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic,	"Sound Blaster 16" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic,	"Sound Blaster 16" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic,	"Sound Blaster 16" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic,	"Sound Blaster 16" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic,	"Sound Blaster 16" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0,	   &sb_init_awe,		"Sound Blaster 32" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0,	   &sb_init_awe,		"Sound Blaster AWE 32" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0,	   &sb_init_awe,		"Sound Blaster AWE 64" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0,	   &sb_init_awe,		"Sound Blaster AWE 64" },
+	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0,	   &sb_init_awe,		"Sound Blaster AWE 64" },
+	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess,		"ESS 1868" },
+	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess,		"ESS 1868" },
+	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess,		"ESS 1869" },
+	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess,		"ESS 1878" },
+	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess,		"ESS 1879" },
+	{ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0,	   &sb_init_cmi,		"CMI 8330 SoundPRO" },
     {0}
 };
 
+static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
+{
+	struct pci_dev *idev = NULL;
+
+    /* You missed the init func? That's bad. */
+	if(isapnp_sb_list[slot].initfunc)
+	{
+		char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name;
+
+		printk(KERN_INFO "sb: %s detected\n", busname); 
+
+		/* Initialize this baby. */
+
+		if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config)))
+		{
+			/* We got it. */
+
+			printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",
+			       busname,
+			       hw_config->io_base, hw_config->irq, hw_config->dma,
+			       hw_config->dma2);
+			return 1;
+		}
+		else
+			printk(KERN_INFO "sb: Failed to initialize %s\n", busname);
+	}
+	else
+		printk(KERN_ERR "sb: Bad entry in sb_card.c PnP table\n");
+
+	return 0;
+}
+
 /* Actually this routine will detect and configure only the first card with successful
-   initalization. isapnpjump could be used to jump to a specific entry.
+   initialization. isapnpjump could be used to jump to a specific entry.
    Please always add entries at the end of the array.
    Should this be fixed? - azummo
 */
 
-static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) {
-
+static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) 
+{
 	int i;
 
 	/* Count entries in isapnp_sb_list */
@@ -502,34 +581,43 @@
 	}
 	
 	for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
-		struct pci_bus *card = NULL;
-			
-		while ((card = isapnp_find_card(
-					       isapnp_sb_list[i].vendor,
-					       isapnp_sb_list[i].function,
-					       card))) {
 
-       			/* You missed the init func? That's bad. */
+		if(!(isapnp_sb_list[i].flags & SBF_DEV))
+		{
+			struct pci_bus *bus = NULL;
+				
+			while ((bus = isapnp_find_card(
+						       isapnp_sb_list[i].vendor,
+						       isapnp_sb_list[i].function,
+						       bus))) {
+	
+				if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i))
+					return 0;
+			}
+		}
+	}
 
-			if(isapnp_sb_list[i].initfunc)
-			{
-				struct pci_dev *idev = NULL;
+	/*  No cards found. I'll try now to search inside every card for a logical device
+	 *  that matches any entry marked with SBF_DEV in the table.
+	 */
+
+	for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
 
-				/* Initialize this baby. */
+		if(isapnp_sb_list[i].flags & SBF_DEV)
+		{
+			struct pci_dev *card = NULL;
+
+			while ((card = isapnp_find_dev(NULL,
+						       isapnp_sb_list[i].vendor,
+						       isapnp_sb_list[i].function,
+						       card))) {
 
-				if((idev = isapnp_sb_list[i].initfunc(card, hw_config, mpu_config)))
-				{
-					/* We got it. */
-
-					printk(KERN_INFO "sb: ISAPnP reports %s at i/o %#x, irq %d, dma %d, %d\n",
-					       isapnp_sb_list[i].name,
-					       hw_config->io_base, hw_config->irq, hw_config->dma,
-					       hw_config->dma2);
+				if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i))
 					return 0;
-				}
 			}
 		}
 	}
+
 	return -ENODEV;
 }
 #endif
@@ -544,18 +632,15 @@
 			able to disable PNP support for this single driver!
 		*/
 
-#ifdef CONFIG_ISAPNP			
-		if (isapnp)
+#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE			
+		if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) )
 		{
-			if(sb_probe_isapnp(&config, &config_mpu) < 0 )
-			{
-				printk(KERN_ERR "sb_card: No ISAPnP cards found\n");
-				return -EINVAL;
-			}
+			printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
+			isapnp = 0;
 		}
-		else
+#endif
+		if(isapnp == 0)
 		{
-#endif		
 			if (io == -1 || dma == -1 || irq == -1)
 			{
 				printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
@@ -566,11 +651,8 @@
 			config.irq 		= irq;
 			config.dma 		= dma;
 			config.dma2 	= dma16;
-#ifdef CONFIG_ISAPNP
 		}
-#endif
 
-		/* If this is not before the #ifdef line, there's a reason... */
 		config.card_subtype = type;
 
 		if (!probe_sb(&config))
@@ -604,6 +686,7 @@
 	if(sb_dev)	sb_dev->deactivate(sb_dev);
 	if(jp_dev)	jp_dev->deactivate(jp_dev);
 	if(wt_dev)	wt_dev->deactivate(wt_dev);
+/*	if(ide_dev)	wt_dev->deactivate(ide_dev); */
 	if(mpu_dev)	mpu_dev->deactivate(mpu_dev);
 	if(wss_dev)	wss_dev->deactivate(wss_dev);
 }
diff -u --recursive --new-file v2.3.46/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.46/linux/drivers/sound/sonicvibes.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sound/sonicvibes.c	Sun Feb 20 20:16:30 2000
@@ -2447,6 +2447,10 @@
 		return -1;
 	if (pcidev->irq == 0)
 		return -1;
+	if (!pci_dma_supported(pcidev, 0x00ffffff)) {
+		printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
+		return -1;
+	}
 	/* try to allocate a DDMA resource if not already available */
 	if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
 		pcidev->resource[RESOURCE_DDMA].start = 0;
@@ -2625,7 +2629,7 @@
        dev->driver_data = NULL;
 }
 
-static const struct pci_device_id id_table[] __devinitdata = {
+static struct pci_device_id id_table[] __devinitdata = {
        { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
        { 0, 0, 0, 0, 0, 0 }
 };
@@ -2648,8 +2652,10 @@
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
 #endif
-	if (!pci_register_driver(&sv_driver))
+	if (!pci_register_driver(&sv_driver)) {
+		pci_unregister_driver(&sv_driver);
                 return -ENODEV;
+	}
         return 0;
 }
 
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.46/linux/drivers/usb/Makefile	Wed Feb 16 17:03:52 2000
+++ linux/drivers/usb/Makefile	Sun Feb 20 16:20:47 2000
@@ -23,16 +23,12 @@
 
 list-multi		:= usbcore.o
 usbcore-objs		:= usb.o usb-debug.o usb-core.o hub.o
-usb-storage-objs	:= usb_storage.o
 
 # Optional parts of multipart objects.
 
 ifeq ($(CONFIG_USB_DEVICEFS),y)
 	usbcore-objs	+= devio.o inode.o drivers.o devices.o
 endif
-ifeq ($(CONFIG_USB_STORAGE_DEBUG),y)
-	usb-storage-objs	+= usb_storage_debug.o
-endif
 
 # Object file lists.
 
@@ -106,7 +102,4 @@
 
 usbcore.o: $(usbcore-objs)
 	$(LD) -r -o $@ $(usbcore-objs)
-
-usb-storage.o: $(usb-storage-objs)
-	$(LD) -r -o $@ $(usb-storage-objs)
 
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.46/linux/drivers/usb/acm.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/usb/acm.c	Sun Feb 20 13:06:56 2000
@@ -1,5 +1,5 @@
 /*
- * acm.c  Version 0.15
+ * acm.c  Version 0.16
  *
  * Copyright (c) 1999 Armin Fuerst	<fuerst@in.tum.de>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
@@ -18,6 +18,7 @@
  *	v0.13 - added termios, added hangup
  *	v0.14 - sized down struct acm
  *	v0.15 - fixed flow control again - characters could be lost
+ *	v0.16 - added code for modems with swapped data and control interfaces
  */
 
 /*
@@ -473,29 +474,34 @@
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 
 		cfacm = dev->config + i;
-		dbg("probing config %d", cfacm->bConfigurationValue);
 
-		ifcom = cfacm->interface[0].altsetting + 0;
-		if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
-		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
-			continue;
+		dbg("probing config %d", cfacm->bConfigurationValue);
 
-		epctrl = ifcom->endpoint + 0;
-		if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3)
+		if (cfacm->bNumInterfaces != 2 || 
+		    usb_interface_claimed(cfacm->interface + 0) ||
+		    usb_interface_claimed(cfacm->interface + 1))
 			continue;
 
+		ifcom = cfacm->interface[0].altsetting + 0;
 		ifdata = cfacm->interface[1].altsetting + 0;
-		if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
-			continue;
 
-		if (usb_interface_claimed(cfacm->interface + 0) ||
-		    usb_interface_claimed(cfacm->interface + 1))
+		if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
+			ifcom = cfacm->interface[1].altsetting + 0;
+			ifdata = cfacm->interface[0].altsetting + 0;
+			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
+				continue;
+		}
+
+		if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
 			continue;
 
+		epctrl = ifcom->endpoint + 0;
 		epread = ifdata->endpoint + 0;
 		epwrite = ifdata->endpoint + 1;
 
-		if ((epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+		if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
+		   (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
 		   ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
 			continue;
 
@@ -640,17 +646,13 @@
  * Init / cleanup.
  */
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit usb_acm_cleanup(void)
 {
 	usb_deregister(&acm_driver);
 	tty_unregister_driver(&acm_tty_driver);
 }
 
-int init_module(void)
-#else
-int usb_acm_init(void)
-#endif
+static int __init usb_acm_init(void)
 {
 	acm_tty_driver.init_termios =		tty_std_termios;
 	acm_tty_driver.init_termios.c_cflag =	B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -666,4 +668,5 @@
 	return 0;
 }
 
-__initcall(usb_acm_init);
+module_init(usb_acm_init);
+module_exit(usb_acm_cleanup);
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/hid.c linux/drivers/usb/hid.c
--- v2.3.46/linux/drivers/usb/hid.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/usb/hid.c	Fri Feb 18 10:33:47 2000
@@ -833,23 +833,45 @@
 			}
 			break;
 
-		case HID_UP_HOTKEY:
+		case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
 			
 			switch (usage->hid & HID_USAGE) {
 
-				case 0x0034: usage->code = KEY_PHONE;		break;
-				case 0x0036: usage->code = KEY_NOTEPAD;		break;
-				case 0x008a: usage->code = KEY_MAIL;		break;
-				case 0x0095: usage->code = KEY_CALENDAR;	break;
-				case 0x00b7: usage->code = KEY_PRINT;		break;
-				case 0x00b8: usage->code = KEY_HELP;		break;
-				case 0x00cd: usage->code = KEY_SOUND;		break;
-				case 0x00e2: usage->code = KEY_PROG1;		break;
-				case 0x00e9: usage->code = KEY_PROG2;		break;
-				case 0x00ea: usage->code = KEY_PROG3;		break;
-				case 0x018a: usage->code = KEY_WWW;		break;
-				case 0x0223: usage->code = KEY_FULLSCREEN;	break;
-				default:     usage->code = KEY_UNKNOWN;		break;
+				case 0x034: usage->code = KEY_SLEEP;		break;
+				case 0x036: usage->code = BTN_MISC;		break;
+				case 0x08a: usage->code = KEY_WWW;		break;
+				case 0x095: usage->code = KEY_HELP;		break;
+
+				case 0x0b4: usage->code = KEY_REWIND;		break;
+				case 0x0b5: usage->code = KEY_NEXTSONG;		break;
+				case 0x0b6: usage->code = KEY_PREVIOUSSONG;	break;
+				case 0x0b7: usage->code = KEY_STOPCD;		break;
+				case 0x0b8: usage->code = KEY_EJECTCD;		break;
+				case 0x0cd: usage->code = KEY_PLAYPAUSE;	break;
+
+				case 0x0e2: usage->code = KEY_MUTE;		break;
+				case 0x0e9: usage->code = KEY_VOLUMEUP;		break;
+				case 0x0ea: usage->code = KEY_VOLUMEDOWN;	break;
+
+				case 0x183: usage->code = KEY_CONFIG;		break;
+				case 0x18a: usage->code = KEY_MAIL;		break;
+				case 0x192: usage->code = KEY_CALC;		break;
+				case 0x194: usage->code = KEY_FILE;		break;
+
+				case 0x21a: usage->code = KEY_UNDO;		break;
+				case 0x21b: usage->code = KEY_COPY;		break;
+				case 0x21c: usage->code = KEY_CUT;		break;
+				case 0x21d: usage->code = KEY_PASTE;		break;
+
+				case 0x221: usage->code = KEY_FIND;		break;
+				case 0x223: usage->code = KEY_HOMEPAGE;		break;
+				case 0x224: usage->code = KEY_BACK;		break;
+				case 0x225: usage->code = KEY_FORWARD;		break;
+				case 0x226: usage->code = KEY_STOP;		break;
+				case 0x227: usage->code = KEY_REFRESH;		break;
+				case 0x22a: usage->code = KEY_BOOKMARKS;	break;
+
+				default:    usage->code = KEY_UNKNOWN;		break;
 
 			}
 		
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/hid.h linux/drivers/usb/hid.h
--- v2.3.46/linux/drivers/usb/hid.h	Sat Feb 12 11:22:11 2000
+++ linux/drivers/usb/hid.h	Fri Feb 18 10:33:47 2000
@@ -158,7 +158,7 @@
 #define HID_UP_KEYBOARD 	0x00070000
 #define HID_UP_LED 		0x00080000
 #define HID_UP_BUTTON 		0x00090000
-#define HID_UP_HOTKEY		0x000c0000
+#define HID_UP_CONSUMER		0x000c0000
 #define HID_UP_DIGITIZER 	0x000d0000
 #define HID_UP_PID 		0x000f0000
 
@@ -201,7 +201,7 @@
  * This is the local enviroment. It is resistent up the the next main-item.
  */
 
-#define MAX_USAGES 256
+#define MAX_USAGES 512
 
 struct hid_local {
 	unsigned usage[MAX_USAGES]; /* usage array */
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c
--- v2.3.46/linux/drivers/usb/plusb.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/usb/plusb.c	Sun Feb 20 13:06:56 2000
@@ -502,7 +502,7 @@
 	dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
 	  usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
 
-	if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct != 0x1)
+	if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct > 0x1)
 		return NULL;
 
 	/* We don't handle multiple configurations */
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.46/linux/drivers/usb/printer.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/usb/printer.c	Sun Feb 20 13:06:56 2000
@@ -432,15 +432,12 @@
 	minor:		USBLP_MINOR_BASE
 };
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit usb_printer_cleanup(void)
 {
 	usb_deregister(&usblp_driver);
 }
-int init_module(void)
-#else
-int usb_printer_init(void)
-#endif
+
+static int __init usb_printer_init(void)
 {
 	if (usb_register(&usblp_driver))
 		return -1;
@@ -448,4 +445,5 @@
 	return 0;
 }
 
-__initcall(usb_printer_init);
+module_init(usb_printer_init);
+module_exit(usb_printer_cleanup);
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/uhci-debug.h linux/drivers/usb/uhci-debug.h
--- v2.3.46/linux/drivers/usb/uhci-debug.h	Tue Feb  1 01:35:44 2000
+++ linux/drivers/usb/uhci-debug.h	Sun Feb 20 13:07:04 2000
@@ -193,7 +193,7 @@
 
 void uhci_show_queues(struct uhci *uhci)
 {
-	int i, isqh;
+	int i, isqh = 0;
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.46/linux/drivers/usb/usb-core.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/usb/usb-core.c	Sun Feb 20 13:06:56 2000
@@ -33,8 +33,6 @@
 int usb_cpia_init(void);
 int usb_ibmcam_init(void);
 int usb_ov511_init(void);
-int usb_dc2xx_init(void);
-int usb_scanner_init(void);
 int usb_stor_init(void);
 int dabusb_init(void);
 int plusb_init(void);
@@ -76,9 +74,6 @@
 	usb_hub_init();
 
 #ifndef CONFIG_USB_MODULE
-#ifdef CONFIG_USB_SCANNER
-	usb_scanner_init();
-#endif
 #ifdef CONFIG_USB_AUDIO
 	usb_audio_init();
 #endif
@@ -90,9 +85,6 @@
 #endif
 #ifdef CONFIG_USB_OV511
 	usb_ov511_init();
-#endif
-#ifdef CONFIG_USB_DC2XX
-	usb_dc2xx_init();
 #endif
 #ifdef CONFIG_USB_STORAGE
 	usb_stor_init();
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-storage-debug.h linux/drivers/usb/usb-storage-debug.h
--- v2.3.46/linux/drivers/usb/usb-storage-debug.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb-storage-debug.h	Sun Feb 20 16:20:47 2000
@@ -0,0 +1,88 @@
+#ifdef CONFIG_USB_STORAGE_DEBUG
+
+/* Debug output for Driver for USB mass storage (scsi-like) devices
+ * 
+ * (C) Michael Gee (michael@linuxspecific.com) 1999
+ *
+ */
+
+void us_show_command(Scsi_Cmnd *srb)
+{
+	char *what = NULL;
+
+	switch (srb->cmnd[0]) {
+	case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+	case REZERO_UNIT: what = "REZERO_UNIT"; break;
+	case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+	case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+	case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+	case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+	case READ_6: what = "READ_6"; break;
+	case WRITE_6: what = "WRITE_6"; break;
+	case SEEK_6: what = "SEEK_6"; break;
+	case READ_REVERSE: what = "READ_REVERSE"; break;
+	case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+	case SPACE: what = "SPACE"; break;
+	case INQUIRY: what = "INQUIRY"; break;
+	case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+	case MODE_SELECT: what = "MODE_SELECT"; break;
+	case RESERVE: what = "RESERVE"; break;
+	case RELEASE: what = "RELEASE"; break;
+	case COPY: what = "COPY"; break;
+	case ERASE: what = "ERASE"; break;
+	case MODE_SENSE: what = "MODE_SENSE"; break;
+	case START_STOP: what = "START_STOP"; break;
+	case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+	case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+	case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+	case SET_WINDOW: what = "SET_WINDOW"; break;
+	case READ_CAPACITY: what = "READ_CAPACITY"; break;
+	case READ_10: what = "READ_10"; break;
+	case WRITE_10: what = "WRITE_10"; break;
+	case SEEK_10: what = "SEEK_10"; break;
+	case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+	case VERIFY: what = "VERIFY"; break;
+	case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+	case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+	case SEARCH_LOW: what = "SEARCH_LOW"; break;
+	case SET_LIMITS: what = "SET_LIMITS"; break;
+	case READ_POSITION: what = "READ_POSITION"; break;
+	case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+	case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+	case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+	case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+	case COMPARE: what = "COMPARE"; break;
+	case COPY_VERIFY: what = "COPY_VERIFY"; break;
+	case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+	case READ_BUFFER: what = "READ_BUFFER"; break;
+	case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+	case READ_LONG: what = "READ_LONG"; break;
+	case WRITE_LONG: what = "WRITE_LONG"; break;
+	case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+	case WRITE_SAME: what = "WRITE_SAME"; break;
+	case READ_TOC: what = "READ_TOC"; break;
+	case LOG_SELECT: what = "LOG_SELECT"; break;
+	case LOG_SENSE: what = "LOG_SENSE"; break;
+	case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+	case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+	case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
+	case READ_12: what = "READ_12"; break;
+	case WRITE_12: what = "WRITE_12"; break;
+	case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+	case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+	case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+	case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+	case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+	case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+	case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+	default: break;
+	}
+	printk(KERN_DEBUG USB_STORAGE
+	       "Command %s (%d bytes)\n", what, srb->cmd_len);
+	printk(KERN_DEBUG USB_STORAGE 
+	       "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	       srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], 
+	       srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
+}
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c
--- v2.3.46/linux/drivers/usb/usb-storage.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb-storage.c	Sun Feb 20 16:20:47 2000
@@ -0,0 +1,1851 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Further reference:
+ *	This driver is based on the 'USB Mass Storage Class' document. This
+ *	describes in detail the protocol used to communicate with such
+ *      devices.  Clearly, the designers had SCSI commands in mind when they
+ *      created this document.  The commands are all similar to commands
+ *      in the SCSI-II specification.
+ *
+ *	It is important to note that in a number of cases this class exhibits
+ *	class-specific exemptions from the USB specification. Notably the
+ *	usage of NAK, STALL and ACK differs from the norm, in that they are
+ *	used to communicate wait, failed and OK on commands.
+ *	Also, for certain devices, the interrupt endpoint is used to convey
+ *	status of a command.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+#include <linux/blk.h>
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+
+#include "usb.h"
+#include "usb-storage.h"
+#include "usb-storage-debug.h"
+
+
+/*
+ * This is the size of the structure Scsi_Host_Template.  We create
+ * an instance of this structure in this file and this is a check
+ * to see if this structure may have changed within the SCSI module.
+ * This is by no means foolproof, but it does help us some.
+ */
+#define SCSI_HOST_TEMPLATE_SIZE			(104)
+
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
+unsigned char us_direction[256/8] = {
+	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
+	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+ * Per device data
+ */
+
+static int my_host_number;
+
+int usb_stor_debug = 1;
+
+struct us_data;
+
+typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
+typedef int (*trans_reset)(struct us_data*);
+typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
+
+struct us_data {
+	struct us_data	*next;		         /* next device */
+	struct usb_device	*pusb_dev;       /* this usb_device */
+	unsigned int		flags;		 /* from filter initially */
+	__u8			ifnum;		 /* interface number */
+	__u8			ep_in;		 /* in endpoint */
+	__u8			ep_out;		 /* out ....... */
+	__u8			ep_int;		 /* interrupt . */
+	__u8			subclass;	 /* as in overview */
+	__u8			protocol;	 /* .............. */
+	__u8			attention_done;  /* force attn on first cmd */
+	trans_cmnd              transport;	 /* protocol specific do cmd */
+	trans_reset             transport_reset; /* .......... device reset */
+	proto_cmnd              proto_handler;   /* protocol handler */
+	GUID(guid);				 /* unique dev id */
+	struct Scsi_Host	*host;		 /* our dummy host data */
+	Scsi_Host_Template	*htmplt;	 /* own host template */
+	int			host_number;	 /* to find us */
+	int			host_no;	 /* allocated by scsi */
+	Scsi_Cmnd		*srb;		 /* current srb */
+	int			action;		 /* what to do */
+	wait_queue_head_t	waitq;		 /* thread waits */
+	wait_queue_head_t	ip_waitq;	 /* for CBI interrupts */
+	__u16			ip_data;	 /* interrupt data */
+	int			ip_wanted;	 /* needed */
+	int			pid;		 /* control thread */
+	struct semaphore	*notify;	 /* wait for thread to begin */
+	void			*irq_handle;	 /* for USB int requests */
+	unsigned int		irqpipe;	 /* pipe for release_irq */
+};
+
+/*
+ * kernel thread actions
+ */
+
+#define US_ACT_COMMAND		1
+#define US_ACT_ABORT		2
+#define US_ACT_DEVICE_RESET	3
+#define US_ACT_BUS_RESET	4
+#define US_ACT_HOST_RESET	5
+
+static struct us_data *us_list;
+
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
+static void storage_disconnect(struct usb_device *dev, void *ptr);
+static struct usb_driver storage_driver = {
+	"usb-storage",
+	storage_probe,
+	storage_disconnect,
+	{ NULL, NULL }
+};
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+/* Transfer one buffer (breaking into packets if necessary)
+ * Note that this function is necessary because if the device NAKs, we
+ * need to know that information directly
+ *
+ * FIXME: is the above true?  Or will the URB status show ETIMEDOUT after
+ * retrying several times allready?  Perhaps this is the way we should
+ * be going anyway?
+ */
+static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
+{
+	int max_size;
+	int this_xfer;
+	int result;
+	int partial;
+	int maxtry;
+
+	/* determine the maximum packet size for these transfers */
+	max_size = usb_maxpacket(us->pusb_dev, 
+				 pipe, usb_pipeout(pipe)) * 16;
+
+	/* while we have data left to transfer */
+	while (length) {
+
+		/* calculate how long this will be -- maximum or a remainder */
+		this_xfer = length > max_size ? max_size : length;
+		length -= this_xfer;
+
+		/* FIXME: this number is totally outrageous.  We need to pick
+		 * a better (smaller) number).
+		 */
+
+		/* setup the retry counter */
+		maxtry = 100;
+
+		/* set up the transfer loop */
+		do {
+			/* transfer the data */
+			US_DEBUGP("Bulk xfer 0x%x(%d) try #%d\n", 
+				  (unsigned int)buf, this_xfer, 101 - maxtry);
+			result = usb_bulk_msg(us->pusb_dev, pipe, buf,
+					      this_xfer, &partial, HZ*5);
+			US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
+				  result, partial, this_xfer);
+
+			/* if we stall, we need to clear it before we go on */
+			if (result == -EPIPE) {
+				US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+				usb_clear_halt(us->pusb_dev, pipe);
+			}
+
+			/* update to show what data was transferred */
+			this_xfer -= partial;
+			buf += partial;
+
+			/* NAK - we retry a few times */
+			if (result == -ETIMEDOUT) {
+
+				US_DEBUGP("us_one_transfer: device NAKed\n");
+
+				/* if our try counter reaches 0, bail out */
+				if (!maxtry--)
+					return -ETIMEDOUT;
+
+				/* just continue the while loop */
+				continue;
+			}
+      
+			/* other errors (besides NAK) -- we just bail out*/
+			if (result != 0) {
+				US_DEBUGP("us_one_transfer: device returned error %d\n", result);
+				return result;
+			}
+
+			/* continue until this transfer is done */
+		} while ( this_xfer );
+	}
+
+	/* if we get here, we're done and successful */
+	return 0;
+}
+
+static unsigned int us_transfer_length(Scsi_Cmnd *srb);
+
+/* transfer one SCSI command, using scatter-gather if requested */
+/* FIXME: what do the return codes here mean? */
+static int us_transfer(Scsi_Cmnd *srb, int dir_in)
+{
+	struct us_data *us = (struct us_data *)srb->host_scribble;
+	int i;
+	int result = -1;
+	unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
+		usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+	/* FIXME: stop transferring data at us_transfer_length(), not 
+	 * bufflen */
+	if (srb->use_sg) {
+		struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
+
+		for (i = 0; i < srb->use_sg; i++) {
+			result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);
+			if (result)
+				break;
+		}
+	}
+	else
+		result = us_one_transfer(us, pipe, srb->request_buffer, 
+					 us_transfer_length(srb));
+
+	if (result < 0)
+		US_DEBUGP("us_transfer returning error %d\n", result);
+	return result;
+}
+
+/* calculate the length of the data transfer (not the command) for any
+ * given SCSI command
+ */
+static unsigned int us_transfer_length(Scsi_Cmnd *srb)
+{
+	int i;
+	unsigned int total = 0;
+
+	/* always zero for some commands */
+	switch (srb->cmnd[0]) {
+	case SEEK_6:
+	case SEEK_10:
+	case REZERO_UNIT:
+	case ALLOW_MEDIUM_REMOVAL:
+	case START_STOP:
+	case TEST_UNIT_READY:
+		return 0;
+
+	case REQUEST_SENSE:
+	case INQUIRY:
+	case MODE_SENSE:
+		return srb->cmnd[4];
+
+	case LOG_SENSE:
+	case MODE_SENSE_10:
+		return (srb->cmnd[7] << 8) + srb->cmnd[8];
+
+	default:
+		break;
+	}
+
+	if (srb->use_sg) {
+		struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
+
+		for (i = 0; i < srb->use_sg; i++) {
+			total += sg[i].length;
+		}
+		return total;
+	}
+	else
+		return srb->request_bufflen;
+}
+
+/***********************************************************************
+ * Protocol routines
+ ***********************************************************************/
+
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us);
+static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us);
+
+static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int old_cmnd = 0;
+  
+	/* fix some commands -- this is a form of mode translation
+	 * UFI devices only accept 12 byte long commands 
+	 *
+	 * NOTE: This only works because a Scsi_Cmnd struct field contains
+	 * a unsigned char cmnd[12], so we know we have storage available
+	 */
+
+	/* set command length to 12 bytes (this affects the transport layer) */
+	srb->cmd_len = 12;
+
+	/* determine the correct (or minimum) data length for these commands */
+	switch (us->srb->cmnd[0]) {
+
+		/* for INQUIRY, UFI devices only ever return 36 bytes */
+	case INQUIRY:
+		us->srb->cmnd[4] = 36;
+		break;
+
+		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+	case MODE_SENSE:
+	case MODE_SELECT:
+		/* save the command so we can tell what it was */
+		old_cmnd = srb->cmnd[0];
+
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+
+		/* if we're sending data, we send all.  If getting data, 
+		 * get the minimum */
+		if (srb->cmnd[0] == MODE_SELECT)
+			srb->cmnd[8] = srb->cmnd[4];
+		else
+			srb->cmnd[8] = 8;
+
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = 0;
+		srb->cmnd[4] = 0;
+		srb->cmnd[3] = 0;
+		srb->cmnd[2] = srb->cmnd[2];
+		srb->cmnd[1] = srb->cmnd[1];
+		srb->cmnd[0] = srb->cmnd[0] | 0x40;
+		break;
+
+		/* again, for MODE_SENSE_10, we get the minimum (8) */
+	case MODE_SENSE_10:
+		us->srb->cmnd[7] = 0;
+		us->srb->cmnd[8] = 8;
+		break;
+ 
+		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
+	case REQUEST_SENSE:
+		us->srb->cmnd[4] = 18;
+		break;
+
+		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
+		 * are UFI commands */
+	case WRITE_6:
+	case READ_6:
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+		srb->cmnd[8] = srb->cmnd[4];
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = srb->cmnd[3];
+		srb->cmnd[4] = srb->cmnd[2];
+		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+		srb->cmnd[2] = 0;
+		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+		srb->cmnd[0] = srb->cmnd[0] | 0x20;
+		break;
+	} /* end switch on cmnd[0] */
+  
+	/* send the command to the transport layer */
+	us->srb->result = us->transport(srb, us);
+
+	/* if we have an error, we're going to do a 
+	 * REQUEST_SENSE automatically */
+
+	/* FIXME: we should only do this for device 
+	 * errors, not system errors */
+	if (us->srb->result) {
+		int temp_result;
+		int count;
+		void* old_request_buffer;
+
+		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+
+		/* set the result so the higher layers expect this data */
+		us->srb->result = CHECK_CONDITION;
+
+		us->srb->cmnd[0] = REQUEST_SENSE;
+		us->srb->cmnd[1] = 0;
+		us->srb->cmnd[2] = 0;
+		us->srb->cmnd[3] = 0;
+		us->srb->cmnd[4] = 18;
+		us->srb->cmnd[5] = 0;
+    
+		/* set the buffer length for transfer */
+		old_request_buffer = us->srb->request_buffer;
+		us->srb->request_bufflen = 18;
+		us->srb->request_buffer = kmalloc(18, GFP_KERNEL);
+
+		/* FIXME: what if this command fails? */
+		temp_result = us->transport(us->srb, us);
+		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+
+		/* copy the data from the request buffer to the sense buffer */
+		for(count = 0; count < 18; count++)
+			us->srb->sense_buffer[count] = 
+				((unsigned char *)(us->srb->request_buffer))[count];
+
+		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+			  us->srb->sense_buffer[2] & 0xf,
+			  us->srb->sense_buffer[12], us->srb->sense_buffer[13]);
+
+		/* we're done here */
+		kfree(us->srb->request_buffer);
+		us->srb->request_buffer = old_request_buffer;
+		return;
+	}
+  
+	/* FIXME: if we need to send more data, or recieve data, we should
+	 * do it here.  Then, we can do status handling here also.
+	 *
+	 * This includes MODE_SENSE from above
+	 */
+	if (old_cmnd == MODE_SENSE) {
+		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+
+		/* calculate the new length */
+		int length = (dta[0] << 8) + dta[1] + 2;
+
+		/* copy the available data length into the structure */
+		us->srb->cmnd[7] = length >> 8;
+		us->srb->cmnd[8] = length & 0xFF;
+
+		/* send the command to the transport layer */
+		us->srb->result = us->transport(srb, us);
+
+		/* FIXME: this assumes that the 2nd attempt is always
+		 * successful convert MODE_SENSE_10 return data format 
+		 * to MODE_SENSE_6 format */
+		dta[0] = dta[1];	/* data len */
+		dta[1] = dta[2];	/* med type */
+		dta[2] = dta[3];	/* dev-spec prm */
+		dta[3] = dta[7];	/* block desc len */
+		printk (KERN_DEBUG USB_STORAGE
+			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+			dta[0], dta[1], dta[2], dta[3]);
+	}
+
+	/* FIXME: if this was a TEST_UNIT_READY, and we get a NOT READY/
+	 * LOGICAL DRIVE NOT READY then we do a START_STOP, and retry 
+	 */
+
+	/* FIXME: here is where we need to fix-up the return data from 
+	 * an INQUIRY command to show ANSI SCSI rev 2
+	 */
+
+	/* FIXME: The rest of this is bogus.  usb_control_msg() will only
+	 * return an error if we've really honked things up.  If it just
+	 * needs a START_STOP, then we'll get some data back via 
+	 * REQUEST_SENSE --  either way, this belongs at a higher level
+	 */
+
+#if 0
+	/* For UFI, if this is the first time we've sent this TEST_UNIT_READY 
+	 * command, we can try again
+	 */
+	if (!done_start && (us->subclass == US_SC_UFI)
+	    && (cmd[0] == TEST_UNIT_READY) && (result < 0)) {
+    
+		/* as per spec try a start command, wait and retry */
+		wait_ms(100);
+    
+		done_start++;
+		memset(cmd, 0, sizeof(cmd));
+		cmd[0] = START_STOP;
+		cmd[4] = 1;		/* start */
+    
+		result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+					 US_CBI_ADSC, 
+					 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+					 0, us->ifnum,
+					 cmd, 12, HZ*5);
+		US_DEBUGP("Next usb_control_msg returns %d\n", result);
+    
+				/* allow another retry */
+		retry++;
+		continue;
+	}
+#endif
+}
+
+static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	unsigned int savelen = us->srb->request_bufflen;
+	unsigned int saveallocation = 0;
+
+#if 0
+	/* force attention on first command */
+	if (!us->attention_done) {
+		if (us->srb->cmnd[0] == REQUEST_SENSE) {
+			US_DEBUGP("forcing unit attention\n");
+			us->attention_done = 1;
+
+			if (us->srb->result == USB_STOR_TRANSPORT_GOOD) {
+				unsigned char *p = (unsigned char *)us->srb->request_buffer;
+	
+				if ((p[2] & 0x0f) != UNIT_ATTENTION) {
+					p[2] = UNIT_ATTENTION;
+					p[12] = 0x29;	/* power on, reset or bus-reset */
+					p[13] = 0;
+				} /* if ((p[2] & 0x0f) != UNIT_ATTENTION) */
+			} /* if (us->srb->result == USB_STORE_TRANSPORT_GOOD) */
+		}
+	} /* if (!us->attention_done) */
+#endif
+
+	/* If the command has a variable-length payload, then we do them
+	 * in two steps -- first we do the minimum, then we recalculate
+	 * then length, and re-issue the command 
+	 *
+	 * we use savelen to remember how much buffer we really have
+	 * we use savealloction to remember how much was really requested
+	 */
+
+	/* FIXME: remove savelen based on mods to us_transfer_length() */
+	switch (us->srb->cmnd[0]) {
+	case REQUEST_SENSE:
+		if (us->srb->request_bufflen > 18)
+			us->srb->request_bufflen = 18;
+		else
+			break;
+		saveallocation = us->srb->cmnd[4];
+		us->srb->cmnd[4] = 18;
+		break;
+    
+	case INQUIRY:
+		if (us->srb->request_bufflen > 36)
+			us->srb->request_bufflen = 36;
+		else
+			break;
+		saveallocation = us->srb->cmnd[4];
+		us->srb->cmnd[4] = 36;
+		break;
+    
+	case MODE_SENSE:
+		if (us->srb->request_bufflen > 4)
+			us->srb->request_bufflen = 4;
+		else
+			break;
+		saveallocation = us->srb->cmnd[4];
+		us->srb->cmnd[4] = 4;
+		break;
+    
+	case LOG_SENSE:
+	case MODE_SENSE_10:
+		if (us->srb->request_bufflen > 8)
+			us->srb->request_bufflen = 8;
+		else
+			break;
+		saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8];
+		us->srb->cmnd[7] = 0;
+		us->srb->cmnd[8] = 8;
+		break;
+    
+	default:
+		break;
+	} /* end switch on cmnd[0] */
+  
+	/* This code supports devices which do not support {READ|WRITE}_6
+	 * Apparently, neither Windows or MacOS will use these commands,
+	 * so some devices do not support them
+	 */
+	if (us->flags & US_FL_MODE_XLATE) {
+    
+		/* translate READ_6 to READ_10 */
+		if (us->srb->cmnd[0] == 0x08) {
+      
+			/* get the control */
+			us->srb->cmnd[9] = us->srb->cmnd[5];
+      
+			/* get the length */
+			us->srb->cmnd[8] = us->srb->cmnd[6];
+			us->srb->cmnd[7] = 0;
+      
+			/* set the reserved area to 0 */
+			us->srb->cmnd[6] = 0;	    
+      
+			/* get LBA */
+			us->srb->cmnd[5] = us->srb->cmnd[3];
+			us->srb->cmnd[4] = us->srb->cmnd[2];
+			us->srb->cmnd[3] = 0;
+			us->srb->cmnd[2] = 0;
+      
+			/* LUN and other info in cmnd[1] can stay */
+      
+			/* fix command code */
+			us->srb->cmnd[0] = 0x28;
+      
+			US_DEBUGP("Changing READ_6 to READ_10\n");
+			US_DEBUG(us_show_command(us->srb));
+		}
+    
+		/* translate WRITE_6 to WRITE_10 */
+		if (us->srb->cmnd[0] == 0x0A) {
+      
+			/* get the control */
+			us->srb->cmnd[9] = us->srb->cmnd[5];
+      
+			/* get the length */
+			us->srb->cmnd[8] = us->srb->cmnd[4];
+			us->srb->cmnd[7] = 0;
+      
+			/* set the reserved area to 0 */
+			us->srb->cmnd[6] = 0;	    
+      
+			/* get LBA */
+			us->srb->cmnd[5] = us->srb->cmnd[3];
+			us->srb->cmnd[4] = us->srb->cmnd[2];
+			us->srb->cmnd[3] = 0;
+			us->srb->cmnd[2] = 0;
+	    
+			/* LUN and other info in cmnd[1] can stay */
+      
+			/* fix command code */
+			us->srb->cmnd[0] = 0x2A;
+
+			US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
+			US_DEBUG(us_show_command(us->srb));
+		}
+	} /* end if (us->flags & US_FL_MODE_XLATE) */
+  
+	/* send the command to the transport layer */
+	us->srb->result = us->transport(us->srb, us);
+
+	/* if we have an error, we're going to do a REQUEST_SENSE 
+	 * automatically */
+	/* FIXME: we should only do this for device errors, not 
+	 * system errors */
+	if (us->srb->result) {
+		int temp_result;
+		int count;
+		void* old_request_buffer;
+
+		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+
+		/* set the result so the higher layers expect this data */
+		us->srb->result = CHECK_CONDITION;
+
+		us->srb->cmnd[0] = REQUEST_SENSE;
+		us->srb->cmnd[1] = 0;
+		us->srb->cmnd[2] = 0;
+		us->srb->cmnd[3] = 0;
+		us->srb->cmnd[4] = 18;
+		us->srb->cmnd[5] = 0;
+    
+		/* set the buffer length for transfer */
+		old_request_buffer = us->srb->request_buffer;
+		us->srb->request_bufflen = 18;
+		us->srb->request_buffer = kmalloc(18, GFP_KERNEL);
+
+		/* FIXME: what if this command fails? */
+		temp_result = us->transport(us->srb, us);
+		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+
+		/* copy the data from the request buffer to the sense buffer */
+		for(count = 0; count < 18; count++)
+			us->srb->sense_buffer[count] = 
+				((unsigned char *)(us->srb->request_buffer))[count];
+
+		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+			  us->srb->sense_buffer[2] & 0xf,
+			  us->srb->sense_buffer[12], us->srb->sense_buffer[13]);
+
+		/* we're done here */
+		kfree(us->srb->request_buffer);
+		us->srb->request_buffer = old_request_buffer;
+		return;
+	}
+
+	if (savelen != us->srb->request_bufflen) {
+		unsigned char *p = (unsigned char *)us->srb->request_buffer;
+		unsigned int length = 0;
+    
+		/* set correct length and retry */
+		switch (us->srb->cmnd[0]) {
+
+			/* FIXME: we should try to get all the sense data */
+		case REQUEST_SENSE:
+			/* simply return 18 bytes */
+			p[7] = 10;
+			length = us->srb->request_bufflen;
+			break;
+      
+		case INQUIRY:
+			length = p[4] + 5 > savelen ? savelen : p[4] + 5;
+			us->srb->cmnd[4] = length;
+			break;
+      
+		case MODE_SENSE:
+			US_DEBUGP("MODE_SENSE Mode data length is %d\n", p[0]);
+			length = p[0] + 1 > savelen ? savelen : p[0] + 1;
+			us->srb->cmnd[4] = length;
+			break;
+      
+		case LOG_SENSE:
+			length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4;
+			us->srb->cmnd[7] = length >> 8;
+			us->srb->cmnd[8] = length;
+			break;
+      
+		case MODE_SENSE_10:
+			US_DEBUGP("MODE_SENSE_10 Mode data length is %d\n",
+				  (p[0] << 8) + p[1]);
+			length = ((p[0] << 8) + p[1]) + 6 > savelen ? savelen : ((p[0] << 8) + p[1]) + 6;
+			us->srb->cmnd[7] = length >> 8;
+			us->srb->cmnd[8] = length;
+			break;
+		} /* end switch on cmnd[0] */
+    
+		US_DEBUGP("Old/New length = %d/%d\n",
+			  savelen, length);
+    
+		/* issue the new command */
+		/* FIXME: this assumes that the second attempt is 
+		 * always successful */
+		if (us->srb->request_bufflen != length) {
+			US_DEBUGP("redoing cmd with len=%d\n", length);
+			us->srb->request_bufflen = length;
+			us->srb->result = us->transport(us->srb, us);
+		}
+    
+		/* reset back to original values */
+		us->srb->request_bufflen = savelen;
+
+		/* fix data as necessary */
+		switch (us->srb->cmnd[0]) {
+		case INQUIRY:
+			if ((((unsigned char*)us->srb->request_buffer)[2] & 0x7) == 0) { 
+				US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
+				((unsigned char*)us->srb->request_buffer)[2] |= 2;
+			}
+			/* FALL THROUGH */
+		case REQUEST_SENSE:
+		case MODE_SENSE:
+			if (us->srb->use_sg == 0 && length > 0) {
+				int i;
+				printk(KERN_DEBUG "Data is");
+				for (i = 0; i < 32 && i < length; ++i)
+					printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]);
+				if (i < length)
+					printk(" ...");
+				printk("\n");
+			}
+
+			/* FIXME: is this really necessary? */
+			us->srb->cmnd[4] = saveallocation;
+			break;
+      
+		case LOG_SENSE:
+		case MODE_SENSE_10:
+			/* FIXME: is this really necessary? */
+			us->srb->cmnd[7] = saveallocation >> 8;
+			us->srb->cmnd[8] = saveallocation;
+			break;
+		} /* end switch on cmnd[0] */
+	} /* if good command */
+}
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+static int CBI_irq(int state, void *buffer, int len, void *dev_id)
+{
+	struct us_data *us = (struct us_data *)dev_id;
+
+	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+
+	/* save the data for interpretation later */
+	if (state != USB_ST_REMOVED) {
+		us->ip_data = le16_to_cpup((__u16 *)buffer);
+		US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data);
+	}
+  
+	/* was this a wanted interrupt? */
+	if (us->ip_wanted) {
+		us->ip_wanted = 0;
+		wake_up(&us->ip_waitq);
+	} else {
+		US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+	}
+
+	/* This return code is truly meaningless -- and I mean truly.  It gets
+	 * ignored by other layers.  It used to indicate if we wanted to get
+	 * another interrupt or disable the interrupt callback
+	 */
+	return 0;
+}
+
+/* FIXME: this reset function doesn't really reset the port, and it
+ * should. Actually it should probably do what it's doing here, and
+ * reset the port physically
+ */
+static int CB_reset(struct us_data *us)
+{
+	unsigned char cmd[12];
+	int result;
+
+	US_DEBUGP("CB_reset\n");
+
+	memset(cmd, 0xFF, sizeof(cmd));
+	cmd[0] = SEND_DIAGNOSTIC;
+	cmd[1] = 4;
+	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+				 US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
+
+	/* long wait for reset */
+	schedule_timeout(HZ*6);
+
+	US_DEBUGP("CB_reset: clearing endpoint halt\n");
+	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+
+	US_DEBUGP("CB_reset done\n");
+	return 0;
+}
+
+static int pop_CB_status(Scsi_Cmnd *srb);
+
+/* FIXME: we also need a CBI_command which sets up the completion
+ * interrupt, and waits for it
+ */
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int result;
+
+	US_DEBUGP("CBI gets a command:\n");
+	US_DEBUG(us_show_command(srb));
+
+	/* FIXME: we aren't setting the ip_wanted indicator early enough, which
+	 * causes some commands to never complete.  This hangs the driver.
+	 */
+
+	/* let's send the command via the control pipe */
+	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+				 US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum,
+				 srb->cmnd, srb->cmd_len, HZ*5);
+
+	/* check the return code for the command */
+	if (result < 0) {
+		US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+
+		/* a stall is a fatal condition from the device */
+		if (result == -EPIPE) {
+			US_DEBUGP("-- Stall on control pipe detected. Clearing\n");
+      
+			US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
+				  usb_clear_halt(us->pusb_dev, 
+						 usb_sndctrlpipe(us->pusb_dev, 0)));
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		/* FIXME: we need to handle NAKs here */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* transfer the data payload for this command, if one exists*/
+	if (us_transfer_length(srb)) {
+		result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+		US_DEBUGP("CBI attempted to transfer data, result is 0x%x\n", result);
+
+		/* FIXME: what do the return codes from us_transfer mean? */
+		if ((result < 0) && 
+		    (result != USB_ST_DATAUNDERRUN) && 
+		    (result != USB_ST_STALL)) {
+			return DID_ERROR << 16;
+		}
+	} /* if (us_transfer_length(srb)) */
+
+	/* get status and return it */
+	return pop_CB_status(srb);
+}
+
+/*
+ * Control/Bulk status handler
+ */
+
+static int pop_CB_status(Scsi_Cmnd *srb)
+{
+	struct us_data *us = (struct us_data *)srb->host_scribble;
+	int result = 0;
+	__u8 status[2];
+	int retry = 5;
+
+	US_DEBUGP("pop_CB_status, proto=0x%x\n", us->protocol);
+	switch (us->protocol) {
+	case US_PR_CB:
+		/* get from control */
+
+		while (retry--) {
+			result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0),
+						 USB_REQ_GET_STATUS, USB_DIR_IN |
+						 USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+						 0, us->ifnum, status, sizeof(status), HZ*5);
+			if (result != USB_ST_TIMEOUT)
+				break;
+		}
+		if (result) {
+			US_DEBUGP("Bad AP status request %d\n", result);
+			return DID_ABORT << 16;
+		}
+		US_DEBUGP("Got AP status 0x%x 0x%x\n", status[0], status[1]);
+		if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
+		    ( (status[0] & ~3) || status[1]))
+			return (DID_OK << 16) | 2;
+		else
+			return USB_STOR_TRANSPORT_GOOD;
+		break;
+
+		/* FIXME: this should be in a separate function */
+	case US_PR_CBI:
+		/* get from interrupt pipe */
+
+		/* add interrupt transfer, marked for removal */
+		us->ip_wanted = 1;
+
+		/* go to sleep until we get this interrup */
+		/* FIXME: this should be changed to use a timeout */
+		sleep_on(&us->ip_waitq);
+    
+		if (us->ip_wanted) {
+			US_DEBUGP("Did not get interrupt on CBI\n");
+			us->ip_wanted = 0;
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+    
+		US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+
+		/* UFI gives us ASC and ASCQ, like a request sense */
+		/* FIXME: is this right?  do REQUEST_SENSE and INQUIRY need special
+		 * case handling?
+		 */
+		if (us->subclass == US_SC_UFI) {
+			if (srb->cmnd[0] == REQUEST_SENSE ||
+			    srb->cmnd[0] == INQUIRY)
+				return USB_STOR_TRANSPORT_GOOD;
+			else
+				if (us->ip_data)
+					return USB_STOR_TRANSPORT_FAILED;
+				else
+					return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		/* otherwise, we interpret the data normally */
+		switch (us->ip_data) {
+		case 0x0001: 
+			return USB_STOR_TRANSPORT_GOOD;
+		case 0x0002: 
+			return USB_STOR_TRANSPORT_FAILED;
+		default: 
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+	}
+	US_DEBUGP("pop_CB_status, reached end of function\n");
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+static int Bulk_reset(struct us_data *us)
+{
+	int result;
+
+	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+				 US_BULK_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 US_BULK_RESET_HARD, us->ifnum,
+				 NULL, 0, HZ*5);
+	if (result)
+		US_DEBUGP("Bulk hard reset failed %d\n", result);
+	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+
+	/* long wait for reset */
+	schedule_timeout(HZ*6);
+
+	return result;
+}
+
+/*
+ * The bulk only protocol handler.
+ *	Uses the in and out endpoints to transfer commands and data
+ */
+static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	struct bulk_cb_wrap bcb;
+	struct bulk_cs_wrap bcs;
+	int result;
+	int pipe;
+	int partial;
+
+	/* set up the command wrapper */
+	bcb.Signature = US_BULK_CB_SIGN;
+	bcb.DataTransferLength = us_transfer_length(srb);
+	bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+	bcb.Tag = srb->serial_number;
+	bcb.Lun = 0;
+	bcb.Length = srb->cmd_len;
+
+	/* construct the pipe handle */
+	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+	/* copy the command payload */
+	memset(bcb.CDB, 0, sizeof(bcb.CDB));
+	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+
+	/* send it to out endpoint */
+	US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n",
+		  bcb.Signature, bcb.Tag, bcb.DataTransferLength,
+		  bcb.Flags, bcb.Length);
+	result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
+			      US_BULK_CB_WRAP_LEN, &partial, HZ*5);
+	US_DEBUGP("Bulk command transfer result=%d\n", result);
+
+	/* if we stall, we need to clear it before we go on */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
+  
+	/* if the command transfered well, then we go to the data stage */
+	/* FIXME: Regardless of the status of the data stage, we go on to the
+	 * status stage.  Note that this implies that if a command is
+	 * partially successful, we rely on the device reporting an error
+	 * the CSW. The spec says that the device may just decide to short us.
+	 */
+	if (result == 0) {
+		/* send/receive data payload, if there is any */
+		if (bcb.DataTransferLength) {
+			result = us_transfer(srb, bcb.Flags);
+			US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+#if 0
+			if ((result < 0) && (result != USB_ST_DATAUNDERRUN) 
+			    && (result != USB_ST_STALL)) {
+				US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+				return DID_ABORT << 16;
+			}
+#endif
+		}
+	}
+
+	/* See flow chart on pg 15 of the Bulk Only Transport spec for
+	 * an explanation of how this code works.
+	 */
+
+	/* construct the pipe handle */
+	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+
+	/* get CSW for device status */
+	result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+			      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+
+	/* did the attempt to read the CSW fail? */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
+
+		/* get the status again */
+		result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+				      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+   
+		/* if it fails again, we need a reset and return an error*/
+		if (result == -EPIPE) {
+			Bulk_reset(us);
+			return (DID_ABORT << 16);
+		}
+	}
+
+	/* if we still have a failure at this point, we're in trouble */
+	if (result) {
+		US_DEBUGP("Bulk status result = 0x%x\n", result);
+		return DID_ABORT << 16;
+	}
+
+	/* check bulk status */
+	US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+		  bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
+	if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
+	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+		US_DEBUGP("Bulk logical error\n");
+		return DID_ABORT << 16;
+	}
+
+	/* based on the status code, we report good or bad */
+	switch (bcs.Status) {
+	case US_BULK_STAT_OK:
+		/* if there is residue, we really didn't finish the command */
+		if (bcs.Residue)
+			return DID_ERROR << 16;
+		else
+			return DID_OK << 16;
+
+	case US_BULK_STAT_FAIL:
+		return DID_ERROR << 16;
+
+	case US_BULK_STAT_PHASE:
+		Bulk_reset(us);
+		return DID_ERROR << 16;
+	}
+
+	return DID_OK << 16;	    /* check sense required */
+}
+
+/***********************************************************************
+ * Host functions 
+ ***********************************************************************/
+
+/* detect adapter (always true ) */
+static int us_detect(struct SHT *sht)
+{
+	/* FIXME - not nice at all, but how else ? */
+	struct us_data *us = (struct us_data *)sht->proc_dir;
+	char name[32];
+
+	/* set up our name */
+	sprintf(name, "usbscsi%d", us->host_number);
+	sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
+	if (!sht->proc_name)
+		return 0;
+	strcpy(sht->proc_name, name);
+
+	/* we start with no /proc directory entry */
+	sht->proc_dir = NULL;
+
+	/* register the host */
+	us->host = scsi_register(sht, sizeof(us));
+	if (us->host) {
+		us->host->hostdata[0] = (unsigned long)us;
+		us->host_no = us->host->host_no;
+		return 1;
+	}
+
+	/* odd... didn't register properly.  Abort and free pointers */
+	kfree(sht->proc_name);
+	sht->proc_name = NULL;
+	sht->name = NULL;
+	return 0;
+}
+
+/* release - must be here to stop scsi
+ *	from trying to release IRQ etc.
+ *	Kill off our data
+ */
+static int us_release(struct Scsi_Host *psh)
+{
+	struct us_data *us = (struct us_data *)psh->hostdata[0];
+	struct us_data *prev = (struct us_data *)&us_list;
+
+	if (us->irq_handle) {
+		usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
+		us->irq_handle = NULL;
+	}
+	if (us->pusb_dev)
+		usb_deregister(&storage_driver);
+
+	/* FIXME - leaves hanging host template copy */
+	/* (because scsi layer uses it after removal !!!) */
+	while (prev->next != us)
+		prev = prev->next;
+	prev->next = us->next;
+	return 0;
+}
+
+/* run command */
+static int us_command( Scsi_Cmnd *srb )
+{
+	US_DEBUGP("Bad use of us_command\n");
+
+	return DID_BAD_TARGET << 16;
+}
+
+/* run command */
+static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
+{
+	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+	US_DEBUGP("Command wakeup\n");
+	if (us->srb) {
+		/* busy */
+	}
+	srb->host_scribble = (unsigned char *)us;
+	us->srb = srb;
+	srb->scsi_done = done;
+	us->action = US_ACT_COMMAND;
+
+	/* wake up the process task */
+
+	wake_up_interruptible(&us->waitq);
+
+	return 0;
+}
+
+/* FIXME: This doesn't actually abort anything */
+static int us_abort( Scsi_Cmnd *srb )
+{
+	return 0;
+}
+
+static int us_bus_reset( Scsi_Cmnd *srb )
+{
+	//  struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+	US_DEBUGP("Bus reset requested\n");
+	//  us->transport_reset(us);
+	return SUCCESS;
+}
+
+/* FIXME: This doesn't actually reset anything */
+static int us_host_reset( Scsi_Cmnd *srb )
+{
+	return 0;
+}
+
+/***********************************************************************
+ * /proc/scsi/ functions
+ ***********************************************************************/
+
+/* we use this macro to help us write into the buffer */
+#undef SPRINTF
+#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0)
+
+int usb_stor_proc_info (char *buffer, char **start, off_t offset, 
+			int length, int hostno, int inout)
+{
+	struct us_data *us = us_list;
+	char *pos = buffer;
+	char *tmp_ptr;
+
+	/* find our data from hostno */
+	while (us) {
+		if (us->host_no == hostno)
+			break;
+		us = us->next;
+	}
+
+	/* if we couldn't find it, we return an error */
+	if (!us)
+		return -ESRCH;
+
+	/* if someone is sending us data, just throw it away */
+	if (inout)
+		return length;
+
+	/* print the controler name */
+	SPRINTF ("Host scsi%d: usb-storage\n", hostno);
+
+	/* print product and vendor strings */
+	tmp_ptr = kmalloc(256, GFP_KERNEL);
+	if (!us->pusb_dev || !tmp_ptr) {
+		SPRINTF("    Vendor: Unknown Vendor\n");
+		SPRINTF("   Product: Unknown Product\n");
+	} else {
+		SPRINTF("    Vendor: ");
+		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0)
+			SPRINTF("%s\n", tmp_ptr);
+		else
+			SPRINTF("Unknown Vendor\n");
+    
+		SPRINTF("   Product: ");
+		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0)
+			SPRINTF("%s\n", tmp_ptr);
+		else
+			SPRINTF("Unknown Product\n");
+		kfree(tmp_ptr);
+	}
+
+	SPRINTF("  Protocol: ");
+	switch (us->protocol) {
+	case US_PR_CB:
+		SPRINTF("Control/Bulk\n");
+		break;
+    
+	case US_PR_CBI:
+		SPRINTF("Control/Bulk/Interrupt\n");
+		break;
+    
+	case US_PR_BULK:
+		SPRINTF("Bulk only\n");
+		break;
+    
+	default:
+		SPRINTF("Unknown Protocol\n");
+		break;
+	}
+
+	/* show the GUID of the device */
+	SPRINTF("      GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
+
+	/*
+	 * Calculate start of next buffer, and return value.
+	 */
+	*start = buffer + offset;
+
+	if ((pos - buffer) < offset)
+		return (0);
+	else if ((pos - buffer - offset) < length)
+		return (pos - buffer - offset);
+	else
+		return (length);
+}
+
+/*
+ * this defines our 'host'
+ */
+
+static Scsi_Host_Template my_host_template = {
+	NULL,			    /* next */
+	NULL,			    /* module */
+	NULL,			    /* proc_dir */
+	usb_stor_proc_info,
+	NULL,			    /* name - points to unique */
+	us_detect,
+	us_release,
+	NULL,			    /* info */
+	NULL,			    /* ioctl */
+	us_command,
+	us_queuecommand,
+	NULL,			    /* eh_strategy */
+	us_abort,
+	us_bus_reset,
+	us_bus_reset,
+	us_host_reset,
+	NULL,			    /* abort */
+	NULL,			    /* reset */
+	NULL,			    /* slave_attach */
+	NULL,			    /* bios_param */
+	NULL,			    /* select_queue_depths */
+	1,			    /* can_queue */
+	-1,			    /* this_id */
+	SG_ALL,		    /* sg_tablesize */
+	1,			    /* cmd_per_lun */
+	0,			    /* present */
+	FALSE,		    /* unchecked_isa_dma */
+	FALSE,		    /* use_clustering */
+	TRUE,			    /* use_new_eh_code */
+	TRUE			    /* emulated */
+};
+
+static unsigned char sense_notready[] = {
+	0x70,			    /* current error */
+	0x00,
+	0x02,			    /* not ready */
+	0x00,
+	0x00,
+	0x0a,			    /* additional length */
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x04,			    /* not ready */
+	0x03,			    /* manual intervention */
+	0x00,
+	0x00,
+	0x00,
+	0x00
+};
+
+static int usb_stor_control_thread(void * __us)
+{
+	struct us_data *us = (struct us_data *)__us;
+	int action;
+
+	lock_kernel();
+
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources..
+	 */
+	daemonize();
+
+	sprintf(current->comm, "usbscsi%d", us->host_number);
+
+	unlock_kernel();
+
+	up(us->notify);
+
+	for(;;) {
+		siginfo_t info;
+		int unsigned long signr;
+
+		interruptible_sleep_on(&us->waitq);
+
+		action = us->action;
+		us->action = 0;
+
+		/* FIXME: we need to examine placment of break; and 
+		 * scsi_done() calls */
+
+		switch (action) {
+		case US_ACT_COMMAND:
+			/* bad device */
+			if (us->srb->target || us->srb->lun) {
+				US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
+					   us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
+				us->srb->result = DID_BAD_TARGET << 16;
+
+				us->srb->scsi_done(us->srb);
+				us->srb = NULL;
+				break;
+			}
+
+			/* our device has gone - pretend not ready */
+			/* FIXME: we also need to handle INQUIRY here, 
+			 * probably */
+			if (!us->pusb_dev) {
+				if (us->srb->cmnd[0] == REQUEST_SENSE) {
+					memcpy(us->srb->request_buffer, sense_notready, 
+					       sizeof(sense_notready));
+					us->srb->result = DID_OK << 16;
+				} else {
+					us->srb->result = (DID_OK << 16) | 2;
+				}
+
+				us->srb->scsi_done(us->srb);
+				us->srb = NULL;
+				break;
+			}
+
+			/* we've got a command, let's do it! */
+			US_DEBUG(us_show_command(us->srb));
+
+			/* FIXME: this is to support Shuttle E-USB bridges, it 
+			 * appears */
+			if (us->srb->cmnd[0] == START_STOP &&
+			    us->pusb_dev->descriptor.idProduct == 0x0001 &&
+			    us->pusb_dev->descriptor.idVendor == 0x04e6)
+				us->srb->result = DID_OK << 16;
+			else {
+				us->proto_handler(us->srb, us);
+			}
+      
+			US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result);
+			us->srb->scsi_done(us->srb);
+			us->srb = NULL;
+			break;
+      
+		case US_ACT_ABORT:
+			break;
+
+		case US_ACT_DEVICE_RESET:
+			break;
+
+		case US_ACT_BUS_RESET:
+			break;
+
+		case US_ACT_HOST_RESET:
+			break;
+
+		} /* end switch on action */
+    
+		if (signal_pending(current)) {
+			/* sending SIGUSR1 makes us print out some info */
+			spin_lock_irq(&current->sigmask_lock);
+			signr = dequeue_signal(&current->blocked, &info);
+			spin_unlock_irq(&current->sigmask_lock);
+
+			if (signr == SIGUSR2) {
+				usb_stor_debug = !usb_stor_debug;
+				printk(USB_STORAGE "debug toggle = %d\n", usb_stor_debug);
+			} else {
+				break;	    /* exit the loop on any other signal */
+			}
+		}
+	}
+  
+	//  MOD_DEC_USE_COUNT;
+
+	printk("usb_stor_control_thread exiting\n");
+
+	/* FIXME: this is a hack to allow for debugging */
+	// scsi_unregister_module(MODULE_SCSI_HA, us->htmplt);
+
+	return 0;
+}	
+
+/* Probe to see if a new device is actually a SCSI device */
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	int i;
+	char mf[32];		     /* manufacturer */
+	char prod[32];		     /* product */
+	char serial[32];       	     /* serial number */
+	struct us_data *ss = NULL;
+	unsigned int flags = 0;
+	GUID(guid);		     /* Global Unique Identifier */
+	struct us_data *prev;
+	Scsi_Host_Template *htmplt;
+	int protocol = 0;
+	int subclass = 0;
+	struct usb_interface_descriptor *altsetting = 
+		&(dev->actconfig->interface[ifnum].altsetting[0]); 
+
+	/* clear the GUID and fetch the strings */
+	GUID_CLEAR(guid);
+	memset(mf, 0, sizeof(mf));
+	memset(prod, 0, sizeof(prod));
+	memset(serial, 0, sizeof(serial));
+	if (dev->descriptor.iManufacturer)
+		usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf));
+	if (dev->descriptor.iProduct)
+		usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod));
+	if (dev->descriptor.iSerialNumber)
+		usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial));
+	
+	/* let's examine the device now */
+
+	/* We make an exception for the shuttle E-USB */
+	if (dev->descriptor.idVendor == 0x04e6 &&
+	    dev->descriptor.idProduct == 0x0001) {
+		protocol = US_PR_CB;
+		subclass = US_SC_8070;	    /* an assumption */
+	} else if (dev->descriptor.bDeviceClass != 0 ||
+		   altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
+		   altsetting->bInterfaceSubClass < US_SC_MIN ||
+		   altsetting->bInterfaceSubClass > US_SC_MAX) {
+		/* if it's not a mass storage, we go no further */
+		return NULL;
+	}
+
+	/* At this point, we know we've got a live one */
+	US_DEBUGP("USB Mass Storage device detected\n");
+
+	/* Create a GUID for this device */
+	if (dev->descriptor.iSerialNumber && serial[0]) {
+		/* If we have a serial number, and it's a non-NULL string */
+		make_guid(guid, dev->descriptor.idVendor, 
+			  dev->descriptor.idProduct, serial);
+	} else {
+		/* We don't have a serial number, so we use 0 */
+		make_guid(guid, dev->descriptor.idVendor, 
+			  dev->descriptor.idProduct, "0");
+	}
+
+	/* Now check if we have seen this GUID before, and restore
+	 * the flags if we find it
+	 */
+	for (ss = us_list; ss != NULL; ss = ss->next) {
+		if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid))    {
+			US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
+				  GUID_ARGS(guid));
+			flags = ss->flags;
+			break;
+		}
+	}
+
+	/* If ss == NULL, then this is a new device.  Allocate memory for it */
+	if (!ss) {
+		if ((ss = (struct us_data *)kmalloc(sizeof(*ss), 
+						    GFP_KERNEL)) == NULL) {
+			printk(KERN_WARNING USB_STORAGE "Out of memory\n");
+			return NULL;
+		}
+		memset(ss, 0, sizeof(struct us_data));
+	}
+
+	/* Initialize the us_data structure with some useful info */
+	interface = altsetting;
+	ss->flags = flags;
+	ss->ifnum = ifnum;
+	ss->pusb_dev = dev;
+	ss->attention_done = 0;
+
+	/* If the device has subclass and protocol, then use that.  Otherwise, 
+	 * take data from the specific interface.
+	 */
+	if (subclass) {
+		ss->subclass = subclass;
+		ss->protocol = protocol;
+	} else {
+		ss->subclass = interface->bInterfaceSubClass;
+		ss->protocol = interface->bInterfaceProtocol;
+	}
+
+	/* set the handler pointers based on the protocol */
+	US_DEBUGP("Transport: ");
+	switch (ss->protocol) {
+	case US_PR_CB:
+		US_DEBUGPX("Control/Bulk\n");
+		ss->transport = CB_transport;
+		ss->transport_reset = CB_reset;
+		break;
+
+	case US_PR_CBI:
+		US_DEBUGPX("Control/Bulk/Interrupt\n");
+		ss->transport = CB_transport;
+		ss->transport_reset = CB_reset;
+		break;
+
+	case US_PR_BULK:
+		US_DEBUGPX("Bulk\n");
+		ss->transport = Bulk_transport;
+		ss->transport_reset = Bulk_reset;
+		break;
+
+	default:
+		US_DEBUGPX("Unknown\n");    
+		kfree(ss);
+		return NULL;
+		break;
+	}
+
+	/*
+	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
+	 * An optional interrupt is OK (necessary for CBI protocol).
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < interface->bNumEndpoints; i++) {
+		/* is it an BULK endpoint? */
+		if ((interface->endpoint[i].bmAttributes &  USB_ENDPOINT_XFERTYPE_MASK)
+		    == USB_ENDPOINT_XFER_BULK) {
+			if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN)
+				ss->ep_in = interface->endpoint[i].bEndpointAddress &
+					USB_ENDPOINT_NUMBER_MASK;
+			else
+				ss->ep_out = interface->endpoint[i].bEndpointAddress &
+					USB_ENDPOINT_NUMBER_MASK;
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 
+		    == USB_ENDPOINT_XFER_INT) {
+			ss->ep_int = interface->endpoint[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+		}
+	}
+	US_DEBUGP("Endpoints In %d Out %d Int %d\n",
+		  ss->ep_in, ss->ep_out, ss->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (usb_set_interface(dev, interface->bInterfaceNumber, 0) ||
+	    !ss->ep_in || !ss->ep_out || 
+	    (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
+		US_DEBUGP("Problems with device\n");
+		if (ss->host) {
+			scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt);
+			kfree(ss->htmplt->name);
+			kfree(ss->htmplt);
+		}
+
+		kfree(ss);
+		return NULL;
+	}
+
+	/* If this is a new device (i.e. we haven't seen it before), we need to
+	 * generate a scsi host definition, and register with scsi above us 
+	 */
+	if (!ss->host) {
+		/* copy the GUID we created before */
+		US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+		memcpy(ss->guid, guid, sizeof(guid));
+
+		/* set class specific stuff */
+		US_DEBUGP("Protocol: ");
+		switch (ss->subclass) {
+		case US_SC_RBC:
+			US_DEBUGPX("Reduced Block Commands\n");
+			break;
+
+		case US_SC_8020:
+			US_DEBUGPX("8020\n");
+			break;
+
+		case US_SC_QIC:
+			US_DEBUGPX("QIC157\n");
+			break;
+
+		case US_SC_8070:
+			US_DEBUGPX("8070\n");
+			break;
+
+		case US_SC_SCSI:
+			US_DEBUGPX("Transparent SCSI\n");
+			ss->proto_handler = transparent_scsi_command;
+			break;
+
+		case US_SC_UFI:
+			US_DEBUGPX("UFI\n");
+			ss->proto_handler = ufi_command;
+			break;
+
+		default:
+			US_DEBUGPX("Unknown\n");
+			break;
+		}
+
+		/* We only handle certain protocols.  Currently, these are
+		 *the only ones that devices use.
+		 */
+		if ((ss->subclass != US_SC_SCSI) && (ss->subclass != US_SC_UFI)) {
+			US_DEBUGP("Sorry, we do not support that protocol yet.\n");
+			US_DEBUGP("If you have a device which uses one of the unsupported\n");
+			US_DEBUGP("protocols, please contact mdharm-usb@one-eyed-alien.net\n");
+     
+			kfree(ss);
+			return NULL;
+		}
+
+		/* Allocate memory for the SCSI Host Template */
+		if ((htmplt = (Scsi_Host_Template *)
+		     kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) {
+
+			printk(KERN_WARNING USB_STORAGE "Out of memory\n");
+
+			kfree(ss);
+			return NULL;
+		}
+
+		/* Initialize the host template based on the default one */
+		memcpy(htmplt, &my_host_template, sizeof(my_host_template));
+
+		/* Grab the next host number */
+		ss->host_number = my_host_number++;
+
+		/* MDD: FIXME: this is bad.  We abuse this pointer so we
+		 * can pass the ss pointer to the host controler thread
+		 * in us_detect
+		 */
+		(struct us_data *)htmplt->proc_dir = ss; 
+
+		/* shuttle E-USB */	
+		if (dev->descriptor.idVendor == 0x04e6 &&
+		    dev->descriptor.idProduct == 0x0001) {
+			__u8 qstat[2];
+			int result;
+	    
+			result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0),
+						 1, 0xC0,
+						 0, ss->ifnum,
+						 qstat, 2, HZ*5);
+			US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
+			init_waitqueue_head(&ss->ip_waitq);
+			ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+			result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
+						 255, (void *)ss, &ss->irq_handle);
+			if (result)
+				return NULL;
+
+			interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6);
+		} else if (ss->protocol == US_PR_CBI)
+		{
+			int result; 
+
+			init_waitqueue_head(&ss->ip_waitq);
+
+			/* set up the IRQ pipe and handler */
+			/* FIXME: This needs to get the period from the device */
+			ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+			result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
+						 255, (void *)ss, &ss->irq_handle);
+			if (result) {
+				US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n",
+					  result);
+			}
+		}
+    
+
+		/* start up our thread */
+		{
+			DECLARE_MUTEX_LOCKED(sem);
+
+			init_waitqueue_head(&ss->waitq);
+
+			ss->notify = &sem;
+			ss->pid = kernel_thread(usb_stor_control_thread, ss,
+						CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+			if (ss->pid < 0) {
+				printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n");
+				kfree(htmplt);
+
+				kfree(ss);
+				return NULL;
+			}
+
+			/* wait for it to start */
+			down(&sem);
+		}
+
+		/* now register - our detect function will be called */
+		scsi_register_module(MODULE_SCSI_HA, htmplt);
+
+		/* put us in the list */
+		prev = (struct us_data *)&us_list;
+		while (prev->next)
+			prev = prev->next;
+		prev->next = ss;
+	}
+
+	printk(KERN_INFO "WARNING: USB Mass Storage data integrity not assured\n");
+	printk(KERN_INFO "USB Mass Storage device found at %d\n", dev->devnum);
+
+	return ss;
+}
+
+/* Handle a disconnect event from the USB core */
+static void storage_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct us_data *ss = ptr;
+
+	if (!ss)
+		return;
+
+	ss->pusb_dev = NULL;
+	//  MOD_DEC_USE_COUNT;
+}
+
+
+/***********************************************************************
+ * Initialization and registration
+ ***********************************************************************/
+
+int __init usb_stor_init(void)
+{
+	//  MOD_INC_USE_COUNT;
+
+	if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
+		printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ;
+		printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n", 
+		       SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
+
+		return -1 ;
+	}
+
+	/* register the driver, return -1 if error */
+	if (usb_register(&storage_driver) < 0)
+		return -1;
+
+	printk(KERN_INFO "USB Mass Storage support registered.\n");
+	return 0;
+}
+
+void __exit usb_stor_exit(void)
+{
+	usb_deregister(&storage_driver) ;
+}
+
+module_init(usb_stor_init) ;
+module_exit(usb_stor_exit) ;
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-storage.h linux/drivers/usb/usb-storage.h
--- v2.3.46/linux/drivers/usb/usb-storage.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb-storage.h	Sun Feb 20 16:20:47 2000
@@ -0,0 +1,130 @@
+/* Driver for USB mass storage - include file
+ *
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ */
+
+#include <linux/config.h>
+
+#define USB_STORAGE "usb-storage: "
+
+extern int usb_stor_debug;
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+void us_show_command(Scsi_Cmnd *srb);
+#define US_DEBUGP(x...) { if(usb_stor_debug) printk( KERN_DEBUG USB_STORAGE ## x ); }
+#define US_DEBUGPX(x...) { if(usb_stor_debug) printk( ## x ); }
+#define US_DEBUG(x)  { if(usb_stor_debug) x; }
+#else
+#define US_DEBUGP(x...)
+#define US_DEBUGPX(x...)
+#define US_DEBUG(x)
+#endif
+
+/* bit set if input */
+extern unsigned char us_direction[256/8];
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+/* Sub Classes */
+
+#define US_SC_RBC	1		/* Typically, flash devices */
+#define US_SC_8020	2		/* CD-ROM */
+#define US_SC_QIC	3		/* QIC-157 Tapes */
+#define US_SC_UFI	4		/* Floppy */
+#define US_SC_8070	5		/* Removable media */
+#define US_SC_SCSI	6		/* Transparent */
+#define US_SC_MIN	US_SC_RBC
+#define US_SC_MAX	US_SC_SCSI
+
+/* Protocols */
+
+#define US_PR_CB	1		/* Control/Bulk w/o interrupt */
+#define US_PR_CBI	0		/* Control/Bulk/Interrupt */
+#define US_PR_BULK	0x50		/* bulk only */
+
+/*
+ * Bulk only data structures (Zip 100, for example)
+ */
+
+/* command block wrapper */
+struct bulk_cb_wrap {
+	__u32	Signature;		/* contains 'USBC' */
+	__u32	Tag;			/* unique per command id */
+	__u32	DataTransferLength;	/* size of data */
+	__u8	Flags;			/* direction in bit 0 */
+	__u8	Lun;			/* LUN normally 0 */
+	__u8	Length;			/* of of the CDB */
+	__u8	CDB[16];		/* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN 	31
+#define US_BULK_CB_SIGN		0x43425355
+#define US_BULK_FLAG_IN		1
+#define US_BULK_FLAG_OUT	0
+
+/* command status wrapper */
+struct bulk_cs_wrap {
+	__u32	Signature;		/* should = 'USBS' */
+	__u32	Tag;			/* same as original command */
+	__u32	Residue;		/* amount not transferred */
+	__u8	Status;			/* see below */
+	__u8	Filler[18];
+};
+
+#define US_BULK_CS_WRAP_LEN	13
+#define US_BULK_CS_SIGN		0x53425355
+#define US_BULK_STAT_OK		0
+#define US_BULK_STAT_FAIL	1
+#define US_BULK_STAT_PHASE	2
+
+#define US_BULK_RESET		0xff
+#define US_BULK_RESET_SOFT	1
+#define US_BULK_RESET_HARD	0
+
+/*
+ * Transport return codes
+ */
+
+#define USB_STOR_TRANSPORT_GOOD    0    /* Transport good, command good    */
+#define USB_STOR_TRANSPORT_FAILED  1    /* Transport good, command failed  */
+#define USB_STOR_TRANSPORT_ERROR   2    /* Transport bad (i.e. device dead */
+
+/*
+ * CBI style
+ */
+
+#define US_CBI_ADSC		0
+
+/* 
+ * GUID definitions
+ */
+
+#define GUID(x) __u32 x[3]
+#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2])
+#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0;
+#define GUID_NONE(x) (!x[0] && !x[1] && !x[2])
+#define GUID_FORMAT "%08x%08x%08x"
+#define GUID_ARGS(x) x[0], x[1], x[2]
+
+static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial)
+{
+	pg[0] = (vendor << 16) | product;
+	pg[1] = pg[2] = 0;
+	while (*serial) {
+		pg[1] <<= 4;
+		pg[1] |= pg[2] >> 28;
+		pg[2] <<= 4;
+		if (*serial >= 'a')
+			*serial -= 'a' - 'A';
+		pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0'
+			: *serial - 'A' + 10;
+		serial++;
+	}
+}
+
+/* Flag definitions */
+#define US_FL_IP_STATUS	      0x00000001         /* status uses interrupt */
+#define US_FL_FIXED_COMMAND   0x00000002 /* expand commands to fixed size */
+#define US_FL_MODE_XLATE      0x00000004 /* translate _6 to _10 comands for
+					    Win/MacOS compatibility */
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb_storage.c linux/drivers/usb/usb_storage.c
--- v2.3.46/linux/drivers/usb/usb_storage.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/usb/usb_storage.c	Wed Dec 31 16:00:00 1969
@@ -1,1849 +0,0 @@
-/* Driver for USB Mass Storage compliant devices
- *
- * (c) 1999 Michael Gee (michael@linuxspecific.com)
- * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
- *
- * Further reference:
- *	This driver is based on the 'USB Mass Storage Class' document. This
- *	describes in detail the protocol used to communicate with such
- *      devices.  Clearly, the designers had SCSI commands in mind when they
- *      created this document.  The commands are all similar to commands
- *      in the SCSI-II specification.
- *
- *	It is important to note that in a number of cases this class exhibits
- *	class-specific exemptions from the USB specification. Notably the
- *	usage of NAK, STALL and ACK differs from the norm, in that they are
- *	used to communicate wait, failed and OK on commands.
- *	Also, for certain devices, the interrupt endpoint is used to convey
- *	status of a command.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-
-#include <linux/blk.h>
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
-
-#include "usb.h"
-#include "usb_storage.h"
-
-/*
- * This is the size of the structure Scsi_Host_Template.  We create
- * an instance of this structure in this file and this is a check
- * to see if this structure may have changed within the SCSI module.
- * This is by no means foolproof, but it does help us some.
- */
-#define SCSI_HOST_TEMPLATE_SIZE			(104)
-
-/* direction table -- this indicates the direction of the data
- * transfer for each command code -- a 1 indicates input
- */
-unsigned char us_direction[256/8] = {
-	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
-	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-/*
- * Per device data
- */
-
-static int my_host_number;
-
-int usb_stor_debug = 1;
-
-struct us_data;
-
-typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
-typedef int (*trans_reset)(struct us_data*);
-typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
-
-struct us_data {
-	struct us_data	*next;		         /* next device */
-	struct usb_device	*pusb_dev;       /* this usb_device */
-	unsigned int		flags;		 /* from filter initially */
-	__u8			ifnum;		 /* interface number */
-	__u8			ep_in;		 /* in endpoint */
-	__u8			ep_out;		 /* out ....... */
-	__u8			ep_int;		 /* interrupt . */
-	__u8			subclass;	 /* as in overview */
-	__u8			protocol;	 /* .............. */
-	__u8			attention_done;  /* force attn on first cmd */
-	trans_cmnd              transport;	 /* protocol specific do cmd */
-	trans_reset             transport_reset; /* .......... device reset */
-	proto_cmnd              proto_handler;   /* protocol handler */
-	GUID(guid);				 /* unique dev id */
-	struct Scsi_Host	*host;		 /* our dummy host data */
-	Scsi_Host_Template	*htmplt;	 /* own host template */
-	int			host_number;	 /* to find us */
-	int			host_no;	 /* allocated by scsi */
-	Scsi_Cmnd		*srb;		 /* current srb */
-	int			action;		 /* what to do */
-	wait_queue_head_t	waitq;		 /* thread waits */
-	wait_queue_head_t	ip_waitq;	 /* for CBI interrupts */
-	__u16			ip_data;	 /* interrupt data */
-	int			ip_wanted;	 /* needed */
-	int			pid;		 /* control thread */
-	struct semaphore	*notify;	 /* wait for thread to begin */
-	void			*irq_handle;	 /* for USB int requests */
-	unsigned int		irqpipe;	 /* pipe for release_irq */
-};
-
-/*
- * kernel thread actions
- */
-
-#define US_ACT_COMMAND		1
-#define US_ACT_ABORT		2
-#define US_ACT_DEVICE_RESET	3
-#define US_ACT_BUS_RESET	4
-#define US_ACT_HOST_RESET	5
-
-static struct us_data *us_list;
-
-static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
-static void storage_disconnect(struct usb_device *dev, void *ptr);
-static struct usb_driver storage_driver = {
-	"usb-storage",
-	storage_probe,
-	storage_disconnect,
-	{ NULL, NULL }
-};
-
-/***********************************************************************
- * Data transfer routines
- ***********************************************************************/
-
-/* Transfer one buffer (breaking into packets if necessary)
- * Note that this function is necessary because if the device NAKs, we
- * need to know that information directly
- *
- * FIXME: is the above true?  Or will the URB status show ETIMEDOUT after
- * retrying several times allready?  Perhaps this is the way we should
- * be going anyway?
- */
-static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
-{
-	int max_size;
-	int this_xfer;
-	int result;
-	int partial;
-	int maxtry;
-
-	/* determine the maximum packet size for these transfers */
-	max_size = usb_maxpacket(us->pusb_dev, 
-				 pipe, usb_pipeout(pipe)) * 16;
-
-	/* while we have data left to transfer */
-	while (length) {
-
-		/* calculate how long this will be -- maximum or a remainder */
-		this_xfer = length > max_size ? max_size : length;
-		length -= this_xfer;
-
-		/* FIXME: this number is totally outrageous.  We need to pick
-		 * a better (smaller) number).
-		 */
-
-		/* setup the retry counter */
-		maxtry = 100;
-
-		/* set up the transfer loop */
-		do {
-			/* transfer the data */
-			US_DEBUGP("Bulk xfer 0x%x(%d) try #%d\n", 
-				  (unsigned int)buf, this_xfer, 101 - maxtry);
-			result = usb_bulk_msg(us->pusb_dev, pipe, buf,
-					      this_xfer, &partial, HZ*5);
-			US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
-				  result, partial, this_xfer);
-
-			/* if we stall, we need to clear it before we go on */
-			if (result == -EPIPE) {
-				US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-				usb_clear_halt(us->pusb_dev, pipe);
-			}
-
-			/* update to show what data was transferred */
-			this_xfer -= partial;
-			buf += partial;
-
-			/* NAK - we retry a few times */
-			if (result == -ETIMEDOUT) {
-
-				US_DEBUGP("us_one_transfer: device NAKed\n");
-
-				/* if our try counter reaches 0, bail out */
-				if (!maxtry--)
-					return -ETIMEDOUT;
-
-				/* just continue the while loop */
-				continue;
-			}
-      
-			/* other errors (besides NAK) -- we just bail out*/
-			if (result != 0) {
-				US_DEBUGP("us_one_transfer: device returned error %d\n", result);
-				return result;
-			}
-
-			/* continue until this transfer is done */
-		} while ( this_xfer );
-	}
-
-	/* if we get here, we're done and successful */
-	return 0;
-}
-
-static unsigned int us_transfer_length(Scsi_Cmnd *srb);
-
-/* transfer one SCSI command, using scatter-gather if requested */
-/* FIXME: what do the return codes here mean? */
-static int us_transfer(Scsi_Cmnd *srb, int dir_in)
-{
-	struct us_data *us = (struct us_data *)srb->host_scribble;
-	int i;
-	int result = -1;
-	unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
-		usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
-	/* FIXME: stop transferring data at us_transfer_length(), not 
-	 * bufflen */
-	if (srb->use_sg) {
-		struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
-
-		for (i = 0; i < srb->use_sg; i++) {
-			result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);
-			if (result)
-				break;
-		}
-	}
-	else
-		result = us_one_transfer(us, pipe, srb->request_buffer, 
-					 us_transfer_length(srb));
-
-	if (result < 0)
-		US_DEBUGP("us_transfer returning error %d\n", result);
-	return result;
-}
-
-/* calculate the length of the data transfer (not the command) for any
- * given SCSI command
- */
-static unsigned int us_transfer_length(Scsi_Cmnd *srb)
-{
-	int i;
-	unsigned int total = 0;
-
-	/* always zero for some commands */
-	switch (srb->cmnd[0]) {
-	case SEEK_6:
-	case SEEK_10:
-	case REZERO_UNIT:
-	case ALLOW_MEDIUM_REMOVAL:
-	case START_STOP:
-	case TEST_UNIT_READY:
-		return 0;
-
-	case REQUEST_SENSE:
-	case INQUIRY:
-	case MODE_SENSE:
-		return srb->cmnd[4];
-
-	case LOG_SENSE:
-	case MODE_SENSE_10:
-		return (srb->cmnd[7] << 8) + srb->cmnd[8];
-
-	default:
-		break;
-	}
-
-	if (srb->use_sg) {
-		struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
-
-		for (i = 0; i < srb->use_sg; i++) {
-			total += sg[i].length;
-		}
-		return total;
-	}
-	else
-		return srb->request_bufflen;
-}
-
-/***********************************************************************
- * Protocol routines
- ***********************************************************************/
-
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us);
-static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us);
-
-static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
-{
-	int old_cmnd = 0;
-  
-	/* fix some commands -- this is a form of mode translation
-	 * UFI devices only accept 12 byte long commands 
-	 *
-	 * NOTE: This only works because a Scsi_Cmnd struct field contains
-	 * a unsigned char cmnd[12], so we know we have storage available
-	 */
-
-	/* set command length to 12 bytes (this affects the transport layer) */
-	srb->cmd_len = 12;
-
-	/* determine the correct (or minimum) data length for these commands */
-	switch (us->srb->cmnd[0]) {
-
-		/* for INQUIRY, UFI devices only ever return 36 bytes */
-	case INQUIRY:
-		us->srb->cmnd[4] = 36;
-		break;
-
-		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
-	case MODE_SENSE:
-	case MODE_SELECT:
-		/* save the command so we can tell what it was */
-		old_cmnd = srb->cmnd[0];
-
-		srb->cmnd[11] = 0;
-		srb->cmnd[10] = 0;
-		srb->cmnd[9] = 0;
-
-		/* if we're sending data, we send all.  If getting data, 
-		 * get the minimum */
-		if (srb->cmnd[0] == MODE_SELECT)
-			srb->cmnd[8] = srb->cmnd[4];
-		else
-			srb->cmnd[8] = 8;
-
-		srb->cmnd[7] = 0;
-		srb->cmnd[6] = 0;
-		srb->cmnd[5] = 0;
-		srb->cmnd[4] = 0;
-		srb->cmnd[3] = 0;
-		srb->cmnd[2] = srb->cmnd[2];
-		srb->cmnd[1] = srb->cmnd[1];
-		srb->cmnd[0] = srb->cmnd[0] | 0x40;
-		break;
-
-		/* again, for MODE_SENSE_10, we get the minimum (8) */
-	case MODE_SENSE_10:
-		us->srb->cmnd[7] = 0;
-		us->srb->cmnd[8] = 8;
-		break;
- 
-		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
-	case REQUEST_SENSE:
-		us->srb->cmnd[4] = 18;
-		break;
-
-		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
-		 * are UFI commands */
-	case WRITE_6:
-	case READ_6:
-		srb->cmnd[11] = 0;
-		srb->cmnd[10] = 0;
-		srb->cmnd[9] = 0;
-		srb->cmnd[8] = srb->cmnd[4];
-		srb->cmnd[7] = 0;
-		srb->cmnd[6] = 0;
-		srb->cmnd[5] = srb->cmnd[3];
-		srb->cmnd[4] = srb->cmnd[2];
-		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
-		srb->cmnd[2] = 0;
-		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
-		srb->cmnd[0] = srb->cmnd[0] | 0x20;
-		break;
-	} /* end switch on cmnd[0] */
-  
-	/* send the command to the transport layer */
-	us->srb->result = us->transport(srb, us);
-
-	/* if we have an error, we're going to do a 
-	 * REQUEST_SENSE automatically */
-
-	/* FIXME: we should only do this for device 
-	 * errors, not system errors */
-	if (us->srb->result) {
-		int temp_result;
-		int count;
-		void* old_request_buffer;
-
-		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
-		/* set the result so the higher layers expect this data */
-		us->srb->result = CHECK_CONDITION;
-
-		us->srb->cmnd[0] = REQUEST_SENSE;
-		us->srb->cmnd[1] = 0;
-		us->srb->cmnd[2] = 0;
-		us->srb->cmnd[3] = 0;
-		us->srb->cmnd[4] = 18;
-		us->srb->cmnd[5] = 0;
-    
-		/* set the buffer length for transfer */
-		old_request_buffer = us->srb->request_buffer;
-		us->srb->request_bufflen = 18;
-		us->srb->request_buffer = kmalloc(18, GFP_KERNEL);
-
-		/* FIXME: what if this command fails? */
-		temp_result = us->transport(us->srb, us);
-		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-
-		/* copy the data from the request buffer to the sense buffer */
-		for(count = 0; count < 18; count++)
-			us->srb->sense_buffer[count] = 
-				((unsigned char *)(us->srb->request_buffer))[count];
-
-		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-			  us->srb->sense_buffer[2] & 0xf,
-			  us->srb->sense_buffer[12], us->srb->sense_buffer[13]);
-
-		/* we're done here */
-		kfree(us->srb->request_buffer);
-		us->srb->request_buffer = old_request_buffer;
-		return;
-	}
-  
-	/* FIXME: if we need to send more data, or recieve data, we should
-	 * do it here.  Then, we can do status handling here also.
-	 *
-	 * This includes MODE_SENSE from above
-	 */
-	if (old_cmnd == MODE_SENSE) {
-		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
-
-		/* calculate the new length */
-		int length = (dta[0] << 8) + dta[1] + 2;
-
-		/* copy the available data length into the structure */
-		us->srb->cmnd[7] = length >> 8;
-		us->srb->cmnd[8] = length & 0xFF;
-
-		/* send the command to the transport layer */
-		us->srb->result = us->transport(srb, us);
-
-		/* FIXME: this assumes that the 2nd attempt is always
-		 * successful convert MODE_SENSE_10 return data format 
-		 * to MODE_SENSE_6 format */
-		dta[0] = dta[1];	/* data len */
-		dta[1] = dta[2];	/* med type */
-		dta[2] = dta[3];	/* dev-spec prm */
-		dta[3] = dta[7];	/* block desc len */
-		printk (KERN_DEBUG USB_STORAGE
-			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
-			dta[0], dta[1], dta[2], dta[3]);
-	}
-
-	/* FIXME: if this was a TEST_UNIT_READY, and we get a NOT READY/
-	 * LOGICAL DRIVE NOT READY then we do a START_STOP, and retry 
-	 */
-
-	/* FIXME: here is where we need to fix-up the return data from 
-	 * an INQUIRY command to show ANSI SCSI rev 2
-	 */
-
-	/* FIXME: The rest of this is bogus.  usb_control_msg() will only
-	 * return an error if we've really honked things up.  If it just
-	 * needs a START_STOP, then we'll get some data back via 
-	 * REQUEST_SENSE --  either way, this belongs at a higher level
-	 */
-
-#if 0
-	/* For UFI, if this is the first time we've sent this TEST_UNIT_READY 
-	 * command, we can try again
-	 */
-	if (!done_start && (us->subclass == US_SC_UFI)
-	    && (cmd[0] == TEST_UNIT_READY) && (result < 0)) {
-    
-		/* as per spec try a start command, wait and retry */
-		wait_ms(100);
-    
-		done_start++;
-		memset(cmd, 0, sizeof(cmd));
-		cmd[0] = START_STOP;
-		cmd[4] = 1;		/* start */
-    
-		result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
-					 US_CBI_ADSC, 
-					 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-					 0, us->ifnum,
-					 cmd, 12, HZ*5);
-		US_DEBUGP("Next usb_control_msg returns %d\n", result);
-    
-				/* allow another retry */
-		retry++;
-		continue;
-	}
-#endif
-}
-
-static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
-{
-	unsigned int savelen = us->srb->request_bufflen;
-	unsigned int saveallocation = 0;
-
-#if 0
-	/* force attention on first command */
-	if (!us->attention_done) {
-		if (us->srb->cmnd[0] == REQUEST_SENSE) {
-			US_DEBUGP("forcing unit attention\n");
-			us->attention_done = 1;
-
-			if (us->srb->result == USB_STOR_TRANSPORT_GOOD) {
-				unsigned char *p = (unsigned char *)us->srb->request_buffer;
-	
-				if ((p[2] & 0x0f) != UNIT_ATTENTION) {
-					p[2] = UNIT_ATTENTION;
-					p[12] = 0x29;	/* power on, reset or bus-reset */
-					p[13] = 0;
-				} /* if ((p[2] & 0x0f) != UNIT_ATTENTION) */
-			} /* if (us->srb->result == USB_STORE_TRANSPORT_GOOD) */
-		}
-	} /* if (!us->attention_done) */
-#endif
-
-	/* If the command has a variable-length payload, then we do them
-	 * in two steps -- first we do the minimum, then we recalculate
-	 * then length, and re-issue the command 
-	 *
-	 * we use savelen to remember how much buffer we really have
-	 * we use savealloction to remember how much was really requested
-	 */
-
-	/* FIXME: remove savelen based on mods to us_transfer_length() */
-	switch (us->srb->cmnd[0]) {
-	case REQUEST_SENSE:
-		if (us->srb->request_bufflen > 18)
-			us->srb->request_bufflen = 18;
-		else
-			break;
-		saveallocation = us->srb->cmnd[4];
-		us->srb->cmnd[4] = 18;
-		break;
-    
-	case INQUIRY:
-		if (us->srb->request_bufflen > 36)
-			us->srb->request_bufflen = 36;
-		else
-			break;
-		saveallocation = us->srb->cmnd[4];
-		us->srb->cmnd[4] = 36;
-		break;
-    
-	case MODE_SENSE:
-		if (us->srb->request_bufflen > 4)
-			us->srb->request_bufflen = 4;
-		else
-			break;
-		saveallocation = us->srb->cmnd[4];
-		us->srb->cmnd[4] = 4;
-		break;
-    
-	case LOG_SENSE:
-	case MODE_SENSE_10:
-		if (us->srb->request_bufflen > 8)
-			us->srb->request_bufflen = 8;
-		else
-			break;
-		saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8];
-		us->srb->cmnd[7] = 0;
-		us->srb->cmnd[8] = 8;
-		break;
-    
-	default:
-		break;
-	} /* end switch on cmnd[0] */
-  
-	/* This code supports devices which do not support {READ|WRITE}_6
-	 * Apparently, neither Windows or MacOS will use these commands,
-	 * so some devices do not support them
-	 */
-	if (us->flags & US_FL_MODE_XLATE) {
-    
-		/* translate READ_6 to READ_10 */
-		if (us->srb->cmnd[0] == 0x08) {
-      
-			/* get the control */
-			us->srb->cmnd[9] = us->srb->cmnd[5];
-      
-			/* get the length */
-			us->srb->cmnd[8] = us->srb->cmnd[6];
-			us->srb->cmnd[7] = 0;
-      
-			/* set the reserved area to 0 */
-			us->srb->cmnd[6] = 0;	    
-      
-			/* get LBA */
-			us->srb->cmnd[5] = us->srb->cmnd[3];
-			us->srb->cmnd[4] = us->srb->cmnd[2];
-			us->srb->cmnd[3] = 0;
-			us->srb->cmnd[2] = 0;
-      
-			/* LUN and other info in cmnd[1] can stay */
-      
-			/* fix command code */
-			us->srb->cmnd[0] = 0x28;
-      
-			US_DEBUGP("Changing READ_6 to READ_10\n");
-			US_DEBUG(us_show_command(us->srb));
-		}
-    
-		/* translate WRITE_6 to WRITE_10 */
-		if (us->srb->cmnd[0] == 0x0A) {
-      
-			/* get the control */
-			us->srb->cmnd[9] = us->srb->cmnd[5];
-      
-			/* get the length */
-			us->srb->cmnd[8] = us->srb->cmnd[4];
-			us->srb->cmnd[7] = 0;
-      
-			/* set the reserved area to 0 */
-			us->srb->cmnd[6] = 0;	    
-      
-			/* get LBA */
-			us->srb->cmnd[5] = us->srb->cmnd[3];
-			us->srb->cmnd[4] = us->srb->cmnd[2];
-			us->srb->cmnd[3] = 0;
-			us->srb->cmnd[2] = 0;
-	    
-			/* LUN and other info in cmnd[1] can stay */
-      
-			/* fix command code */
-			us->srb->cmnd[0] = 0x2A;
-
-			US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
-			US_DEBUG(us_show_command(us->srb));
-		}
-	} /* end if (us->flags & US_FL_MODE_XLATE) */
-  
-	/* send the command to the transport layer */
-	us->srb->result = us->transport(us->srb, us);
-
-	/* if we have an error, we're going to do a REQUEST_SENSE 
-	 * automatically */
-	/* FIXME: we should only do this for device errors, not 
-	 * system errors */
-	if (us->srb->result) {
-		int temp_result;
-		int count;
-		void* old_request_buffer;
-
-		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
-		/* set the result so the higher layers expect this data */
-		us->srb->result = CHECK_CONDITION;
-
-		us->srb->cmnd[0] = REQUEST_SENSE;
-		us->srb->cmnd[1] = 0;
-		us->srb->cmnd[2] = 0;
-		us->srb->cmnd[3] = 0;
-		us->srb->cmnd[4] = 18;
-		us->srb->cmnd[5] = 0;
-    
-		/* set the buffer length for transfer */
-		old_request_buffer = us->srb->request_buffer;
-		us->srb->request_bufflen = 18;
-		us->srb->request_buffer = kmalloc(18, GFP_KERNEL);
-
-		/* FIXME: what if this command fails? */
-		temp_result = us->transport(us->srb, us);
-		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-
-		/* copy the data from the request buffer to the sense buffer */
-		for(count = 0; count < 18; count++)
-			us->srb->sense_buffer[count] = 
-				((unsigned char *)(us->srb->request_buffer))[count];
-
-		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-			  us->srb->sense_buffer[2] & 0xf,
-			  us->srb->sense_buffer[12], us->srb->sense_buffer[13]);
-
-		/* we're done here */
-		kfree(us->srb->request_buffer);
-		us->srb->request_buffer = old_request_buffer;
-		return;
-	}
-
-	if (savelen != us->srb->request_bufflen) {
-		unsigned char *p = (unsigned char *)us->srb->request_buffer;
-		unsigned int length = 0;
-    
-		/* set correct length and retry */
-		switch (us->srb->cmnd[0]) {
-
-			/* FIXME: we should try to get all the sense data */
-		case REQUEST_SENSE:
-			/* simply return 18 bytes */
-			p[7] = 10;
-			length = us->srb->request_bufflen;
-			break;
-      
-		case INQUIRY:
-			length = p[4] + 5 > savelen ? savelen : p[4] + 5;
-			us->srb->cmnd[4] = length;
-			break;
-      
-		case MODE_SENSE:
-			US_DEBUGP("MODE_SENSE Mode data length is %d\n", p[0]);
-			length = p[0] + 1 > savelen ? savelen : p[0] + 1;
-			us->srb->cmnd[4] = length;
-			break;
-      
-		case LOG_SENSE:
-			length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4;
-			us->srb->cmnd[7] = length >> 8;
-			us->srb->cmnd[8] = length;
-			break;
-      
-		case MODE_SENSE_10:
-			US_DEBUGP("MODE_SENSE_10 Mode data length is %d\n",
-				  (p[0] << 8) + p[1]);
-			length = ((p[0] << 8) + p[1]) + 6 > savelen ? savelen : ((p[0] << 8) + p[1]) + 6;
-			us->srb->cmnd[7] = length >> 8;
-			us->srb->cmnd[8] = length;
-			break;
-		} /* end switch on cmnd[0] */
-    
-		US_DEBUGP("Old/New length = %d/%d\n",
-			  savelen, length);
-    
-		/* issue the new command */
-		/* FIXME: this assumes that the second attempt is 
-		 * always successful */
-		if (us->srb->request_bufflen != length) {
-			US_DEBUGP("redoing cmd with len=%d\n", length);
-			us->srb->request_bufflen = length;
-			us->srb->result = us->transport(us->srb, us);
-		}
-    
-		/* reset back to original values */
-		us->srb->request_bufflen = savelen;
-
-		/* fix data as necessary */
-		switch (us->srb->cmnd[0]) {
-		case INQUIRY:
-			if ((((unsigned char*)us->srb->request_buffer)[2] & 0x7) == 0) { 
-				US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
-				((unsigned char*)us->srb->request_buffer)[2] |= 2;
-			}
-			/* FALL THROUGH */
-		case REQUEST_SENSE:
-		case MODE_SENSE:
-			if (us->srb->use_sg == 0 && length > 0) {
-				int i;
-				printk(KERN_DEBUG "Data is");
-				for (i = 0; i < 32 && i < length; ++i)
-					printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]);
-				if (i < length)
-					printk(" ...");
-				printk("\n");
-			}
-
-			/* FIXME: is this really necessary? */
-			us->srb->cmnd[4] = saveallocation;
-			break;
-      
-		case LOG_SENSE:
-		case MODE_SENSE_10:
-			/* FIXME: is this really necessary? */
-			us->srb->cmnd[7] = saveallocation >> 8;
-			us->srb->cmnd[8] = saveallocation;
-			break;
-		} /* end switch on cmnd[0] */
-	} /* if good command */
-}
-
-/***********************************************************************
- * Transport routines
- ***********************************************************************/
-
-static int CBI_irq(int state, void *buffer, int len, void *dev_id)
-{
-	struct us_data *us = (struct us_data *)dev_id;
-
-	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
-
-	/* save the data for interpretation later */
-	if (state != USB_ST_REMOVED) {
-		us->ip_data = le16_to_cpup((__u16 *)buffer);
-		US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data);
-	}
-  
-	/* was this a wanted interrupt? */
-	if (us->ip_wanted) {
-		us->ip_wanted = 0;
-		wake_up(&us->ip_waitq);
-	} else {
-		US_DEBUGP("ERROR: Unwanted interrupt received!\n");
-	}
-
-	/* This return code is truly meaningless -- and I mean truly.  It gets
-	 * ignored by other layers.  It used to indicate if we wanted to get
-	 * another interrupt or disable the interrupt callback
-	 */
-	return 0;
-}
-
-/* FIXME: this reset function doesn't really reset the port, and it
- * should. Actually it should probably do what it's doing here, and
- * reset the port physically
- */
-static int CB_reset(struct us_data *us)
-{
-	unsigned char cmd[12];
-	int result;
-
-	US_DEBUGP("CB_reset\n");
-
-	memset(cmd, 0xFF, sizeof(cmd));
-	cmd[0] = SEND_DIAGNOSTIC;
-	cmd[1] = 4;
-	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
-				 US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-				 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
-
-	/* long wait for reset */
-	schedule_timeout(HZ*6);
-
-	US_DEBUGP("CB_reset: clearing endpoint halt\n");
-	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
-
-	US_DEBUGP("CB_reset done\n");
-	return 0;
-}
-
-static int pop_CB_status(Scsi_Cmnd *srb);
-
-/* FIXME: we also need a CBI_command which sets up the completion
- * interrupt, and waits for it
- */
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
-	int result;
-
-	US_DEBUGP("CBI gets a command:\n");
-	US_DEBUG(us_show_command(srb));
-
-	/* FIXME: we aren't setting the ip_wanted indicator early enough, which
-	 * causes some commands to never complete.  This hangs the driver.
-	 */
-
-	/* let's send the command via the control pipe */
-	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
-				 US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-				 0, us->ifnum,
-				 srb->cmnd, srb->cmd_len, HZ*5);
-
-	/* check the return code for the command */
-	if (result < 0) {
-		US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
-
-		/* a stall is a fatal condition from the device */
-		if (result == -EPIPE) {
-			US_DEBUGP("-- Stall on control pipe detected. Clearing\n");
-      
-			US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
-				  usb_clear_halt(us->pusb_dev, 
-						 usb_sndctrlpipe(us->pusb_dev, 0)));
-			return USB_STOR_TRANSPORT_ERROR;
-		}
-
-		/* FIXME: we need to handle NAKs here */
-		return USB_STOR_TRANSPORT_ERROR;
-	}
-
-	/* transfer the data payload for this command, if one exists*/
-	if (us_transfer_length(srb)) {
-		result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-		US_DEBUGP("CBI attempted to transfer data, result is 0x%x\n", result);
-
-		/* FIXME: what do the return codes from us_transfer mean? */
-		if ((result < 0) && 
-		    (result != USB_ST_DATAUNDERRUN) && 
-		    (result != USB_ST_STALL)) {
-			return DID_ERROR << 16;
-		}
-	} /* if (us_transfer_length(srb)) */
-
-	/* get status and return it */
-	return pop_CB_status(srb);
-}
-
-/*
- * Control/Bulk status handler
- */
-
-static int pop_CB_status(Scsi_Cmnd *srb)
-{
-	struct us_data *us = (struct us_data *)srb->host_scribble;
-	int result;
-	__u8 status[2];
-	int retry = 5;
-
-	US_DEBUGP("pop_CB_status, proto=0x%x\n", us->protocol);
-	switch (us->protocol) {
-	case US_PR_CB:
-		/* get from control */
-
-		while (retry--) {
-			result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0),
-						 USB_REQ_GET_STATUS, USB_DIR_IN |
-						 USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-						 0, us->ifnum, status, sizeof(status), HZ*5);
-			if (result != USB_ST_TIMEOUT)
-				break;
-		}
-		if (result) {
-			US_DEBUGP("Bad AP status request %d\n", result);
-			return DID_ABORT << 16;
-		}
-		US_DEBUGP("Got AP status 0x%x 0x%x\n", status[0], status[1]);
-		if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
-		    ( (status[0] & ~3) || status[1]))
-			return (DID_OK << 16) | 2;
-		else
-			return USB_STOR_TRANSPORT_GOOD;
-		break;
-
-		/* FIXME: this should be in a separate function */
-	case US_PR_CBI:
-		/* get from interrupt pipe */
-
-		/* add interrupt transfer, marked for removal */
-		us->ip_wanted = 1;
-
-		/* go to sleep until we get this interrup */
-		/* FIXME: this should be changed to use a timeout */
-		sleep_on(&us->ip_waitq);
-    
-		if (us->ip_wanted) {
-			US_DEBUGP("Did not get interrupt on CBI\n");
-			us->ip_wanted = 0;
-			return USB_STOR_TRANSPORT_ERROR;
-		}
-    
-		US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
-
-		/* UFI gives us ASC and ASCQ, like a request sense */
-		/* FIXME: is this right?  do REQUEST_SENSE and INQUIRY need special
-		 * case handling?
-		 */
-		if (us->subclass == US_SC_UFI) {
-			if (srb->cmnd[0] == REQUEST_SENSE ||
-			    srb->cmnd[0] == INQUIRY)
-				return USB_STOR_TRANSPORT_GOOD;
-			else
-				if (us->ip_data)
-					return USB_STOR_TRANSPORT_FAILED;
-				else
-					return USB_STOR_TRANSPORT_GOOD;
-		}
-
-		/* otherwise, we interpret the data normally */
-		switch (us->ip_data) {
-		case 0x0001: 
-			return USB_STOR_TRANSPORT_GOOD;
-		case 0x0002: 
-			return USB_STOR_TRANSPORT_FAILED;
-		default: 
-			return USB_STOR_TRANSPORT_ERROR;
-		}
-	}
-	US_DEBUGP("pop_CB_status, reached end of function\n");
-	return USB_STOR_TRANSPORT_ERROR;
-}
-
-static int Bulk_reset(struct us_data *us)
-{
-	int result;
-
-	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
-				 US_BULK_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-				 US_BULK_RESET_HARD, us->ifnum,
-				 NULL, 0, HZ*5);
-	if (result)
-		US_DEBUGP("Bulk hard reset failed %d\n", result);
-	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-	usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out));
-
-	/* long wait for reset */
-	schedule_timeout(HZ*6);
-
-	return result;
-}
-
-/*
- * The bulk only protocol handler.
- *	Uses the in and out endpoints to transfer commands and data
- */
-static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
-	struct bulk_cb_wrap bcb;
-	struct bulk_cs_wrap bcs;
-	int result;
-	int pipe;
-	int partial;
-
-	/* set up the command wrapper */
-	bcb.Signature = US_BULK_CB_SIGN;
-	bcb.DataTransferLength = us_transfer_length(srb);
-	bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
-	bcb.Tag = srb->serial_number;
-	bcb.Lun = 0;
-	bcb.Length = srb->cmd_len;
-
-	/* construct the pipe handle */
-	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
-	/* copy the command payload */
-	memset(bcb.CDB, 0, sizeof(bcb.CDB));
-	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
-
-	/* send it to out endpoint */
-	US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n",
-		  bcb.Signature, bcb.Tag, bcb.DataTransferLength,
-		  bcb.Flags, bcb.Length);
-	result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
-			      US_BULK_CB_WRAP_LEN, &partial, HZ*5);
-	US_DEBUGP("Bulk command transfer result=%d\n", result);
-
-	/* if we stall, we need to clear it before we go on */
-	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_clear_halt(us->pusb_dev, pipe);
-	}
-  
-	/* if the command transfered well, then we go to the data stage */
-	/* FIXME: Regardless of the status of the data stage, we go on to the
-	 * status stage.  Note that this implies that if a command is
-	 * partially successful, we rely on the device reporting an error
-	 * the CSW. The spec says that the device may just decide to short us.
-	 */
-	if (result == 0) {
-		/* send/receive data payload, if there is any */
-		if (bcb.DataTransferLength) {
-			result = us_transfer(srb, bcb.Flags);
-			US_DEBUGP("Bulk data transfer result 0x%x\n", result);
-#if 0
-			if ((result < 0) && (result != USB_ST_DATAUNDERRUN) 
-			    && (result != USB_ST_STALL)) {
-				US_DEBUGP("Bulk data transfer result 0x%x\n", result);
-				return DID_ABORT << 16;
-			}
-#endif
-		}
-	}
-
-	/* See flow chart on pg 15 of the Bulk Only Transport spec for
-	 * an explanation of how this code works.
-	 */
-
-	/* construct the pipe handle */
-	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-
-	/* get CSW for device status */
-	result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
-			      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-
-	/* did the attempt to read the CSW fail? */
-	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_clear_halt(us->pusb_dev, pipe);
-
-		/* get the status again */
-		result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
-				      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-   
-		/* if it fails again, we need a reset and return an error*/
-		if (result == -EPIPE) {
-			Bulk_reset(us);
-			return (DID_ABORT << 16);
-		}
-	}
-
-	/* if we still have a failure at this point, we're in trouble */
-	if (result) {
-		US_DEBUGP("Bulk status result = 0x%x\n", result);
-		return DID_ABORT << 16;
-	}
-
-	/* check bulk status */
-	US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
-		  bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
-	if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
-	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
-		US_DEBUGP("Bulk logical error\n");
-		return DID_ABORT << 16;
-	}
-
-	/* based on the status code, we report good or bad */
-	switch (bcs.Status) {
-	case US_BULK_STAT_OK:
-		/* if there is residue, we really didn't finish the command */
-		if (bcs.Residue)
-			return DID_ERROR << 16;
-		else
-			return DID_OK << 16;
-
-	case US_BULK_STAT_FAIL:
-		return DID_ERROR << 16;
-
-	case US_BULK_STAT_PHASE:
-		Bulk_reset(us);
-		return DID_ERROR << 16;
-	}
-
-	return DID_OK << 16;	    /* check sense required */
-}
-
-/***********************************************************************
- * Host functions 
- ***********************************************************************/
-
-/* detect adapter (always true ) */
-static int us_detect(struct SHT *sht)
-{
-	/* FIXME - not nice at all, but how else ? */
-	struct us_data *us = (struct us_data *)sht->proc_dir;
-	char name[32];
-
-	/* set up our name */
-	sprintf(name, "usbscsi%d", us->host_number);
-	sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
-	if (!sht->proc_name)
-		return 0;
-	strcpy(sht->proc_name, name);
-
-	/* we start with no /proc directory entry */
-	sht->proc_dir = NULL;
-
-	/* register the host */
-	us->host = scsi_register(sht, sizeof(us));
-	if (us->host) {
-		us->host->hostdata[0] = (unsigned long)us;
-		us->host_no = us->host->host_no;
-		return 1;
-	}
-
-	/* odd... didn't register properly.  Abort and free pointers */
-	kfree(sht->proc_name);
-	sht->proc_name = NULL;
-	sht->name = NULL;
-	return 0;
-}
-
-/* release - must be here to stop scsi
- *	from trying to release IRQ etc.
- *	Kill off our data
- */
-static int us_release(struct Scsi_Host *psh)
-{
-	struct us_data *us = (struct us_data *)psh->hostdata[0];
-	struct us_data *prev = (struct us_data *)&us_list;
-
-	if (us->irq_handle) {
-		usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
-		us->irq_handle = NULL;
-	}
-	if (us->pusb_dev)
-		usb_deregister(&storage_driver);
-
-	/* FIXME - leaves hanging host template copy */
-	/* (because scsi layer uses it after removal !!!) */
-	while (prev->next != us)
-		prev = prev->next;
-	prev->next = us->next;
-	return 0;
-}
-
-/* run command */
-static int us_command( Scsi_Cmnd *srb )
-{
-	US_DEBUGP("Bad use of us_command\n");
-
-	return DID_BAD_TARGET << 16;
-}
-
-/* run command */
-static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
-{
-	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
-
-	US_DEBUGP("Command wakeup\n");
-	if (us->srb) {
-		/* busy */
-	}
-	srb->host_scribble = (unsigned char *)us;
-	us->srb = srb;
-	srb->scsi_done = done;
-	us->action = US_ACT_COMMAND;
-
-	/* wake up the process task */
-
-	wake_up_interruptible(&us->waitq);
-
-	return 0;
-}
-
-/* FIXME: This doesn't actually abort anything */
-static int us_abort( Scsi_Cmnd *srb )
-{
-	return 0;
-}
-
-static int us_bus_reset( Scsi_Cmnd *srb )
-{
-	//  struct us_data *us = (struct us_data *)srb->host->hostdata[0];
-
-	US_DEBUGP("Bus reset requested\n");
-	//  us->transport_reset(us);
-	return SUCCESS;
-}
-
-/* FIXME: This doesn't actually reset anything */
-static int us_host_reset( Scsi_Cmnd *srb )
-{
-	return 0;
-}
-
-/***********************************************************************
- * /proc/scsi/ functions
- ***********************************************************************/
-
-/* we use this macro to help us write into the buffer */
-#undef SPRINTF
-#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0)
-
-int usb_stor_proc_info (char *buffer, char **start, off_t offset, 
-			int length, int hostno, int inout)
-{
-	struct us_data *us = us_list;
-	char *pos = buffer;
-	char *tmp_ptr;
-
-	/* find our data from hostno */
-	while (us) {
-		if (us->host_no == hostno)
-			break;
-		us = us->next;
-	}
-
-	/* if we couldn't find it, we return an error */
-	if (!us)
-		return -ESRCH;
-
-	/* if someone is sending us data, just throw it away */
-	if (inout)
-		return length;
-
-	/* print the controler name */
-	SPRINTF ("Host scsi%d: usb-storage\n", hostno);
-
-	/* print product and vendor strings */
-	tmp_ptr = kmalloc(256, GFP_KERNEL);
-	if (!us->pusb_dev || !tmp_ptr) {
-		SPRINTF("    Vendor: Unknown Vendor\n");
-		SPRINTF("   Product: Unknown Product\n");
-	} else {
-		SPRINTF("    Vendor: ");
-		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0)
-			SPRINTF("%s\n", tmp_ptr);
-		else
-			SPRINTF("Unknown Vendor\n");
-    
-		SPRINTF("   Product: ");
-		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0)
-			SPRINTF("%s\n", tmp_ptr);
-		else
-			SPRINTF("Unknown Product\n");
-		kfree(tmp_ptr);
-	}
-
-	SPRINTF("  Protocol: ");
-	switch (us->protocol) {
-	case US_PR_CB:
-		SPRINTF("Control/Bulk\n");
-		break;
-    
-	case US_PR_CBI:
-		SPRINTF("Control/Bulk/Interrupt\n");
-		break;
-    
-	case US_PR_BULK:
-		SPRINTF("Bulk only\n");
-		break;
-    
-	default:
-		SPRINTF("Unknown Protocol\n");
-		break;
-	}
-
-	/* show the GUID of the device */
-	SPRINTF("      GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
-
-	/*
-	 * Calculate start of next buffer, and return value.
-	 */
-	*start = buffer + offset;
-
-	if ((pos - buffer) < offset)
-		return (0);
-	else if ((pos - buffer - offset) < length)
-		return (pos - buffer - offset);
-	else
-		return (length);
-}
-
-/*
- * this defines our 'host'
- */
-
-static Scsi_Host_Template my_host_template = {
-	NULL,			    /* next */
-	NULL,			    /* module */
-	NULL,			    /* proc_dir */
-	usb_stor_proc_info,
-	NULL,			    /* name - points to unique */
-	us_detect,
-	us_release,
-	NULL,			    /* info */
-	NULL,			    /* ioctl */
-	us_command,
-	us_queuecommand,
-	NULL,			    /* eh_strategy */
-	us_abort,
-	us_bus_reset,
-	us_bus_reset,
-	us_host_reset,
-	NULL,			    /* abort */
-	NULL,			    /* reset */
-	NULL,			    /* slave_attach */
-	NULL,			    /* bios_param */
-	NULL,			    /* select_queue_depths */
-	1,			    /* can_queue */
-	-1,			    /* this_id */
-	SG_ALL,		    /* sg_tablesize */
-	1,			    /* cmd_per_lun */
-	0,			    /* present */
-	FALSE,		    /* unchecked_isa_dma */
-	FALSE,		    /* use_clustering */
-	TRUE,			    /* use_new_eh_code */
-	TRUE			    /* emulated */
-};
-
-static unsigned char sense_notready[] = {
-	0x70,			    /* current error */
-	0x00,
-	0x02,			    /* not ready */
-	0x00,
-	0x00,
-	0x0a,			    /* additional length */
-	0x00,
-	0x00,
-	0x00,
-	0x00,
-	0x04,			    /* not ready */
-	0x03,			    /* manual intervention */
-	0x00,
-	0x00,
-	0x00,
-	0x00
-};
-
-static int usb_stor_control_thread(void * __us)
-{
-	struct us_data *us = (struct us_data *)__us;
-	int action;
-
-	lock_kernel();
-
-	/*
-	 * This thread doesn't need any user-level access,
-	 * so get rid of all our resources..
-	 */
-	daemonize();
-
-	sprintf(current->comm, "usbscsi%d", us->host_number);
-
-	unlock_kernel();
-
-	up(us->notify);
-
-	for(;;) {
-		siginfo_t info;
-		int unsigned long signr;
-
-		interruptible_sleep_on(&us->waitq);
-
-		action = us->action;
-		us->action = 0;
-
-		/* FIXME: we need to examine placment of break; and 
-		 * scsi_done() calls */
-
-		switch (action) {
-		case US_ACT_COMMAND:
-			/* bad device */
-			if (us->srb->target || us->srb->lun) {
-				US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
-					   us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
-				us->srb->result = DID_BAD_TARGET << 16;
-
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				break;
-			}
-
-			/* our device has gone - pretend not ready */
-			/* FIXME: we also need to handle INQUIRY here, 
-			 * probably */
-			if (!us->pusb_dev) {
-				if (us->srb->cmnd[0] == REQUEST_SENSE) {
-					memcpy(us->srb->request_buffer, sense_notready, 
-					       sizeof(sense_notready));
-					us->srb->result = DID_OK << 16;
-				} else {
-					us->srb->result = (DID_OK << 16) | 2;
-				}
-
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				break;
-			}
-
-			/* we've got a command, let's do it! */
-			US_DEBUG(us_show_command(us->srb));
-
-			/* FIXME: this is to support Shuttle E-USB bridges, it 
-			 * appears */
-			if (us->srb->cmnd[0] == START_STOP &&
-			    us->pusb_dev->descriptor.idProduct == 0x0001 &&
-			    us->pusb_dev->descriptor.idVendor == 0x04e6)
-				us->srb->result = DID_OK << 16;
-			else {
-				us->proto_handler(us->srb, us);
-			}
-      
-			US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result);
-			us->srb->scsi_done(us->srb);
-			us->srb = NULL;
-			break;
-      
-		case US_ACT_ABORT:
-			break;
-
-		case US_ACT_DEVICE_RESET:
-			break;
-
-		case US_ACT_BUS_RESET:
-			break;
-
-		case US_ACT_HOST_RESET:
-			break;
-
-		} /* end switch on action */
-    
-		if (signal_pending(current)) {
-			/* sending SIGUSR1 makes us print out some info */
-			spin_lock_irq(&current->sigmask_lock);
-			signr = dequeue_signal(&current->blocked, &info);
-			spin_unlock_irq(&current->sigmask_lock);
-
-			if (signr == SIGUSR2) {
-				usb_stor_debug = !usb_stor_debug;
-				printk(USB_STORAGE "debug toggle = %d\n", usb_stor_debug);
-			} else {
-				break;	    /* exit the loop on any other signal */
-			}
-		}
-	}
-  
-	//  MOD_DEC_USE_COUNT;
-
-	printk("usb_stor_control_thread exiting\n");
-
-	/* FIXME: this is a hack to allow for debugging */
-	// scsi_unregister_module(MODULE_SCSI_HA, us->htmplt);
-
-	return 0;
-}	
-
-/* Probe to see if a new device is actually a SCSI device */
-static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
-{
-	struct usb_interface_descriptor *interface;
-	int i;
-	char mf[32];		     /* manufacturer */
-	char prod[32];		     /* product */
-	char serial[32];       	     /* serial number */
-	struct us_data *ss = NULL;
-	unsigned int flags = 0;
-	GUID(guid);		     /* Global Unique Identifier */
-	struct us_data *prev;
-	Scsi_Host_Template *htmplt;
-	int protocol = 0;
-	int subclass = 0;
-	struct usb_interface_descriptor *altsetting = 
-		&(dev->actconfig->interface[ifnum].altsetting[0]); 
-
-	/* clear the GUID and fetch the strings */
-	GUID_CLEAR(guid);
-	memset(mf, 0, sizeof(mf));
-	memset(prod, 0, sizeof(prod));
-	memset(serial, 0, sizeof(serial));
-	if (dev->descriptor.iManufacturer)
-		usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf));
-	if (dev->descriptor.iProduct)
-		usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod));
-	if (dev->descriptor.iSerialNumber)
-		usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial));
-	
-	/* let's examine the device now */
-
-	/* We make an exception for the shuttle E-USB */
-	if (dev->descriptor.idVendor == 0x04e6 &&
-	    dev->descriptor.idProduct == 0x0001) {
-		protocol = US_PR_CB;
-		subclass = US_SC_8070;	    /* an assumption */
-	} else if (dev->descriptor.bDeviceClass != 0 ||
-		   altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
-		   altsetting->bInterfaceSubClass < US_SC_MIN ||
-		   altsetting->bInterfaceSubClass > US_SC_MAX) {
-		/* if it's not a mass storage, we go no further */
-		return NULL;
-	}
-
-	/* At this point, we know we've got a live one */
-	US_DEBUGP("USB Mass Storage device detected\n");
-
-	/* Create a GUID for this device */
-	if (dev->descriptor.iSerialNumber && serial[0]) {
-		/* If we have a serial number, and it's a non-NULL string */
-		make_guid(guid, dev->descriptor.idVendor, 
-			  dev->descriptor.idProduct, serial);
-	} else {
-		/* We don't have a serial number, so we use 0 */
-		make_guid(guid, dev->descriptor.idVendor, 
-			  dev->descriptor.idProduct, "0");
-	}
-
-	/* Now check if we have seen this GUID before, and restore
-	 * the flags if we find it
-	 */
-	for (ss = us_list; ss != NULL; ss = ss->next) {
-		if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid))    {
-			US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
-				  GUID_ARGS(guid));
-			flags = ss->flags;
-			break;
-		}
-	}
-
-	/* If ss == NULL, then this is a new device.  Allocate memory for it */
-	if (!ss) {
-		if ((ss = (struct us_data *)kmalloc(sizeof(*ss), 
-						    GFP_KERNEL)) == NULL) {
-			printk(KERN_WARNING USB_STORAGE "Out of memory\n");
-			return NULL;
-		}
-		memset(ss, 0, sizeof(struct us_data));
-	}
-
-	/* Initialize the us_data structure with some useful info */
-	interface = altsetting;
-	ss->flags = flags;
-	ss->ifnum = ifnum;
-	ss->pusb_dev = dev;
-	ss->attention_done = 0;
-
-	/* If the device has subclass and protocol, then use that.  Otherwise, 
-	 * take data from the specific interface.
-	 */
-	if (subclass) {
-		ss->subclass = subclass;
-		ss->protocol = protocol;
-	} else {
-		ss->subclass = interface->bInterfaceSubClass;
-		ss->protocol = interface->bInterfaceProtocol;
-	}
-
-	/* set the handler pointers based on the protocol */
-	US_DEBUGP("Transport: ");
-	switch (ss->protocol) {
-	case US_PR_CB:
-		US_DEBUGPX("Control/Bulk\n");
-		ss->transport = CB_transport;
-		ss->transport_reset = CB_reset;
-		break;
-
-	case US_PR_CBI:
-		US_DEBUGPX("Control/Bulk/Interrupt\n");
-		ss->transport = CB_transport;
-		ss->transport_reset = CB_reset;
-		break;
-
-	case US_PR_BULK:
-		US_DEBUGPX("Bulk\n");
-		ss->transport = Bulk_transport;
-		ss->transport_reset = Bulk_reset;
-		break;
-
-	default:
-		US_DEBUGPX("Unknown\n");    
-		kfree(ss);
-		return NULL;
-		break;
-	}
-
-	/*
-	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
-	 * An optional interrupt is OK (necessary for CBI protocol).
-	 * We will ignore any others.
-	 */
-	for (i = 0; i < interface->bNumEndpoints; i++) {
-		/* is it an BULK endpoint? */
-		if ((interface->endpoint[i].bmAttributes &  USB_ENDPOINT_XFERTYPE_MASK)
-		    == USB_ENDPOINT_XFER_BULK) {
-			if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN)
-				ss->ep_in = interface->endpoint[i].bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK;
-			else
-				ss->ep_out = interface->endpoint[i].bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK;
-		}
-
-		/* is it an interrupt endpoint? */
-		if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 
-		    == USB_ENDPOINT_XFER_INT) {
-			ss->ep_int = interface->endpoint[i].bEndpointAddress &
-				USB_ENDPOINT_NUMBER_MASK;
-		}
-	}
-	US_DEBUGP("Endpoints In %d Out %d Int %d\n",
-		  ss->ep_in, ss->ep_out, ss->ep_int);
-
-	/* Do some basic sanity checks, and bail if we find a problem */
-	if (usb_set_interface(dev, interface->bInterfaceNumber, 0) ||
-	    !ss->ep_in || !ss->ep_out || 
-	    (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
-		US_DEBUGP("Problems with device\n");
-		if (ss->host) {
-			scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt);
-			kfree(ss->htmplt->name);
-			kfree(ss->htmplt);
-		}
-
-		kfree(ss);
-		return NULL;
-	}
-
-	/* If this is a new device (i.e. we haven't seen it before), we need to
-	 * generate a scsi host definition, and register with scsi above us 
-	 */
-	if (!ss->host) {
-		/* copy the GUID we created before */
-		US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
-		memcpy(ss->guid, guid, sizeof(guid));
-
-		/* set class specific stuff */
-		US_DEBUGP("Protocol: ");
-		switch (ss->subclass) {
-		case US_SC_RBC:
-			US_DEBUGPX("Reduced Block Commands\n");
-			break;
-
-		case US_SC_8020:
-			US_DEBUGPX("8020\n");
-			break;
-
-		case US_SC_QIC:
-			US_DEBUGPX("QIC157\n");
-			break;
-
-		case US_SC_8070:
-			US_DEBUGPX("8070\n");
-			break;
-
-		case US_SC_SCSI:
-			US_DEBUGPX("Transparent SCSI\n");
-			ss->proto_handler = transparent_scsi_command;
-			break;
-
-		case US_SC_UFI:
-			US_DEBUGPX("UFI\n");
-			ss->proto_handler = ufi_command;
-			break;
-
-		default:
-			US_DEBUGPX("Unknown\n");
-			break;
-		}
-
-		/* We only handle certain protocols.  Currently, these are
-		 *the only ones that devices use.
-		 */
-		if ((ss->subclass != US_SC_SCSI) && (ss->subclass != US_SC_UFI)) {
-			US_DEBUGP("Sorry, we do not support that protocol yet.\n");
-			US_DEBUGP("If you have a device which uses one of the unsupported\n");
-			US_DEBUGP("protocols, please contact mdharm-usb@one-eyed-alien.net\n");
-     
-			kfree(ss);
-			return NULL;
-		}
-
-		/* Allocate memory for the SCSI Host Template */
-		if ((htmplt = (Scsi_Host_Template *)
-		     kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) {
-
-			printk(KERN_WARNING USB_STORAGE "Out of memory\n");
-
-			kfree(ss);
-			return NULL;
-		}
-
-		/* Initialize the host template based on the default one */
-		memcpy(htmplt, &my_host_template, sizeof(my_host_template));
-
-		/* Grab the next host number */
-		ss->host_number = my_host_number++;
-
-		/* MDD: FIXME: this is bad.  We abuse this pointer so we
-		 * can pass the ss pointer to the host controler thread
-		 * in us_detect
-		 */
-		(struct us_data *)htmplt->proc_dir = ss; 
-
-		/* shuttle E-USB */	
-		if (dev->descriptor.idVendor == 0x04e6 &&
-		    dev->descriptor.idProduct == 0x0001) {
-			__u8 qstat[2];
-			int result;
-	    
-			result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0),
-						 1, 0xC0,
-						 0, ss->ifnum,
-						 qstat, 2, HZ*5);
-			US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
-			init_waitqueue_head(&ss->ip_waitq);
-			ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
-			result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
-						 255, (void *)ss, &ss->irq_handle);
-			if (result)
-				return NULL;
-
-			interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6);
-		} else if (ss->protocol == US_PR_CBI)
-		{
-			int result; 
-
-			init_waitqueue_head(&ss->ip_waitq);
-
-			/* set up the IRQ pipe and handler */
-			/* FIXME: This needs to get the period from the device */
-			ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
-			result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
-						 255, (void *)ss, &ss->irq_handle);
-			if (result) {
-				US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n",
-					  result);
-			}
-		}
-    
-
-		/* start up our thread */
-		{
-			DECLARE_MUTEX_LOCKED(sem);
-
-			init_waitqueue_head(&ss->waitq);
-
-			ss->notify = &sem;
-			ss->pid = kernel_thread(usb_stor_control_thread, ss,
-						CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-			if (ss->pid < 0) {
-				printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n");
-				kfree(htmplt);
-
-				kfree(ss);
-				return NULL;
-			}
-
-			/* wait for it to start */
-			down(&sem);
-		}
-
-		/* now register - our detect function will be called */
-		scsi_register_module(MODULE_SCSI_HA, htmplt);
-
-		/* put us in the list */
-		prev = (struct us_data *)&us_list;
-		while (prev->next)
-			prev = prev->next;
-		prev->next = ss;
-	}
-
-	printk(KERN_INFO "WARNING: USB Mass Storage data integrity not assured\n");
-	printk(KERN_INFO "USB Mass Storage device found at %d\n", dev->devnum);
-
-	return ss;
-}
-
-/* Handle a disconnect event from the USB core */
-static void storage_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct us_data *ss = ptr;
-
-	if (!ss)
-		return;
-
-	ss->pusb_dev = NULL;
-	//  MOD_DEC_USE_COUNT;
-}
-
-
-/***********************************************************************
- * Initialization and registration
- ***********************************************************************/
-
-int __init usb_stor_init(void)
-{
-	//  MOD_INC_USE_COUNT;
-
-	if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
-		printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ;
-		printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n", 
-		       SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
-
-		return -1 ;
-	}
-
-	/* register the driver, return -1 if error */
-	if (usb_register(&storage_driver) < 0)
-		return -1;
-
-	printk(KERN_INFO "USB Mass Storage support registered.\n");
-	return 0;
-}
-
-void __exit usb_stor_exit(void)
-{
-	usb_deregister(&storage_driver) ;
-}
-
-module_init(usb_stor_init) ;
-module_exit(usb_stor_exit) ;
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb_storage.h linux/drivers/usb/usb_storage.h
--- v2.3.46/linux/drivers/usb/usb_storage.h	Thu Feb 10 17:11:15 2000
+++ linux/drivers/usb/usb_storage.h	Wed Dec 31 16:00:00 1969
@@ -1,130 +0,0 @@
-/* Driver for USB mass storage - include file
- *
- * (c) 1999 Michael Gee (michael@linuxspecific.com)
- * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
- *
- */
-
-#include <linux/config.h>
-
-#define USB_STORAGE "usb-storage: "
-
-extern int usb_stor_debug;
-
-#ifdef CONFIG_USB_STORAGE_DEBUG
-void us_show_command(Scsi_Cmnd *srb);
-#define US_DEBUGP(x...) { if(usb_stor_debug) printk( KERN_DEBUG USB_STORAGE ## x ); }
-#define US_DEBUGPX(x...) { if(usb_stor_debug) printk( ## x ); }
-#define US_DEBUG(x)  { if(usb_stor_debug) x; }
-#else
-#define US_DEBUGP(x...)
-#define US_DEBUGPX(x...)
-#define US_DEBUG(x)
-#endif
-
-/* bit set if input */
-extern unsigned char us_direction[256/8];
-#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
-
-/* Sub Classes */
-
-#define US_SC_RBC	1		/* Typically, flash devices */
-#define US_SC_8020	2		/* CD-ROM */
-#define US_SC_QIC	3		/* QIC-157 Tapes */
-#define US_SC_UFI	4		/* Floppy */
-#define US_SC_8070	5		/* Removable media */
-#define US_SC_SCSI	6		/* Transparent */
-#define US_SC_MIN	US_SC_RBC
-#define US_SC_MAX	US_SC_SCSI
-
-/* Protocols */
-
-#define US_PR_CB	1		/* Control/Bulk w/o interrupt */
-#define US_PR_CBI	0		/* Control/Bulk/Interrupt */
-#define US_PR_BULK	0x50		/* bulk only */
-
-/*
- * Bulk only data structures (Zip 100, for example)
- */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
-	__u32	Signature;		/* contains 'USBC' */
-	__u32	Tag;			/* unique per command id */
-	__u32	DataTransferLength;	/* size of data */
-	__u8	Flags;			/* direction in bit 0 */
-	__u8	Lun;			/* LUN normally 0 */
-	__u8	Length;			/* of of the CDB */
-	__u8	CDB[16];		/* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN 	31
-#define US_BULK_CB_SIGN		0x43425355
-#define US_BULK_FLAG_IN		1
-#define US_BULK_FLAG_OUT	0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
-	__u32	Signature;		/* should = 'USBS' */
-	__u32	Tag;			/* same as original command */
-	__u32	Residue;		/* amount not transferred */
-	__u8	Status;			/* see below */
-	__u8	Filler[18];
-};
-
-#define US_BULK_CS_WRAP_LEN	13
-#define US_BULK_CS_SIGN		0x53425355
-#define US_BULK_STAT_OK		0
-#define US_BULK_STAT_FAIL	1
-#define US_BULK_STAT_PHASE	2
-
-#define US_BULK_RESET		0xff
-#define US_BULK_RESET_SOFT	1
-#define US_BULK_RESET_HARD	0
-
-/*
- * Transport return codes
- */
-
-#define USB_STOR_TRANSPORT_GOOD    0    /* Transport good, command good    */
-#define USB_STOR_TRANSPORT_FAILED  1    /* Transport good, command failed  */
-#define USB_STOR_TRANSPORT_ERROR   2    /* Transport bad (i.e. device dead */
-
-/*
- * CBI style
- */
-
-#define US_CBI_ADSC		0
-
-/* 
- * GUID definitions
- */
-
-#define GUID(x) __u32 x[3]
-#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2])
-#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0;
-#define GUID_NONE(x) (!x[0] && !x[1] && !x[2])
-#define GUID_FORMAT "%08x%08x%08x"
-#define GUID_ARGS(x) x[0], x[1], x[2]
-
-static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial)
-{
-	pg[0] = (vendor << 16) | product;
-	pg[1] = pg[2] = 0;
-	while (*serial) {
-		pg[1] <<= 4;
-		pg[1] |= pg[2] >> 28;
-		pg[2] <<= 4;
-		if (*serial >= 'a')
-			*serial -= 'a' - 'A';
-		pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0'
-			: *serial - 'A' + 10;
-		serial++;
-	}
-}
-
-/* Flag definitions */
-#define US_FL_IP_STATUS	      0x00000001         /* status uses interrupt */
-#define US_FL_FIXED_COMMAND   0x00000002 /* expand commands to fixed size */
-#define US_FL_MODE_XLATE      0x00000004 /* translate _6 to _10 comands for
-					    Win/MacOS compatibility */
diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb_storage_debug.c linux/drivers/usb/usb_storage_debug.c
--- v2.3.46/linux/drivers/usb/usb_storage_debug.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/usb_storage_debug.c	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-
-/* Driver for USB mass storage (scsi-like) devices
- * 
- * (C) Michael Gee (michael@linuxspecific.com) 1999
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/spinlock.h>
-
-#include <linux/blk.h>
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
-
-#include "usb.h"
-#include "usb_storage.h"
-
-void us_show_command(Scsi_Cmnd *srb)
-{
-	char *what = NULL;
-
-	switch (srb->cmnd[0]) {
-	case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
-	case REZERO_UNIT: what = "REZERO_UNIT"; break;
-	case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
-	case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
-	case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
-	case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
-	case READ_6: what = "READ_6"; break;
-	case WRITE_6: what = "WRITE_6"; break;
-	case SEEK_6: what = "SEEK_6"; break;
-	case READ_REVERSE: what = "READ_REVERSE"; break;
-	case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
-	case SPACE: what = "SPACE"; break;
-	case INQUIRY: what = "INQUIRY"; break;
-	case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
-	case MODE_SELECT: what = "MODE_SELECT"; break;
-	case RESERVE: what = "RESERVE"; break;
-	case RELEASE: what = "RELEASE"; break;
-	case COPY: what = "COPY"; break;
-	case ERASE: what = "ERASE"; break;
-	case MODE_SENSE: what = "MODE_SENSE"; break;
-	case START_STOP: what = "START_STOP"; break;
-	case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
-	case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
-	case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
-	case SET_WINDOW: what = "SET_WINDOW"; break;
-	case READ_CAPACITY: what = "READ_CAPACITY"; break;
-	case READ_10: what = "READ_10"; break;
-	case WRITE_10: what = "WRITE_10"; break;
-	case SEEK_10: what = "SEEK_10"; break;
-	case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
-	case VERIFY: what = "VERIFY"; break;
-	case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
-	case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
-	case SEARCH_LOW: what = "SEARCH_LOW"; break;
-	case SET_LIMITS: what = "SET_LIMITS"; break;
-	case READ_POSITION: what = "READ_POSITION"; break;
-	case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
-	case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
-	case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
-	case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
-	case COMPARE: what = "COMPARE"; break;
-	case COPY_VERIFY: what = "COPY_VERIFY"; break;
-	case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
-	case READ_BUFFER: what = "READ_BUFFER"; break;
-	case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
-	case READ_LONG: what = "READ_LONG"; break;
-	case WRITE_LONG: what = "WRITE_LONG"; break;
-	case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
-	case WRITE_SAME: what = "WRITE_SAME"; break;
-	case READ_TOC: what = "READ_TOC"; break;
-	case LOG_SELECT: what = "LOG_SELECT"; break;
-	case LOG_SENSE: what = "LOG_SENSE"; break;
-	case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
-	case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
-	case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
-	case READ_12: what = "READ_12"; break;
-	case WRITE_12: what = "WRITE_12"; break;
-	case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
-	case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
-	case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
-	case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
-	case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
-	case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
-	case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
-	default: break;
-	}
-	printk(KERN_DEBUG USB_STORAGE
-	       "Command %s (%d bytes)\n", what, srb->cmd_len);
-	printk(KERN_DEBUG USB_STORAGE 
-	       "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], 
-	       srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
-}
diff -u --recursive --new-file v2.3.46/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.46/linux/drivers/video/aty128fb.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/video/aty128fb.c	Sun Feb 20 08:48:45 2000
@@ -29,7 +29,7 @@
 
 /*
  * A special note of gratitude to ATI's devrel for providing documentation,
- * example code and hardware. Thanks Nitya.	-atong
+ * example code and hardware. Thanks Nitya.	-atong and brad
  */
 
 
@@ -129,6 +129,8 @@
     {"PCI_DEVICE_ID_ATI_RAGE128_RF", PCI_VENDOR_ID_ATI, 0x5246},
     {"PCI_DEVICE_ID_ATI_RAGE128_RK", PCI_VENDOR_ID_ATI, 0x524b},
     {"PCI_DEVICE_ID_ATI_RAGE128_RL", PCI_VENDOR_ID_ATI, 0x524c},
+    {"PCI_DEVICE_ID_ATI_RAGE128_PF", PCI_VENDOR_ID_ATI, 0x5046},
+    {"PCI_DEVICE_ID_ATI_RAGE128_PR", PCI_VENDOR_ID_ATI, 0x5052},
     {NULL, 0, 0}
 };
 
@@ -1684,8 +1686,8 @@
     } else {
         if (mac_vmode_to_var(default_vmode, default_cmode, &var))
             var = default_var;
-#endif /* CONFIG_PPC */
     }
+#endif /* CONFIG_PPC */
 #endif /* MODULE */
 
     if (noaccel)
@@ -2293,19 +2295,6 @@
     /*
      *  Accelerated functions
      */
-
-static void
-aty128_rectdraw(s16 x, s16 y, u16 width, u16 height,
-		struct fb_info_aty128 *info)
-{
-    /* perform rectangle operation */
-    wait_for_fifo(2, info);
-    aty_st_le32(DST_Y_X, (y << 16) | x);
-    aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
-
-    info->blitter_may_be_busy = 1;
-}
-
 
 static void
 aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
diff -u --recursive --new-file v2.3.46/linux/fs/Config.in linux/fs/Config.in
--- v2.3.46/linux/fs/Config.in	Wed Feb 16 17:03:52 2000
+++ linux/fs/Config.in	Sun Feb 20 16:21:49 2000
@@ -1,32 +1,32 @@
 #
-# Filesystem configuration
+# File system configuration
 #
 mainmenu_option next_comment
-comment 'Filesystems'
+comment 'File systems'
 
 bool 'Quota support' CONFIG_QUOTA
 tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
 tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
 
 
-dep_tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
+dep_tristate 'ADFS file system support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 
-tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
+tristate 'Amiga FFS file system support' CONFIG_AFFS_FS
 
-dep_tristate 'Apple Macintosh filesystem support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
+dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
 
-dep_tristate 'BFS filesystem support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
+dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
 
-# msdos filesystems
+# msdos file systems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
 dep_tristate '  MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate '    UMSDOS: Unix-like filesystem on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
 dep_tristate '  VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
-dep_tristate 'EFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
+dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
 
-tristate 'Compressed ROM filessytem support' CONFIG_CRAMFS
+tristate 'Compressed ROM file sytem support' CONFIG_CRAMFS
 
-tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS
+tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
 if [ "$CONFIG_ISO9660_FS" != "n" ]; then
    bool '  Microsoft Joliet CDROM extensions' CONFIG_JOLIET
 else
@@ -36,44 +36,47 @@
 
 tristate 'Minix fs support' CONFIG_MINIX_FS
 
-tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS
-dep_bool '  NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL
+tristate 'NTFS file system support (read only)' CONFIG_NTFS_FS
+if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool '  NTFS write support (DANGEROUS)' CONFIG_NTFS_RW
+fi
 
-tristate 'OS/2 HPFS filesystem support' CONFIG_HPFS_FS
+tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS
 
-bool '/proc filesystem support' CONFIG_PROC_FS
+bool '/proc file system support' CONFIG_PROC_FS
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool '/dev filesystem support (EXPERIMENTAL)' CONFIG_DEVFS_FS
-  if [ "$CONFIG_DEVFS_FS" = "y" ]; then
-    bool '  Debug devfs' CONFIG_DEVFS_DEBUG
-  fi
-fi
+dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL
+dep_bool '  Debug devfs' CONFIG_DEVFS_DEBUG $CONFIG_DEVFS_FS
 
 # It compiles as a module for testing only.  It should not be used
 # as a module in general.  If we make this "tristate", a bunch of people
 # who don't know what they are doing turn it on and complain when it
 # breaks.
-dep_bool '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS $CONFIG_UNIX98_PTYS
+dep_bool '/dev/pts file system for Unix98 PTYs' CONFIG_DEVPTS_FS $CONFIG_UNIX98_PTYS
 
-dep_tristate 'QNX4 filesystem support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL
-dep_bool '  QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW $CONFIG_QNX4FS_FS
+dep_tristate 'QNX4 file system support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_QNX4FS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool '  QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW
+fi
 
-tristate 'ROM filesystem support' CONFIG_ROMFS_FS
+tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 
-tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-dep_bool '  SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL
+tristate 'System V and Coherent file system support (read only)' CONFIG_SYSV_FS
+if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool '  SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE
+fi
 
-tristate 'UDF filesystem support (read only)' CONFIG_UDF_FS
+tristate 'UDF file system support (read only)' CONFIG_UDF_FS
 if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool '  UDF write support (DANGEROUS)' CONFIG_UDF_RW
+   bool '  UDF write support (DANGEROUS)' CONFIG_UDF_RW
 fi
 
-tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
-dep_bool '  UFS filesystem write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL
-
+tristate 'UFS file system support (read only)' CONFIG_UFS_FS
+if [ "$CONFIG_UFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool '  UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE
+fi
 
 if [ "$CONFIG_NET" = "y" ]; then
 
@@ -81,13 +84,15 @@
 comment 'Network File Systems'
 
 if [ "$CONFIG_INET" = "y" ]; then
-   tristate 'Coda filesystem support (advanced network fs)' CONFIG_CODA_FS
+   tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS
 
-   tristate 'NFS filesystem support' CONFIG_NFS_FS
+   tristate 'NFS file system support' CONFIG_NFS_FS
    dep_bool '  Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
 
    tristate 'NFS server support' CONFIG_NFSD
-   dep_bool '  Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3 $CONFIG_NFSD $CONFIG_EXPERIMENTAL
+   if [ "$CONFIG_NFSD" != "n" ]; then
+      bool '  Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
+   fi
 
    if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
       define_tristate CONFIG_SUNRPC y
@@ -101,10 +106,13 @@
 	 define_tristate CONFIG_LOCKD n
       fi
    fi
-   tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS
+   if [ "$CONFIG_NFSD_V3" = "y" ]; then
+     define_bool CONFIG_LOCKD_V4 y
+   fi
+   tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS
 fi
 if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
-   tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
+   tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
    if [ "$CONFIG_NCP_FS" != "n" ]; then
       source fs/ncpfs/Config.in
    fi
diff -u --recursive --new-file v2.3.46/linux/fs/adfs/inode.c linux/fs/adfs/inode.c
--- v2.3.46/linux/fs/adfs/inode.c	Sun Feb 13 19:29:04 2000
+++ linux/fs/adfs/inode.c	Wed Feb 16 20:23:47 2000
@@ -334,10 +334,8 @@
 	if (error)
 		goto out;
 
-	if (ia_valid & ATTR_SIZE) {
-		inode->i_size = attr->ia_size;
+	if (ia_valid & ATTR_SIZE)
 		vmtruncate(inode, attr->ia_size);
-	}
 	if (ia_valid & ATTR_MTIME) {
 		inode->i_mtime = attr->ia_mtime;
 		adfs_unix2adfs_time(inode, attr->ia_mtime);
diff -u --recursive --new-file v2.3.46/linux/fs/attr.c linux/fs/attr.c
--- v2.3.46/linux/fs/attr.c	Sun Feb 13 19:29:04 2000
+++ linux/fs/attr.c	Wed Feb 16 20:23:47 2000
@@ -62,10 +62,8 @@
 		inode->i_uid = attr->ia_uid;
 	if (ia_valid & ATTR_GID)
 		inode->i_gid = attr->ia_gid;
-	if (ia_valid & ATTR_SIZE) {
-		inode->i_size = attr->ia_size;
+	if (ia_valid & ATTR_SIZE)
 		vmtruncate(inode, attr->ia_size);
-	}
 	if (ia_valid & ATTR_ATIME)
 		inode->i_atime = attr->ia_atime;
 	if (ia_valid & ATTR_MTIME)
diff -u --recursive --new-file v2.3.46/linux/fs/binfmt_script.c linux/fs/binfmt_script.c
--- v2.3.46/linux/fs/binfmt_script.c	Tue Aug  3 10:18:39 1999
+++ linux/fs/binfmt_script.c	Sun Feb 20 20:16:37 2000
@@ -14,7 +14,7 @@
 
 static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
 {
-	char *cp, *i_name, *i_name_start, *i_arg;
+	char *cp, *i_name, *i_arg;
 	struct dentry * dentry;
 	char interp[128];
 	int retval;
@@ -44,17 +44,15 @@
 	for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
 	if (*cp == '\0') 
 		return -ENOEXEC; /* No interpreter name found */
-	i_name_start = i_name = cp;
+	i_name = cp;
 	i_arg = 0;
-	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
- 		if (*cp == '/')
-			i_name = cp+1;
-	}
+	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
+		/* nothing */ ;
 	while ((*cp == ' ') || (*cp == '\t'))
 		*cp++ = '\0';
 	if (*cp)
 		i_arg = cp;
-	strcpy (interp, i_name_start);
+	strcpy (interp, i_name);
 	/*
 	 * OK, we've parsed out the interpreter name and
 	 * (optional) argument.
diff -u --recursive --new-file v2.3.46/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.46/linux/fs/buffer.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/buffer.c	Wed Feb 16 20:23:47 2000
@@ -1692,8 +1692,12 @@
 int generic_commit_write(struct file *file, struct page *page,
 		unsigned from, unsigned to)
 {
-	__block_commit_write((struct inode*)page->mapping->host,page,from,to);
+	struct inode *inode = (struct inode*)page->mapping->host;
+	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+	__block_commit_write(inode,page,from,to);
 	kunmap(page);
+	if (pos > inode->i_size)
+		inode->i_size = pos;
 	return 0;
 }
 
@@ -2010,7 +2014,6 @@
 	kaddr = (char*)page_address(page);
 	memcpy(kaddr, symname, len-1);
 	mapping->a_ops->commit_write(NULL, page, 0, len-1);
-	inode->i_size = len-1;
 	/*
 	 * Notice that we are _not_ going to block here - end of page is
 	 * unmapped, so this will only try to map the rest of page, see
@@ -2026,7 +2029,6 @@
 	mark_inode_dirty(inode);
 	return 0;
 fail_map:
-	inode->i_size = len-1;
 	UnlockPage(page);
 	page_cache_release(page);
 fail:
diff -u --recursive --new-file v2.3.46/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.3.46/linux/fs/ext2/inode.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/ext2/inode.c	Sun Feb 20 13:09:46 2000
@@ -35,7 +35,9 @@
  */
 void ext2_put_inode (struct inode * inode)
 {
+	lock_kernel();
 	ext2_discard_prealloc (inode);
+	unlock_kernel();
 }
 
 /*
@@ -43,6 +45,8 @@
  */
 void ext2_delete_inode (struct inode * inode)
 {
+	lock_kernel();
+
 	if (is_bad_inode(inode) ||
 	    inode->i_ino == EXT2_ACL_IDX_INO ||
 	    inode->i_ino == EXT2_ACL_DATA_INO)
@@ -54,6 +58,8 @@
 	if (inode->i_blocks)
 		ext2_truncate (inode);
 	ext2_free_inode (inode);
+
+	unlock_kernel();
 }
 
 #define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)]))
@@ -893,7 +899,9 @@
 
 void ext2_write_inode (struct inode * inode)
 {
+	lock_kernel();
 	ext2_update_inode (inode, 0);
+	unlock_kernel();
 }
 
 int ext2_sync_inode (struct inode *inode)
diff -u --recursive --new-file v2.3.46/linux/fs/inode.c linux/fs/inode.c
--- v2.3.46/linux/fs/inode.c	Sun Feb 13 19:29:04 2000
+++ linux/fs/inode.c	Sun Feb 20 20:51:56 2000
@@ -156,11 +156,26 @@
 		inode->i_sb->s_op->write_inode(inode);
 }
 
+static inline void __iget(struct inode * inode)
+{
+	if (!inode->i_count++)
+	{
+		if (!(inode->i_state & I_DIRTY))
+		{
+			list_del(&inode->i_list);
+			list_add(&inode->i_list, &inode_in_use);
+		}
+		inodes_stat.nr_unused--;
+	}
+}
+
 static inline void sync_one(struct inode *inode)
 {
 	if (inode->i_state & I_LOCK) {
+		__iget(inode);
 		spin_unlock(&inode_lock);
 		__wait_on_inode(inode);
+		iput(inode);
 		spin_lock(&inode_lock);
 	} else {
 		list_del(&inode->i_list);
@@ -253,6 +268,8 @@
 		BUG();
 	if (!(inode->i_state & I_FREEING))
 		BUG();
+	if (inode->i_state & I_CLEAR)
+		BUG();
 	wait_on_inode(inode);
 	if (IS_QUOTAINIT(inode))
 		DQUOT_DROP(inode);
@@ -262,7 +279,7 @@
 		bdput(inode->i_bdev);
 		inode->i_bdev = NULL;
 	}
-	inode->i_state = 0;
+	inode->i_state = I_CLEAR;
 }
 
 /*
@@ -377,6 +394,8 @@
 
 		entry = entry->prev;
 		inode = INODE(tmp);
+		if (inode->i_state & (I_FREEING|I_CLEAR))
+			BUG();
 		if (!CAN_UNUSE(inode))
 			continue;
 		if (inode->i_count)
@@ -413,19 +432,6 @@
 	return 0;
 }
 
-static inline void __iget(struct inode * inode)
-{
-	if (!inode->i_count++)
-	{
-		if (!(inode->i_state & I_DIRTY))
-		{
-			list_del(&inode->i_list);
-			list_add(&inode->i_list, &inode_in_use);
-		}
-		inodes_stat.nr_unused--;
-	}
-}
-
 /*
  * Called with the inode lock held.
  * NOTE: we are not increasing the inode-refcount, you must call __iget()
@@ -603,6 +609,11 @@
 	if (!(inode->i_state & I_FREEING))
 		__iget(inode);
 	else
+		/*
+		 * Handle the case where s_op->clear_inode is not been
+		 * called yet, and somebody is calling igrab
+		 * while the inode is getting freed.
+		 */
 		inode = NULL;
 	spin_unlock(&inode_lock);
 	if (inode)
@@ -669,32 +680,39 @@
 				list_del(&inode->i_list);
 				INIT_LIST_HEAD(&inode->i_list);
 				inode->i_state|=I_FREEING;
+				spin_unlock(&inode_lock);
+
+				destroy = 1;
 				if (op && op->delete_inode) {
 					void (*delete)(struct inode *) = op->delete_inode;
-					spin_unlock(&inode_lock);
 					if (inode->i_data.nrpages)
 						truncate_inode_pages(&inode->i_data, 0);
+					/* s_op->delete_inode internally recalls clear_inode() */
 					delete(inode);
-					spin_lock(&inode_lock);
-				}
-			}
-			if (list_empty(&inode->i_hash)) {
-				list_del(&inode->i_list);
-				INIT_LIST_HEAD(&inode->i_list);
-				inode->i_state|=I_FREEING;
-				spin_unlock(&inode_lock);
-				clear_inode(inode);
-				destroy = 1;
+				} else
+					clear_inode(inode);
+				if (inode->i_state != I_CLEAR)
+					BUG();
+
 				spin_lock(&inode_lock);
-			}
-			else
-			{
-				if (!(inode->i_state & I_DIRTY)) {
+			} else {
+				if (!list_empty(&inode->i_hash)) {
+					if (!(inode->i_state & I_DIRTY)) {
+						list_del(&inode->i_list);
+						list_add(&inode->i_list,
+							 &inode_unused);
+					}
+					inodes_stat.nr_unused++;
+				} else {
+					/* magic nfs path */
 					list_del(&inode->i_list);
-					list_add(&inode->i_list,
-						 &inode_unused);
+					INIT_LIST_HEAD(&inode->i_list);
+					inode->i_state|=I_FREEING;
+					spin_unlock(&inode_lock);
+					clear_inode(inode);
+					destroy = 1;
+					spin_lock(&inode_lock);
 				}
-				inodes_stat.nr_unused++;
 			}
 #ifdef INODE_PARANOIA
 if (inode->i_flock)
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/Makefile linux/fs/lockd/Makefile
--- v2.3.46/linux/fs/lockd/Makefile	Mon Apr  7 11:35:30 1997
+++ linux/fs/lockd/Makefile	Thu Feb 17 17:23:30 2000
@@ -10,6 +10,11 @@
 O_TARGET := lockd.o
 O_OBJS   := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
 	    svcproc.o svcsubs.o mon.o xdr.o
+
+ifdef CONFIG_LOCKD_V4
+ O_OBJS += xdr4.o svc4proc.o
+endif
+
 OX_OBJS  := lockd_syms.o
 M_OBJS   := $(O_TARGET)
 
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c
--- v2.3.46/linux/fs/lockd/clntproc.c	Wed Oct 27 16:34:12 1999
+++ linux/fs/lockd/clntproc.c	Sun Feb 20 20:37:48 2000
@@ -69,7 +69,7 @@
 	call->a_args.lock    = *lock;
 	call->a_args.lock.caller = system_utsname.nodename;
 
-	init_waitqueue_head(&lock->fl.fl_wait);
+	init_waitqueue_head(&call->a_args.lock.fl.fl_wait);
 	/* set default data area */
 	call->a_args.lock.oh.data = call->a_owner;
 
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/lockd_syms.c linux/fs/lockd/lockd_syms.c
--- v2.3.46/linux/fs/lockd/lockd_syms.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/lockd/lockd_syms.c	Thu Feb 17 17:23:30 2000
@@ -39,4 +39,15 @@
 EXPORT_SYMBOL(nlmsvc_grace_period);
 EXPORT_SYMBOL(nlmsvc_timeout);
 
+#ifdef CONFIG_LOCKD_V4
+
+/* NLM4 exported symbols */ 
+EXPORT_SYMBOL(nlm4_rofs);
+EXPORT_SYMBOL(nlm4_stale_fh);
+EXPORT_SYMBOL(nlm4_deadlock);
+EXPORT_SYMBOL(nlm4_failed);
+EXPORT_SYMBOL(nlm4_fbig);
+
+#endif
+
 #endif /* CONFIG_MODULES */
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svc.c linux/fs/lockd/svc.c
--- v2.3.46/linux/fs/lockd/svc.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/lockd/svc.c	Thu Feb 17 17:23:30 2000
@@ -343,7 +343,7 @@
 static struct svc_version	nlmsvc_version3 = {
 	3, 24, nlmsvc_procedures, NULL
 };
-#ifdef CONFIG_NFSD_NFS3
+#ifdef CONFIG_LOCKD_V4
 static struct svc_version	nlmsvc_version4 = {
 	4, 24, nlmsvc_procedures4, NULL
 };
@@ -353,7 +353,7 @@
 	&nlmsvc_version1,
 	NULL,
 	&nlmsvc_version3,
-#ifdef CONFIG_NFSD_NFS3
+#ifdef CONFIG_LOCKD_V4
 	&nlmsvc_version4,
 #endif
 };
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svc4proc.c linux/fs/lockd/svc4proc.c
--- v2.3.46/linux/fs/lockd/svc4proc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/lockd/svc4proc.c	Thu Feb 17 17:23:30 2000
@@ -0,0 +1,561 @@
+/*
+ * linux/fs/lockd/svc4proc.c
+ *
+ * Lockd server procedures. We don't implement the NLM_*_RES 
+ * procedures because we don't use the async procedures.
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/in.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/lockd/lockd.h>
+#include <linux/lockd/share.h>
+#include <linux/lockd/sm_inter.h>
+
+
+#define NLMDBG_FACILITY		NLMDBG_CLIENT
+
+static u32	nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
+static void	nlm4svc_callback_exit(struct rpc_task *);
+
+/*
+ * Obtain client and file from arguments
+ */
+static u32
+nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+			struct nlm_host **hostp, struct nlm_file **filp)
+{
+	struct nlm_host		*host = NULL;
+	struct nlm_file		*file = NULL;
+	struct nlm_lock		*lock = &argp->lock;
+	u32			error = 0;
+
+	/* nfsd callbacks must have been installed for this procedure */
+	if (!nlmsvc_ops)
+		return nlm_lck_denied_nolocks;
+
+	/* Obtain handle for client host */
+	if (rqstp->rq_client == NULL) {
+		printk(KERN_NOTICE
+			"lockd: unauthenticated request from (%08x:%d)\n",
+			ntohl(rqstp->rq_addr.sin_addr.s_addr),
+			ntohs(rqstp->rq_addr.sin_port));
+		return nlm_lck_denied_nolocks;
+	}
+
+	/* Obtain host handle */
+	if (!(host = nlmsvc_lookup_host(rqstp))
+	 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+		goto no_locks;
+	*hostp = host;
+
+	/* Obtain file pointer. Not used by FREE_ALL call. */
+	if (filp != NULL) {
+		if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
+			goto no_locks;
+		*filp = file;
+
+		/* Set up the missing parts of the file_lock structure */
+		lock->fl.fl_file  = &file->f_file;
+		lock->fl.fl_owner = (fl_owner_t) host;
+	}
+
+	return 0;
+
+no_locks:
+	if (host)
+		nlm_release_host(host);
+ 	if (error)
+		return error;	
+	return nlm_lck_denied_nolocks;
+}
+
+/*
+ * NULL: Test for presence of service
+ */
+static int
+nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+	dprintk("lockd: NULL          called\n");
+	return rpc_success;
+}
+
+/*
+ * TEST: Check for conflicting lock
+ */
+static int
+nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+				         struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: TEST4        called\n");
+	resp->cookie = argp->cookie;
+
+	/* Don't accept test requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now check for conflicting locks */
+	resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+
+	dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+static int
+nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+				         struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: LOCK          called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept new lock requests during grace period */
+	if (nlmsvc_grace_period && !argp->reclaim) {
+		resp->status = nlm_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+#if 0
+	/* If supplied state doesn't match current state, we assume it's
+	 * an old request that time-warped somehow. Any error return would
+	 * do in this case because it's irrelevant anyway.
+	 *
+	 * NB: We don't retrieve the remote host's state yet.
+	 */
+	if (host->h_nsmstate && host->h_nsmstate != argp->state) {
+		resp->status = nlm_lck_denied_nolocks;
+	} else
+#endif
+
+	/* Now try to lock the file */
+	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
+					argp->block, &argp->cookie);
+
+	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+static int
+nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
+				           struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: CANCEL        called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Try to cancel request. */
+	resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+
+	dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * UNLOCK: release a lock
+ */
+static int
+nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
+				           struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: UNLOCK        called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept new lock requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now try to remove the lock */
+	resp->status = nlmsvc_unlock(file, &argp->lock);
+
+	dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * GRANTED: A server calls us to tell that a process' lock request
+ * was granted
+ */
+static int
+nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
+				            struct nlm_res  *resp)
+{
+	resp->cookie = argp->cookie;
+
+	dprintk("lockd: GRANTED       called\n");
+	resp->status = nlmclnt_grant(&argp->lock);
+	dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
+	return rpc_success;
+}
+
+/*
+ * `Async' versions of the above service routines. They aren't really,
+ * because we send the callback before the reply proper. I hope this
+ * doesn't break any clients.
+ */
+static int
+nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+					     void	     *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: TEST_MSG      called\n");
+
+	if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+					     void	     *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: LOCK_MSG      called\n");
+
+	if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+					       void	       *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: CANCEL_MSG    called\n");
+
+	if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+                                               void            *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: UNLOCK_MSG    called\n");
+
+	if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+                                                void            *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: GRANTED_MSG   called\n");
+
+	if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
+	return stat;
+}
+
+/*
+ * SHARE: create a DOS share or alter existing share.
+ */
+static int
+nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
+				          struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: SHARE         called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept new lock requests during grace period */
+	if (nlmsvc_grace_period && !argp->reclaim) {
+		resp->status = nlm_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now try to create the share */
+	resp->status = nlmsvc_share_file(host, file, argp);
+
+	dprintk("lockd: SHARE         status %d\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * UNSHARE: Release a DOS share.
+ */
+static int
+nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
+				            struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: UNSHARE       called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now try to lock the file */
+	resp->status = nlmsvc_unshare_file(host, file, argp);
+
+	dprintk("lockd: UNSHARE       status %d\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * NM_LOCK: Create an unmonitored lock
+ */
+static int
+nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+				            struct nlm_res  *resp)
+{
+	dprintk("lockd: NM_LOCK       called\n");
+
+	argp->monitor = 0;		/* just clean the monitor flag */
+	return nlm4svc_proc_lock(rqstp, argp, resp);
+}
+
+/*
+ * FREE_ALL: Release all locks and shares held by client
+ */
+static int
+nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
+					     void            *resp)
+{
+	struct nlm_host	*host;
+
+	/* Obtain client */
+	if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
+		return rpc_success;
+
+	nlmsvc_free_host_resources(host);
+	nlm_release_host(host);
+	return rpc_success;
+}
+
+/*
+ * SM_NOTIFY: private callback from statd (not part of official NLM proto)
+ */
+static int
+nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
+					      void	        *resp)
+{
+	struct sockaddr_in	saddr = rqstp->rq_addr;
+	struct nlm_host		*host;
+
+	dprintk("lockd: SM_NOTIFY     called\n");
+	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
+	 || ntohs(saddr.sin_port) >= 1024) {
+		printk(KERN_WARNING
+			"lockd: rejected NSM callback from %08x:%d\n",
+			ntohl(rqstp->rq_addr.sin_addr.s_addr),
+			ntohs(rqstp->rq_addr.sin_port));
+		return rpc_system_err;
+	}
+
+	/* Obtain the host pointer for this NFS server and try to
+	 * reclaim all locks we hold on this server.
+	 */
+	saddr.sin_addr.s_addr = argp->addr;	
+	if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
+		nlmclnt_recovery(host, argp->state);
+		nlm_release_host(host);
+	}
+
+	/* If we run on an NFS server, delete all locks held by the client */
+	if (nlmsvc_ops != NULL) {
+		struct svc_client	*clnt;
+		saddr.sin_addr.s_addr = argp->addr;	
+		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
+		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+			nlmsvc_free_host_resources(host);
+		}
+		nlm_release_host(host);
+	}
+
+	return rpc_success;
+}
+
+/*
+ * This is the generic lockd callback for async RPC calls
+ */
+static u32
+nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_rqst	*call;
+
+	if (!(call = nlmclnt_alloc_call()))
+		return rpc_system_err;
+
+	host = nlmclnt_lookup_host(&rqstp->rq_addr,
+				rqstp->rq_prot, rqstp->rq_vers);
+	if (!host) {
+		rpc_free(call);
+		return rpc_system_err;
+	}
+
+	call->a_flags = RPC_TASK_ASYNC;
+	call->a_host  = host;
+	memcpy(&call->a_args, resp, sizeof(*resp));
+
+/* FIXME this should become nlmSVC_async_call when that code gets
+   merged in XXX */
+	if (nlmclnt_async_call(call, proc, nlm4svc_callback_exit) < 0)
+		return rpc_system_err;
+
+	return rpc_success;
+}
+
+static void
+nlm4svc_callback_exit(struct rpc_task *task)
+{
+	struct nlm_rqst	*call = (struct nlm_rqst *) task->tk_calldata;
+
+	if (task->tk_status < 0) {
+		dprintk("lockd: %4d callback failed (errno = %d)\n",
+					task->tk_pid, -task->tk_status);
+	}
+	nlm_release_host(call->a_host);
+	rpc_free(call);
+}
+
+/*
+ * NLM Server procedures.
+ */
+
+#define nlm4svc_encode_norep	nlm4svc_encode_void
+#define nlm4svc_decode_norep	nlm4svc_decode_void
+#define nlm4svc_decode_testres	nlm4svc_decode_void
+#define nlm4svc_decode_lockres	nlm4svc_decode_void
+#define nlm4svc_decode_unlockres	nlm4svc_decode_void
+#define nlm4svc_decode_cancelres	nlm4svc_decode_void
+#define nlm4svc_decode_grantedres	nlm4svc_decode_void
+
+#define nlm4svc_proc_none	nlm4svc_proc_null
+#define nlm4svc_proc_test_res	nlm4svc_proc_null
+#define nlm4svc_proc_lock_res	nlm4svc_proc_null
+#define nlm4svc_proc_cancel_res	nlm4svc_proc_null
+#define nlm4svc_proc_unlock_res	nlm4svc_proc_null
+#define nlm4svc_proc_granted_res	nlm4svc_proc_null
+
+struct nlm_void			{ int dummy; };
+
+#define PROC(name, xargt, xrest, argt, rest)	\
+ { (svc_procfunc) nlm4svc_proc_##name,	\
+   (kxdrproc_t) nlm4svc_decode_##xargt,	\
+   (kxdrproc_t) nlm4svc_encode_##xrest,	\
+   NULL,				\
+   sizeof(struct nlm_##argt),		\
+   sizeof(struct nlm_##rest),		\
+   0,					\
+   0					\
+ }
+struct svc_procedure		nlmsvc_procedures4[] = {
+  PROC(null,		void,		void,		void,	void),
+  PROC(test,		testargs,	testres,	args,	res),
+  PROC(lock,		lockargs,	res,		args,	res),
+  PROC(cancel,		cancargs,	res,		args,	res),
+  PROC(unlock,		unlockargs,	res,		args,	res),
+  PROC(granted,		testargs,	res,		args,	res),
+  PROC(test_msg,	testargs,	norep,		args,	void),
+  PROC(lock_msg,	lockargs,	norep,		args,	void),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
+  PROC(granted_msg,	testargs,	norep,		args,	void),
+  PROC(test_res,	testres,	norep,		res,	void),
+  PROC(lock_res,	lockres,	norep,		res,	void),
+  PROC(cancel_res,	cancelres,	norep,		res,	void),
+  PROC(unlock_res,	unlockres,	norep,		res,	void),
+  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(share,		shareargs,	shareres,	args,	res),
+  PROC(unshare,		shareargs,	shareres,	args,	res),
+  PROC(nm_lock,		lockargs,	res,		args,	res),
+  PROC(free_all,	notify,		void,		args,	void),
+
+  /* statd callback */
+  PROC(sm_notify,	reboot,		void,		reboot,	void),
+};
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c
--- v2.3.46/linux/fs/lockd/svclock.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/lockd/svclock.c	Sun Feb 20 10:41:18 2000
@@ -20,6 +20,7 @@
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -98,9 +99,10 @@
 				lock->fl.fl_end, lock->fl.fl_type);
 	for (head = &nlm_blocked; (block = *head); head = &block->b_next) {
 		fl = &block->b_call.a_args.lock.fl;
-		dprintk("       check f=%p pd=%d %ld-%ld ty=%d\n",
+		dprintk("lockd: check f=%p pd=%d %ld-%ld ty=%d cookie=%x\n",
 				block->b_file, fl->fl_pid, fl->fl_start,
-				fl->fl_end, fl->fl_type);
+				fl->fl_end, fl->fl_type,
+				*(unsigned int*)(block->b_call.a_args.cookie.data));
 		if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
 			if (remove)
 				*head = block->b_next;
@@ -129,6 +131,8 @@
 	struct nlm_block *block;
 
 	for (block = nlm_blocked; block; block = block->b_next) {
+		dprintk("cookie: head of blocked queue %p, block %p\n", 
+			nlm_blocked, block);
 		if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie))
 			break;
 	}
@@ -310,7 +314,13 @@
 		switch(-error) {
 		case 0:
 			return nlm_granted;
-		case EDEADLK:			/* no applicable NLM status */
+		case EDEADLK:
+#ifdef CONFIG_LOCKD_V4
+			return nlm4_deadlock; /* will be downgraded to lck_deined if this
+					       * is a NLMv1,3 request */
+#else
+			/* no applicable NLM status */
+#endif
 		case EAGAIN:
 			return nlm_lck_denied;
 		default:			/* includes ENOLCK */
@@ -541,6 +551,8 @@
 	unsigned long		timeout;
 
 	dprintk("lockd: GRANT_MSG RPC callback\n");
+	dprintk("callback: looking for cookie %x \n", 
+		*(unsigned int *)(call->a_args.cookie.data));
 	if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {
 		dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));
 		return;
@@ -617,7 +629,7 @@
 	dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 			nlm_blocked,
 			nlm_blocked? nlm_blocked->b_when : 0);
-	while ((block = nlm_blocked) && block->b_when < jiffies) {
+	while ((block = nlm_blocked) && block->b_when <= jiffies) {
 		dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
 			block, block->b_when, block->b_done);
 		if (block->b_done)
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svcproc.c linux/fs/lockd/svcproc.c
--- v2.3.46/linux/fs/lockd/svcproc.c	Fri Jan 21 18:19:17 2000
+++ linux/fs/lockd/svcproc.c	Sun Feb 20 10:41:18 2000
@@ -7,6 +7,7 @@
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/malloc.h>
@@ -24,6 +25,31 @@
 static u32	nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
 static void	nlmsvc_callback_exit(struct rpc_task *);
 
+#ifdef CONFIG_LOCKD_V4
+static u32
+cast_to_nlm(u32 status, u32 vers)
+{
+
+	if (vers != 4){
+		switch(ntohl(status)){
+		case NLM_LCK_GRANTED:
+		case NLM_LCK_DENIED:
+		case NLM_LCK_DENIED_NOLOCKS:
+		case NLM_LCK_BLOCKED:
+		case NLM_LCK_DENIED_GRACE_PERIOD:
+			break;
+		default:
+			status = NLM_LCK_DENIED_NOLOCKS;
+		}
+	}
+
+	return (status);
+}
+#define	cast_status(status) (cast_to_nlm(status, rqstp->rq_vers))
+#else
+#define cast_status(status) (status)
+#endif
+
 /*
  * Obtain client and file from arguments
  */
@@ -108,9 +134,10 @@
 		return rpc_success;
 
 	/* Now check for conflicting locks */
-	resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+	resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
 
-	dprintk("lockd: TEST          status %d\n", ntohl(resp->status));
+	dprintk("lockd: TEST          status %d vers %d\n",
+		ntohl(resp->status), rqstp->rq_vers);
 	nlm_release_host(host);
 	nlm_release_file(file);
 	return rpc_success;
@@ -150,8 +177,8 @@
 #endif
 
 	/* Now try to lock the file */
-	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
-					argp->block, &argp->cookie);
+	resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
+					       argp->block, &argp->cookie));
 
 	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -181,7 +208,7 @@
 		return rpc_success;
 
 	/* Try to cancel request. */
-	resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+	resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
 
 	dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -214,7 +241,7 @@
 		return rpc_success;
 
 	/* Now try to remove the lock */
-	resp->status = nlmsvc_unlock(file, &argp->lock);
+	resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
 
 	dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -338,7 +365,7 @@
 		return rpc_success;
 
 	/* Now try to create the share */
-	resp->status = nlmsvc_share_file(host, file, argp);
+	resp->status = cast_status(nlmsvc_share_file(host, file, argp));
 
 	dprintk("lockd: SHARE         status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -370,8 +397,8 @@
 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 		return rpc_success;
 
-	/* Now try to lock the file */
-	resp->status = nlmsvc_unshare_file(host, file, argp);
+	/* Now try to unshare the file */
+	resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
 
 	dprintk("lockd: UNSHARE       status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svcsubs.c linux/fs/lockd/svcsubs.c
--- v2.3.46/linux/fs/lockd/svcsubs.c	Fri Jan 21 18:19:17 2000
+++ linux/fs/lockd/svcsubs.c	Sun Feb 20 10:41:18 2000
@@ -6,6 +6,7 @@
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/sched.h>
@@ -105,6 +106,11 @@
 
 out_free:
 	kfree(file);
+#ifdef CONFIG_LOCKD_V4
+	if (nfserr == 1)
+		nfserr = nlm4_stale_fh;
+	else
+#endif
 	nfserr = nlm_lck_denied;
 	goto out_unlock;
 }
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/xdr.c linux/fs/lockd/xdr.c
--- v2.3.46/linux/fs/lockd/xdr.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/lockd/xdr.c	Sun Feb 20 20:37:48 2000
@@ -6,6 +6,7 @@
  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/utsname.h>
@@ -47,6 +48,14 @@
 	nlm_lck_blocked = htonl(NLM_LCK_BLOCKED);
 	nlm_lck_denied_grace_period = htonl(NLM_LCK_DENIED_GRACE_PERIOD);
 
+#ifdef CONFIG_LOCKD_V4
+	nlm4_deadlock = htonl(NLM_DEADLCK);
+	nlm4_rofs = htonl(NLM_ROFS);
+	nlm4_stale_fh = htonl(NLM_STALE_FH);
+	nlm4_fbig = htonl(NLM_FBIG);
+	nlm4_failed = htonl(NLM_FAILED);
+#endif
+
 	inited = 1;
 }
 
@@ -541,7 +550,8 @@
     { "nlm_" #proc,						\
       (kxdrproc_t) nlmclt_encode_##argtype,			\
       (kxdrproc_t) nlmclt_decode_##restype,			\
-      MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2		\
+      MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2,		\
+      0								\
     }
 
 static struct rpc_procinfo	nlm_procedures[] = {
@@ -586,11 +596,18 @@
 	3, 24, nlm_procedures,
 };
 
+#ifdef 	CONFIG_LOCKD_V4
+extern struct rpc_version nlm_version4;
+#endif
+
 static struct rpc_version *	nlm_versions[] = {
 	NULL,
 	&nlm_version1,
 	NULL,
 	&nlm_version3,
+#ifdef 	CONFIG_LOCKD_V4
+	&nlm_version4,
+#endif
 };
 
 static struct rpc_stat		nlm_stats;
diff -u --recursive --new-file v2.3.46/linux/fs/lockd/xdr4.c linux/fs/lockd/xdr4.c
--- v2.3.46/linux/fs/lockd/xdr4.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/lockd/xdr4.c	Thu Feb 17 17:23:30 2000
@@ -0,0 +1,601 @@
+/*
+ * linux/fs/lockd/xdr4.c
+ *
+ * XDR support for lockd and the lock client.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <linux/nfs.h>
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
+
+#define NLMDBG_FACILITY		NLMDBG_XDR
+#define NLM_MAXSTRLEN		1024
+#define OFFSET_MAX		((off_t)LONG_MAX)
+
+#define QUADLEN(len)		(((len) + 3) >> 2)
+
+u32     nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig,
+	nlm4_failed;
+
+
+typedef struct nlm_args	nlm_args;
+
+static inline off_t
+size_to_off_t(__s64 size)
+{
+        size = (size > (__s64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size;
+        return (size < (__s64)-LONG_MAX) ? (off_t)-LONG_MAX : (off_t) size;
+}
+
+/*
+ * XDR functions for basic NLM types
+ */
+static u32 *
+nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
+{
+	unsigned int	len;
+
+	len = ntohl(*p++);
+	
+	if(len==0)
+	{
+		c->len=4;
+		memset(c->data, 0, 4);	/* hockeypux brain damage */
+	}
+	else if(len<=8)
+	{
+		c->len=len;
+		memcpy(c->data, p, len);
+		p+=(len+3)>>2;
+	}
+	else 
+	{
+		printk(KERN_NOTICE
+			"lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len);
+		return NULL;
+	}
+	return p;
+}
+
+static u32 *
+nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
+{
+	*p++ = htonl(c->len);
+	memcpy(p, c->data, c->len);
+	p+=(c->len+3)>>2;
+	return p;
+}
+
+static u32 *
+nlm4_decode_fh(u32 *p, struct nfs_fh *f)
+{
+	memset(f->data, 0, sizeof(f->data));
+#ifdef NFS_MAXFHSIZE
+	f->size = ntohl(*p++);
+	if (f->size > NFS_MAXFHSIZE) {
+		printk(KERN_NOTICE
+			"lockd: bad fhandle size %x (should be %d)\n",
+			f->size, NFS_MAXFHSIZE);
+		return NULL;
+	}
+      	memcpy(f->data, p, f->size);
+	return p + XDR_QUADLEN(f->size);
+#else
+	if (ntohl(*p++) != NFS_FHSIZE)
+		return NULL; /* for now, all filehandles are 32 bytes */
+	memcpy(f->data, p, NFS_FHSIZE);
+	return p + XDR_QUADLEN(NFS_FHSIZE);
+#endif
+}
+
+static u32 *
+nlm4_encode_fh(u32 *p, struct nfs_fh *f)
+{
+#ifdef NFS_MAXFHSIZE
+	*p++ = htonl(f->size);
+	memcpy(p, f->data, f->size);
+	return p + XDR_QUADLEN(f->size);
+#else
+	*p++ = htonl(NFS_FHSIZE);
+	memcpy(p, f->data, NFS_FHSIZE);
+	return p + XDR_QUADLEN(NFS_FHSIZE);
+#endif
+}
+
+/*
+ * Encode and decode owner handle
+ */
+static u32 *
+nlm4_decode_oh(u32 *p, struct xdr_netobj *oh)
+{
+	return xdr_decode_netobj(p, oh);
+}
+
+static u32 *
+nlm4_encode_oh(u32 *p, struct xdr_netobj *oh)
+{
+	return xdr_encode_netobj(p, oh);
+}
+
+static u32 *
+nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
+{
+	struct file_lock	*fl = &lock->fl;
+	__s64			len, start, end;
+	int			tmp;
+
+	if (!(p = xdr_decode_string(p, &lock->caller, &tmp, NLM_MAXSTRLEN))
+	 || !(p = nlm4_decode_fh(p, &lock->fh))
+	 || !(p = nlm4_decode_oh(p, &lock->oh)))
+		return NULL;
+
+	memset(fl, 0, sizeof(*fl));
+	fl->fl_owner = current->files;
+	fl->fl_pid   = ntohl(*p++);
+	fl->fl_flags = FL_POSIX;
+	fl->fl_type  = F_RDLCK;		/* as good as anything else */
+	p = xdr_decode_hyper(p, &start);
+	p = xdr_decode_hyper(p, &len);
+	end = start + len - 1;
+
+	fl->fl_start = size_to_off_t(start);
+	fl->fl_end = size_to_off_t(end);
+
+	if (len == 0 || fl->fl_end < 0)
+		fl->fl_end = OFFSET_MAX;
+	return p;
+}
+
+/*
+ * Encode a lock as part of an NLM call
+ */
+static u32 *
+nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
+{
+	struct file_lock	*fl = &lock->fl;
+
+	if (!(p = xdr_encode_string(p, lock->caller))
+	 || !(p = nlm4_encode_fh(p, &lock->fh))
+	 || !(p = nlm4_encode_oh(p, &lock->oh)))
+		return NULL;
+
+	*p++ = htonl(fl->fl_pid);
+	p = xdr_encode_hyper(p, fl->fl_start);
+	if (fl->fl_end == OFFSET_MAX)
+		p = xdr_encode_hyper(p, 0);
+	else
+		p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+
+	return p;
+}
+
+/*
+ * Encode result of a TEST/TEST_MSG call
+ */
+static u32 *
+nlm4_encode_testres(u32 *p, struct nlm_res *resp)
+{
+	dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return 0;
+	*p++ = resp->status;
+
+	if (resp->status == nlm_lck_denied) {
+		struct file_lock	*fl = &resp->lock.fl;
+
+		*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
+		*p++ = htonl(fl->fl_pid);
+
+		/* Encode owner handle. */
+		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
+			return 0;
+
+		p = xdr_encode_hyper(p, fl->fl_start);
+		if (fl->fl_end == OFFSET_MAX)
+			p = xdr_encode_hyper(p, 0);
+		else
+			p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+		dprintk("xdr: encode_testres (status %d pid %d type %d start %ld end %ld)\n", resp->status, fl->fl_pid, fl->fl_type, fl->fl_start,  fl->fl_end);
+	}
+
+	dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
+	return p;
+}
+
+
+/*
+ * Check buffer bounds after decoding arguments
+ */
+static int
+xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
+{
+	struct svc_buf	*buf = &rqstp->rq_argbuf;
+
+	return p - buf->base <= buf->buflen;
+}
+
+static int
+xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
+{
+	struct svc_buf	*buf = &rqstp->rq_resbuf;
+
+	buf->len = p - buf->base;
+	return (buf->len <= buf->buflen);
+}
+
+/*
+ * First, the server side XDR functions
+ */
+int
+nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	u32	exclusive;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+		return 0;
+
+	exclusive = ntohl(*p++);
+	if (!(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	if (exclusive)
+		argp->lock.fl.fl_type = F_WRLCK;
+
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_testres(p, resp)))
+		return 0;
+	return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	u32	exclusive;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+		return 0;
+	argp->block  = ntohl(*p++);
+	exclusive    = ntohl(*p++);
+	if (!(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	if (exclusive)
+		argp->lock.fl.fl_type = F_WRLCK;
+	argp->reclaim = ntohl(*p++);
+	argp->state   = ntohl(*p++);
+	argp->monitor = 1;		/* monitor client by default */
+
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	u32	exclusive;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+		return 0;
+	argp->block = ntohl(*p++);
+	exclusive = ntohl(*p++);
+	if (!(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	if (exclusive)
+		argp->lock.fl.fl_type = F_WRLCK;
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
+	 || !(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	argp->lock.fl.fl_type = F_UNLCK;
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+	int		len;
+
+	memset(lock, 0, sizeof(*lock));
+	lock->fl.fl_pid = ~(u32) 0;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
+	 || !(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN))
+	 || !(p = nlm4_decode_fh(p, &lock->fh))
+	 || !(p = nlm4_decode_oh(p, &lock->oh)))
+		return 0;
+	argp->fsm_mode = ntohl(*p++);
+	argp->fsm_access = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return 0;
+	*p++ = resp->status;
+	*p++ = xdr_zero;		/* sequence argument */
+	return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return 0;
+	*p++ = resp->status;
+	return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+	int		len;
+
+	if (!(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN)))
+		return 0;
+	argp->state = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
+{
+	if (!(p = xdr_decode_string(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
+		return 0;
+	argp->state = ntohl(*p++);
+	argp->addr = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+		return 0;
+	resp->status = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+	return xdr_ressize_check(rqstp, p);
+}
+
+/*
+ * Now, the client side XDR functions
+ */
+static int
+nlm4clt_encode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+{
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+{
+	return 0;
+}
+
+static int
+nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+		return -EIO;
+	resp->status = ntohl(*p++);
+	if (resp->status == NLM_LCK_DENIED) {
+		struct file_lock	*fl = &resp->lock.fl;
+		u32			excl;
+		s64			start, end, len;
+
+		memset(&resp->lock, 0, sizeof(resp->lock));
+		excl = ntohl(*p++);
+		fl->fl_pid = ntohl(*p++);
+		if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
+			return -EIO;
+
+		fl->fl_flags = FL_POSIX;
+		fl->fl_type  = excl? F_WRLCK : F_RDLCK;
+		p = xdr_decode_hyper(p, &start);
+		p = xdr_decode_hyper(p, &len);
+		end = start + len - 1;
+
+		fl->fl_start = size_to_off_t(start);
+		fl->fl_end = size_to_off_t(end);
+		if (len == 0 || fl->fl_end < 0)
+			fl->fl_end = OFFSET_MAX;
+	}
+	return 0;
+}
+
+
+static int
+nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	*p++ = argp->block? xdr_one : xdr_zero;
+	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	*p++ = argp->reclaim? xdr_one : xdr_zero;
+	*p++ = htonl(argp->state);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	*p++ = argp->block? xdr_one : xdr_zero;
+	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return -EIO;
+	*p++ = resp->status;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_testres(p, resp)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+		return -EIO;
+	resp->status = ntohl(*p++);
+	return 0;
+}
+
+/*
+ * Buffer requirements for NLM
+ */
+#define NLM4_void_sz		0
+#define NLM4_cookie_sz		3	/* 1 len , 2 data */
+#define NLM4_caller_sz		1+XDR_QUADLEN(NLM_MAXSTRLEN)
+#define NLM4_netobj_sz		1+XDR_QUADLEN(XDR_MAX_NETOBJ)
+/* #define NLM4_owner_sz		1+XDR_QUADLEN(NLM4_MAXOWNER) */
+#define NLM4_fhandle_sz		1+XDR_QUADLEN(NFS3_FHSIZE)
+#define NLM4_lock_sz		5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
+#define NLM4_holder_sz		6+NLM4_netobj_sz
+
+#define NLM4_testargs_sz	NLM4_cookie_sz+1+NLM4_lock_sz
+#define NLM4_lockargs_sz	NLM4_cookie_sz+4+NLM4_lock_sz
+#define NLM4_cancargs_sz	NLM4_cookie_sz+2+NLM4_lock_sz
+#define NLM4_unlockargs_sz	NLM4_cookie_sz+NLM4_lock_sz
+
+#define NLM4_testres_sz		NLM4_cookie_sz+1+NLM4_holder_sz
+#define NLM4_res_sz		NLM4_cookie_sz+1
+#define NLM4_norep_sz		0
+
+#ifndef MAX
+# define MAX(a,b)		(((a) > (b))? (a) : (b))
+#endif
+
+/*
+ * For NLM, a void procedure really returns nothing
+ */
+#define nlm4clt_decode_norep	NULL
+
+#define PROC(proc, argtype, restype)				\
+    { "nlm4_" #proc,						\
+      (kxdrproc_t) nlm4clt_encode_##argtype,			\
+      (kxdrproc_t) nlm4clt_decode_##restype,			\
+      MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2,	\
+      0								\
+    }
+
+static struct rpc_procinfo	nlm4_procedures[] = {
+    PROC(null,		void,		void),
+    PROC(test,		testargs,	testres),
+    PROC(lock,		lockargs,	res),
+    PROC(canc,		cancargs,	res),
+    PROC(unlock,	unlockargs,	res),
+    PROC(granted,	testargs,	res),
+    PROC(test_msg,	testargs,	norep),
+    PROC(lock_msg,	lockargs,	norep),
+    PROC(canc_msg,	cancargs,	norep),
+    PROC(unlock_msg,	unlockargs,	norep),
+    PROC(granted_msg,	testargs,	norep),
+    PROC(test_res,	testres,	norep),
+    PROC(lock_res,	res,		norep),
+    PROC(canc_res,	res,		norep),
+    PROC(unlock_res,	res,		norep),
+    PROC(granted_res,	res,		norep),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+#ifdef NLMCLNT_SUPPORT_SHARES
+    PROC(share,		shareargs,	shareres),
+    PROC(unshare,	shareargs,	shareres),
+    PROC(nm_lock,	lockargs,	res),
+    PROC(free_all,	notify,		void),
+#else
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+#endif
+};
+
+struct rpc_version	nlm_version4 = {
+	4, 24, nlm4_procedures,
+};
diff -u --recursive --new-file v2.3.46/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.3.46/linux/fs/minix/inode.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/minix/inode.c	Sun Feb 20 13:09:46 2000
@@ -35,9 +35,13 @@
 
 static void minix_delete_inode(struct inode *inode)
 {
+	lock_kernel();
+
 	inode->i_size = 0;
 	minix_truncate(inode);
 	minix_free_inode(inode);
+
+	unlock_kernel();
 }
 
 static void minix_commit_super(struct super_block * sb)
@@ -1243,7 +1247,9 @@
 {
 	struct buffer_head *bh;
 
+	lock_kernel();
 	bh = minix_update_inode(inode);
+	unlock_kernel();
 	brelse(bh);
 }
 
diff -u --recursive --new-file v2.3.46/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.3.46/linux/fs/ncpfs/sock.c	Mon Nov  1 13:56:27 1999
+++ linux/fs/ncpfs/sock.c	Sun Feb 20 20:19:12 2000
@@ -203,7 +203,8 @@
 				}
 				n = 0;
 				timeout = init_timeout;
-				init_timeout <<= 1;
+				if (init_timeout < max_timeout)
+					init_timeout <<= 1;
 				if (!major_timeout_seen) {
 					printk(KERN_WARNING "NCP server not responding\n");
 				}
diff -u --recursive --new-file v2.3.46/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.3.46/linux/fs/nfs/file.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/nfs/file.c	Wed Feb 16 20:23:47 2000
@@ -165,11 +165,16 @@
 static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
 {
 	long status;
+	loff_t pos = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + to;
+	struct inode *inode = (struct inode*)page->mapping->host;
 
 	kunmap(page);
 	lock_kernel();
 	status = nfs_updatepage(file, page, offset, to-offset);
 	unlock_kernel();
+	/* most likely it's already done. CHECKME */
+	if (pos > inode->i_size)
+		inode->i_size = pos;
 	return status;
 }
 
diff -u --recursive --new-file v2.3.46/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.3.46/linux/fs/nfs/inode.c	Sun Feb 13 19:29:04 2000
+++ linux/fs/nfs/inode.c	Sun Feb 20 13:09:46 2000
@@ -28,6 +28,7 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/nfs_fs.h>
 #include <linux/lockd/bind.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -102,6 +103,7 @@
 
 	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
+	lock_kernel();
 	if (S_ISDIR(inode->i_mode)) {
 		nfs_free_dircache(inode);
 	} else {
@@ -129,6 +131,8 @@
 	if (failed)
 		printk("NFS: inode %ld had %d failed requests\n",
 			inode->i_ino, failed);
+	unlock_kernel();
+
 	clear_inode(inode);
 }
 
@@ -683,14 +687,12 @@
 		if (attr->ia_size != fattr.size)
 			printk("nfs_notify_change: attr=%Ld, fattr=%d??\n",
 			       (long long) attr->ia_size, fattr.size);
-		inode->i_size  = attr->ia_size;
 		inode->i_mtime = fattr.mtime.seconds;
+		vmtruncate(inode, attr->ia_size);
 	}
 	if (attr->ia_valid & ATTR_MTIME)
 		inode->i_mtime = fattr.mtime.seconds;
 	error = nfs_refresh_inode(inode, &fattr);
-	if (!error && (attr->ia_valid & ATTR_SIZE))
-		vmtruncate(inode, attr->ia_size);
 out:
 	return error;
 }
diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/lockd.c linux/fs/nfsd/lockd.c
--- v2.3.46/linux/fs/nfsd/lockd.c	Tue Feb  1 01:35:44 2000
+++ linux/fs/nfsd/lockd.c	Thu Feb 17 17:23:30 2000
@@ -34,7 +34,16 @@
 	if (!nfserr)
 		dget(filp->f_dentry);
 	fh_put(&fh);
-	return nfserr;
+ 	/* nlm and nfsd don't share error codes.
+	 * we invent: 0 = no error
+	 *            1 = stale file handle
+	 *	      2 = other error
+	 */
+	if (nfserr == 0)
+		return 0;
+	else if (nfserr == nfserr_stale)
+		return 1;
+	else return 2;
 }
 
 static void
diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c
--- v2.3.46/linux/fs/nfsd/nfs3xdr.c	Wed Feb 16 17:03:52 2000
+++ linux/fs/nfsd/nfs3xdr.c	Thu Feb 17 17:23:30 2000
@@ -177,15 +177,15 @@
 	*p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
 	*p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
 	if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
-		p = enc64(p, (u64) NFS3_MAXPATHLEN);
+		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 	} else {
-		p = enc64(p, (u64) inode->i_size);
+		p = xdr_encode_hyper(p, (u64) inode->i_size);
 	}
-	p = enc64(p, ((u64)inode->i_blocks) << 9);
+	p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
 	*p++ = htonl((u32) MAJOR(inode->i_rdev));
 	*p++ = htonl((u32) MINOR(inode->i_rdev));
-	p = enc64(p, (u64) inode->i_dev);
-	p = enc64(p, (u64) inode->i_ino);
+	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, inode->i_atime);
 	p = encode_time3(p, inode->i_mtime);
 	p = encode_time3(p, inode->i_ctime);
@@ -207,15 +207,15 @@
 	*p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
 	*p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
 	if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
-		p = enc64(p, (u64) NFS3_MAXPATHLEN);
+		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 	} else {
-		p = enc64(p, (u64) fhp->fh_post_size);
+		p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
 	}
-	p = enc64(p, ((u64)fhp->fh_post_blocks) << 9);
+	p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
 	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
 	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
-	p = enc64(p, (u64) inode->i_dev);
-	p = enc64(p, (u64) inode->i_ino);
+	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, fhp->fh_post_atime);
 	p = encode_time3(p, fhp->fh_post_mtime);
 	p = encode_time3(p, fhp->fh_post_ctime);
@@ -250,7 +250,7 @@
 	if (dentry && dentry->d_inode && fhp->fh_post_saved) {
 		if (fhp->fh_pre_saved) {
 			*p++ = xdr_one;
-			p = enc64(p, (u64) fhp->fh_pre_size);
+			p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
 			p = encode_time3(p, fhp->fh_pre_mtime);
 			p = encode_time3(p, fhp->fh_pre_ctime);
 		} else {
@@ -669,7 +669,7 @@
 	int		buflen, slen, elen;
 
 	if (cd->offset)
-		enc64(cd->offset, (u64) offset);
+		xdr_encode_hyper(cd->offset, (u64) offset);
 
 	/* nfsd_readdir calls us with name == 0 when it wants us to
 	 * set the last offset entry. */
@@ -693,7 +693,7 @@
 		return -EINVAL;
 	}
 	*p++ = xdr_one;				   /* mark entry present */
-	p    = enc64(p, ino);			   /* file id */
+	p    = xdr_encode_hyper(p, ino);			   /* file id */
 #ifdef XDR_ENCODE_STRING_TAKES_LENGTH
 	p    = xdr_encode_string(p, name, namlen); /* name length & name */
 #else
@@ -705,7 +705,7 @@
 	p[slen - 1] = 0;		/* don't leak kernel data */
 
 	cd->offset = p;			/* remember pointer */
-	p = enc64(p, NFS_OFFSET_MAX);	/* offset of next entry */
+	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);	/* offset of next entry */
 
 	/* throw in readdirplus baggage */
 	if (plus) {
@@ -756,12 +756,12 @@
 	*p++ = xdr_zero;	/* no post_op_attr */
 
 	if (resp->status == 0) {
-		p = enc64(p, bs * s->f_blocks);	/* total bytes */
-		p = enc64(p, bs * s->f_bfree);	/* free bytes */
-		p = enc64(p, bs * s->f_bavail);	/* user available bytes */
-		p = enc64(p, s->f_files);	/* total inodes */
-		p = enc64(p, s->f_ffree);	/* free inodes */
-		p = enc64(p, s->f_ffree);	/* user available inodes */
+		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
+		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
+		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
+		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
+		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
+		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
 		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
 	}
 	return xdr_ressize_check(rqstp, p);
@@ -782,7 +782,7 @@
 		*p++ = htonl(resp->f_wtpref);
 		*p++ = htonl(resp->f_wtmult);
 		*p++ = htonl(resp->f_dtpref);
-		p = enc64(p, resp->f_maxfilesize);
+		p = xdr_encode_hyper(p, resp->f_maxfilesize);
 		*p++ = xdr_one;
 		*p++ = xdr_zero;
 		*p++ = htonl(resp->f_properties);
diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.3.46/linux/fs/nfsd/nfsfh.c	Wed Feb 16 17:03:52 2000
+++ linux/fs/nfsd/nfsfh.c	Sun Feb 20 20:41:00 2000
@@ -150,7 +150,7 @@
 	 */
 	for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {
 		result = list_entry(lp,struct dentry, d_alias);
-		if (! IS_ROOT(result) || inode->i_sb->s_root == result) {
+		if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
 			dget(result);
 			iput(inode);
 			return result;
@@ -161,6 +161,7 @@
 		iput(inode);
 		return ERR_PTR(-ENOMEM);
 	}
+	result->d_flags |= DCACHE_NFSD_DISCONNECTED;
 	d_rehash(result); /* so a dput won't loose it */
 	return result;
 }
@@ -175,6 +176,8 @@
 #ifdef NFSD_PARANOIA
 	if (!IS_ROOT(target))
 		printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name);
+	if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED))
+		printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name);
 #endif
 	name->hash = full_name_hash(name->name, name->len);
 	tdentry = d_alloc(parent, name);
@@ -189,6 +192,29 @@
 	tdentry->d_parent = tdentry;
 	d_rehash(target);
 	dput(tdentry);
+
+	/* if parent is properly connected, then we can assert that
+	 * the children are connected, but it must be a singluar (non-forking)
+	 * branch
+	 */
+	if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+		while (target) {
+			target->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
+			parent = target;
+			if (list_empty(&parent->d_subdirs))
+				target = NULL;
+			else {
+				target = list_entry(parent->d_subdirs.next, struct dentry, d_child);
+#ifdef NFSD_PARANOIA
+				/* must be only child */
+				if (target->d_child.next != &parent->d_subdirs
+				    || target->d_child.prev != &parent->d_subdirs)
+					printk("nfsd: d_splice found non-singular disconnected branch: %s/%s\n",
+					       parent->d_name.name, target->d_name.name);
+#endif
+			}
+		}
+	}
 	return 0;
 }
 
@@ -227,7 +253,10 @@
 		}
 		if (pdentry == NULL) {
 			pdentry = d_alloc_root(igrab(tdentry->d_inode));
-			if (pdentry) d_rehash(pdentry);
+			if (pdentry) {
+				pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+				d_rehash(pdentry);
+			}
 		}
 		if (pdentry == NULL)
 			pdentry = ERR_PTR(-ENOMEM);
@@ -302,13 +331,13 @@
 	struct dentry *tmp;
 	int  found =0;
 	int err;
-	/* This semaphore is needed to make sure that only one unconnected (free)
+	/* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free)
 	 * dcache path ever exists, as otherwise two partial paths might get
 	 * joined together, which would be very confusing.
 	 * If there is ever an unconnected non-root directory, then this lock
-	 * must be held.  This could sensibly be per-filesystem.
+	 * must be held.
 	 */
-	static DECLARE_MUTEX(free_path_sem);
+
 
 	nfsdstats.fh_lookup++;
 	/*
@@ -324,7 +353,7 @@
 		dprintk("find_fh_dentry: No inode found.\n");
 		goto err_out;
 	}
-	if (!IS_ROOT(result) || result->d_inode->i_sb->s_root ==result)
+	if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED))
 		return result;
 
 	/* result is now an anonymous dentry, which may be adequate as it stands, or else
@@ -339,7 +368,15 @@
 	 * location in the tree.
 	 */
 	dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,fh->fh_ino);
-	down(&free_path_sem);
+	down(&sb->s_nfsd_free_path_sem);
+
+	/* claiming the semaphore might have allow things to get fixed up */
+	if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+		up(&sb->s_nfsd_free_path_sem);
+		return result;
+	}
+
+
 	found = 0;
 	if (!S_ISDIR(result->d_inode->i_mode)) {
 		nfsdstats.fh_nocache_nondir++;
@@ -356,7 +393,7 @@
 			    || !S_ISDIR(dentry->d_inode->i_mode)) {
 				goto err_dentry;
 			}
-			if (!IS_ROOT(dentry) || dentry->d_inode->i_sb->s_root ==dentry)
+			if ((!dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
 				found = 1;
 			tmp = splice(result, dentry);
 			err = PTR_ERR(tmp);
@@ -393,10 +430,8 @@
 			dput(pdentry);
 			goto err_dentry;
 		}
-		/* I'm not sure that this is the best test for
-		 *  "is it not a floating dentry?"
-		 */
-		if (!IS_ROOT(pdentry) || parent->i_sb->s_root == pdentry)
+
+		if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
 			found = 1;
 
 		tmp = splice(dentry, pdentry);
@@ -419,21 +454,21 @@
 			dput(tmp);
 			dput(dentry);
 			dput(result);	/* this will discard the whole free path, so we can up the semaphore */
-			up(&free_path_sem);
+			up(&sb->s_nfsd_free_path_sem);
 			goto retry;
 		}
 		dput(dentry);
 		dentry = pdentry;
 	}
 	dput(dentry);
-	up(&free_path_sem);
+	up(&sb->s_nfsd_free_path_sem);
 	return result;
 
 err_dentry:
 	dput(dentry);
 err_result:
 	dput(result);
-	up(&free_path_sem);
+	up(&sb->s_nfsd_free_path_sem);
 err_out:
 	if (err == -ESTALE)
 		nfsdstats.fh_stale++;
@@ -515,6 +550,13 @@
 			error = nfserrno(-PTR_ERR(dentry));
 			goto out;
 		}
+#ifdef NFSD_PARANOIA
+		if (S_ISDIR(dentry->d_inode->i_mode) &&
+		    (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+			printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
+			       dentry->d_parent->d_name.name, dentry->d_name.name);
+		}
+#endif
 
 		fhp->fh_dentry = dentry;
 		fhp->fh_export = exp;
diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.46/linux/fs/nfsd/vfs.c	Wed Feb 16 17:03:52 2000
+++ linux/fs/nfsd/vfs.c	Thu Feb 17 17:23:30 2000
@@ -1557,7 +1557,7 @@
 	if (cd.offset) {
 #ifdef CONFIG_NFSD_V3
 		if (rqstp->rq_vers == 3)
-			(void)enc64(cd.offset, file.f_pos);
+			(void)xdr_encode_hyper(cd.offset, file.f_pos);
 		else
 #endif /* CONFIG_NFSD_V3 */
 			*cd.offset = htonl(file.f_pos);
diff -u --recursive --new-file v2.3.46/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.3.46/linux/fs/proc/inode.c	Tue Nov 23 22:42:21 1999
+++ linux/fs/proc/inode.c	Sun Feb 20 13:09:46 2000
@@ -15,6 +15,7 @@
 #include <linux/limits.h>
 #define __NO_VERSION__
 #include <linux/module.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -34,6 +35,7 @@
 void de_put(struct proc_dir_entry *de)
 {
 	if (de) {
+		lock_kernel(); /* FIXME: count should be atomic_t */
 		if (!de->count) {
 			printk("de_put: entry %s already free!\n", de->name);
 			return;
@@ -46,6 +48,7 @@
 				free_proc_entry(de);
 			}
 		}
+		unlock_kernel();
 	}
 }
 
@@ -65,6 +68,8 @@
 static void proc_delete_inode(struct inode *inode)
 {
 	struct proc_dir_entry *de = inode->u.generic_ip;
+
+	inode->i_state = I_CLEAR;
 
 	if (PROC_INODE_PROPER(inode)) {
 		proc_pid_delete_inode(inode);
diff -u --recursive --new-file v2.3.46/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.3.46/linux/fs/smbfs/inode.c	Sun Feb 13 19:29:04 2000
+++ linux/fs/smbfs/inode.c	Wed Feb 16 20:23:47 2000
@@ -483,16 +483,7 @@
 					 attr->ia_size);
 		if (error)
 			goto out;
-		/*
-		 * We don't implement an i_op->truncate operation,
-		 * so we have to update the page cache here.
-		 */
-		if (attr->ia_size < inode->i_size)
-		{
-			/* must die */
-			truncate_inode_pages(inode->i_mapping, attr->ia_size);
-			inode->i_size = attr->ia_size;
-		}
+		vmtruncate(inode, attr->ia_size);
 		refresh = 1;
 	}
 
@@ -563,8 +554,6 @@
 out:
 	if (refresh)
 		smb_refresh_inode(dentry);
-	if (!error && (attr->ia_valid & ATTR_SIZE))
-		vmtruncate(inode, attr->ia_size);
 	return error;
 }
 
diff -u --recursive --new-file v2.3.46/linux/fs/super.c linux/fs/super.c
--- v2.3.46/linux/fs/super.c	Wed Feb 16 17:03:52 2000
+++ linux/fs/super.c	Sun Feb 20 20:41:00 2000
@@ -565,6 +565,7 @@
 	s->s_flags = flags;
 	s->s_dirt = 0;
 	sema_init(&s->s_vfs_rename_sem,1);
+	sema_init(&s->s_nfsd_free_path_sem,1);
 	/* N.B. Should lock superblock now ... */
 	if (!type->read_super(s, data, silent))
 		goto out_fail;
@@ -1142,6 +1143,7 @@
 			sb->s_bdev = NULL;
 			sb->s_flags = root_mountflags;
 			sema_init(&sb->s_vfs_rename_sem,1);
+			sema_init(&s->s_nfsd_free_path_sem,1);
 			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
 			if (vfsmnt) {
 				if (nfs_root_mount(sb) >= 0) {
diff -u --recursive --new-file v2.3.46/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.3.46/linux/fs/udf/file.c	Thu Feb 10 17:11:19 2000
+++ linux/fs/udf/file.c	Wed Feb 16 20:23:47 2000
@@ -145,6 +145,9 @@
 	brelse(bh);
 	kunmap(page);
 	SetPageUptodate(page);
+	/* only one page here */
+	if (to > inode->i_size)
+		inode->i_size = to;
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h
--- v2.3.46/linux/include/asm-alpha/core_mcpcia.h	Thu Feb 10 17:11:19 2000
+++ linux/include/asm-alpha/core_mcpcia.h	Sun Feb 20 08:13:56 2000
@@ -74,6 +74,10 @@
 
 #define MCPCIA_MID(m)		((unsigned long)(m) << 33)
 
+/* Dodge has PCI0 and PCI1 at MID 4 and 5 respectively. 
+   Durango adds PCI2 and PCI3 at MID 6 and 7 respectively.  */
+#define MCPCIA_HOSE2MID(h)	((h) + 4)
+
 #define MCPCIA_MEM_MASK 0x07ffffff /* SPARSE Mem region mask is 27 bits */
 
 /*
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.3.46/linux/include/asm-alpha/hardirq.h	Thu Feb 10 17:11:19 2000
+++ linux/include/asm-alpha/hardirq.h	Thu Feb 17 09:44:11 2000
@@ -8,8 +8,11 @@
 #ifndef __SMP__
 extern int __local_irq_count;
 #define local_irq_count(cpu)  ((void)(cpu), __local_irq_count)
+extern unsigned long __irq_attempt[];
+#define irq_attempt(cpu, irq)  ((void)(cpu), __irq_attempt[irq])
 #else
 #define local_irq_count(cpu)  (cpu_data[cpu].irq_count)
+#define irq_attempt(cpu, irq) (cpu_data[cpu].irq_attempt[irq])
 #endif
 
 /*
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/hw_irq.h linux/include/asm-alpha/hw_irq.h
--- v2.3.46/linux/include/asm-alpha/hw_irq.h	Tue Dec  7 09:32:49 1999
+++ linux/include/asm-alpha/hw_irq.h	Sun Feb 20 08:13:56 2000
@@ -1,91 +1,5 @@
-#ifndef _ALPHA_HW_IRQ_H
-#define _ALPHA_HW_IRQ_H
-/*
- *	linux/arch/alpha/kernel/irq.h
- *
- *	Copyright (C) 1995 Linus Torvalds
- *	Copyright (C) 1998 Richard Henderson
- *
- * This file contains declarations and inline functions for interfacing
- * with the IRQ handling routines in irq.c.
- */
+/* This exists merely to satisfy <linux/irq.h>.  There is
+   nothing that would go here of general interest.
 
-#include <linux/config.h>
-
-#define STANDARD_INIT_IRQ_PROLOG	\
-	outb(0, DMA1_RESET_REG);	\
-	outb(0, DMA2_RESET_REG);	\
-	outb(0, DMA1_CLR_MASK_REG);	\
-	outb(0, DMA2_CLR_MASK_REG)
-
-extern unsigned long _alpha_irq_masks[2];
-#define alpha_irq_mask _alpha_irq_masks[0]
-
-extern void common_ack_irq(unsigned long irq);
-extern void isa_device_interrupt(unsigned long vector, struct pt_regs * regs);
-extern void srm_device_interrupt(unsigned long vector, struct pt_regs * regs);
-
-extern void handle_irq(int irq, int ack, struct pt_regs * regs);
-
-#define RTC_IRQ    8
-#ifdef CONFIG_RTC
-#define TIMER_IRQ  0			 /* timer is the pit */
-#else
-#define TIMER_IRQ  RTC_IRQ		 /* timer is the rtc */
-#endif
-
-/*
- * PROBE_MASK is the bitset of irqs that we consider for autoprobing.
- */
-
-/* NOTE: we only handle the first 64 IRQs in this code. */
-
-/* The normal mask includes all the IRQs except timer IRQ 0.  */
-#define _PROBE_MASK(nr_irqs)	\
-	(((nr_irqs > 63) ? ~0UL : ((1UL << (nr_irqs & 63)) - 1)) & ~1UL)
-
-/* Mask out unused timer irq 0 and RTC irq 8. */
-#define P2K_PROBE_MASK		(_PROBE_MASK(16) & ~0x101UL)
-
-/* Mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade. */
-#define ALCOR_PROBE_MASK	(_PROBE_MASK(48) & ~0xfff000000001UL)
-
-/* Leave timer IRQ 0 in the mask.  */
-#define RUFFIAN_PROBE_MASK	(_PROBE_MASK(48) | 1UL)
-
-/* Do not probe/enable beyond the PCI devices. */
-#define TSUNAMI_PROBE_MASK	_PROBE_MASK(48)
-
-#if defined(CONFIG_ALPHA_GENERIC)
-# define PROBE_MASK	alpha_mv.irq_probe_mask
-#elif defined(CONFIG_ALPHA_P2K)
-# define PROBE_MASK	P2K_PROBE_MASK
-#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
-# define PROBE_MASK	ALCOR_PROBE_MASK
-#elif defined(CONFIG_ALPHA_RUFFIAN)
-# define PROBE_MASK	RUFFIAN_PROBE_MASK
-#elif defined(CONFIG_ALPHA_DP264)
-# define PROBE_MASK	TSUNAMI_PROBE_MASK
-#else
-# define PROBE_MASK	_PROBE_MASK(NR_IRQS)
-#endif
-
-
-extern char _stext;
-static inline void alpha_do_profile (unsigned long pc)
-{
-	if (prof_buffer && current->pid) {
-		pc -= (unsigned long) &_stext;
-		pc >>= prof_shift;
-		/*
-		 * Don't ignore out-of-bounds PC values silently,
-		 * put them into the last histogram slot, so if
-		 * present, they will show up as a sharp peak.
-		 */
-		if (pc > prof_len - 1)
-			pc = prof_len - 1;
-		atomic_inc((atomic_t *)&prof_buffer[pc]);
-	}
-}
-
-#endif
+   Everything of consequence is in arch/alpha/kernel/irq_impl.h,
+   to be used only in arch/alpha/kernel/.  */
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h
--- v2.3.46/linux/include/asm-alpha/hwrpb.h	Tue Dec  7 09:32:49 1999
+++ linux/include/asm-alpha/hwrpb.h	Sun Feb 20 08:13:56 2000
@@ -16,7 +16,7 @@
 #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??)	*/
+#define PCA57_CPU		10	/* PCA57 (notyet)	*/
 
 /*
  * DEC system types for Alpha systems.  Found in HWRPB.
@@ -62,8 +62,8 @@
 #define ST_DTI_RUFFIAN		101	/* RUFFIAN systype	*/
 
 /* Alpha Processor, Inc. systems */
-#define ST_API_BIAS		200			/* Offset for API systems */
-#define ST_API_NAUTILUS		(ST_API_BIAS + 1)	/* Nautilus systype */
+#define ST_API_BIAS		200
+#define ST_API_NAUTILUS		201	/* UP1000 systype	*/
 
 struct pcb_struct {
 	unsigned long ksp;
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h
--- v2.3.46/linux/include/asm-alpha/machvec.h	Thu Feb 10 17:11:19 2000
+++ linux/include/asm-alpha/machvec.h	Sun Feb 20 08:13:56 2000
@@ -22,6 +22,7 @@
 struct pci_dev;
 struct pci_ops;
 struct pci_controler;
+struct irqaction;
 
 struct alpha_machine_vector
 {
@@ -81,7 +82,7 @@
 
 	void (*init_arch)(void);
 	void (*init_irq)(void);
-	void (*init_pit)(void);
+	void (*init_rtc)(struct irqaction *);
 	void (*init_pci)(void);
 	void (*kill_arch)(int);
 
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h
--- v2.3.46/linux/include/asm-alpha/pci.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-alpha/pci.h	Fri Feb 18 15:07:20 2000
@@ -74,9 +74,9 @@
 /* Map a single buffer of the indicate size for PCI DMA in streaming
    mode.  The 32-bit PCI bus mastering address to use is returned.
    Once the device is given the dma address, the device owns this memory
-   until either pci_unmap_single or pci_sync_single is performed.  */
+   until either pci_unmap_single or pci_dma_sync_single is performed.  */
 
-extern dma_addr_t pci_map_single(struct pci_dev *, void *, long);
+extern dma_addr_t pci_map_single(struct pci_dev *, void *, long, int);
 
 /* Unmap a single streaming mode DMA translation.  The DMA_ADDR and
    SIZE must match what was provided for in a previous pci_map_single
@@ -84,7 +84,7 @@
    the cpu to the buffer are guarenteed to see whatever the device
    wrote there.  */
 
-extern void pci_unmap_single(struct pci_dev *, dma_addr_t, long);
+extern void pci_unmap_single(struct pci_dev *, dma_addr_t, long, int);
 
 /* Map a set of buffers described by scatterlist in streaming mode for
    PCI DMA.  This is the scather-gather version of the above
@@ -100,13 +100,13 @@
    Device ownership issues as mentioned above for pci_map_single are
    the same here.  */
 
-extern int pci_map_sg(struct pci_dev *, struct scatterlist *, int);
+extern int pci_map_sg(struct pci_dev *, struct scatterlist *, int, int);
 
 /* Unmap a set of streaming mode DMA translations.  Again, cpu read
    rules concerning calls here are the same as for pci_unmap_single()
    above.  */
 
-extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int);
+extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int, int);
 
 /* Make physical memory consistant for a single streaming mode DMA
    translation after a transfer.
@@ -118,7 +118,7 @@
    again owns the buffer.  */
 
 extern inline void
-pci_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size)
+pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size, int direction)
 {
 	/* Nothing to do.  */
 }
@@ -128,9 +128,19 @@
    for a scatter-gather list, same rules and usage.  */
 
 extern inline void
-pci_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int size)
+pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int direction)
 {
 	/* Nothing to do.  */
+}
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 1;
 }
 
 #endif /* __ALPHA_PCI_H */
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/pgalloc.h linux/include/asm-alpha/pgalloc.h
--- v2.3.46/linux/include/asm-alpha/pgalloc.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-alpha/pgalloc.h	Fri Feb 18 10:01:32 2000
@@ -9,7 +9,18 @@
 #define flush_cache_range(mm, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
-#define flush_icache_range(start, end)		do { } while (0)
+/*
+ * The icache is not coherent with the dcache on alpha, thus before
+ * running self modified code like kernel modules we must always run
+ * an imb().
+ */
+#ifndef __SMP__
+#define flush_icache_range(start, end)		imb()
+#else
+#define flush_icache_range(start, end)		smp_imb()
+extern void smp_imb(void);
+#endif
+#define flush_icache_page(vma, page)		do { } while (0)
 
 /*
  * Use a few helper functions to hide the ugly broken ASN
@@ -95,6 +106,18 @@
 	flush_tlb_current(current->mm);
 }
 
+/*
+ * Flush a specified range of user mapping page tables
+ * from TLB.
+ * Although Alpha uses VPTE caches, this can be a nop, as Alpha does
+ * not have finegrained tlb flushing, so it will flush VPTE stuff
+ * during next flush_tlb_range.
+ */
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+	unsigned long start, unsigned long end)
+{
+}
+
 #ifndef __SMP__
 /*
  * Flush everything (kernel mapping may also have
@@ -143,18 +166,6 @@
 	unsigned long start, unsigned long end)
 {
 	flush_tlb_mm(mm);
-}
-
-/*
- * Flush a specified range of user mapping page tables
- * from TLB.
- * Although Alpha uses VPTE caches, this can be a nop, as Alpha does
- * not have finegrained tlb flushing, so it will flush VPTE stuff
- * during next flush_tlb_range.
- */
-static inline void flush_tlb_pgtables(struct mm_struct *mm,
-	unsigned long start, unsigned long end)
-{
 }
 
 #else /* __SMP__ */
diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.3.46/linux/include/asm-alpha/smp.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-alpha/smp.h	Thu Feb 17 09:44:11 2000
@@ -20,6 +20,7 @@
 #ifdef __SMP__
 
 #include <linux/threads.h>
+#include <asm/irq.h>
 
 struct cpuinfo_alpha {
 	unsigned long loops_per_sec;
@@ -28,6 +29,8 @@
 	unsigned long *pte_cache;
 	unsigned long pgtable_cache_sz;
 	unsigned long ipi_count;
+	unsigned long irq_attempt[NR_IRQS];
+	unsigned long smp_local_irq_count;
 	unsigned long prof_multiplier;
 	unsigned long prof_counter;
 	int irq_count, bh_count;
diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/cpu-multi32.h linux/include/asm-arm/cpu-multi32.h
--- v2.3.46/linux/include/asm-arm/cpu-multi32.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/cpu-multi32.h	Thu Feb 17 23:34:46 2000
@@ -96,6 +96,10 @@
 	 * Idle the processor
 	 */
 	int (*_do_idle)(void);
+	/*
+	 * flush I cache for a page
+	 */
+	void (*_flush_icache_page)(unsigned long address);
 } processor;
 
 extern const struct processor arm6_processor_functions;
@@ -123,6 +127,7 @@
 #define cpu_flush_icache_area(start,end)	processor._flush_icache_area(start,end)
 #define cpu_cache_wback_area(start,end)		processor._cache_wback_area(start,end)
 #define cpu_cache_purge_area(start,end)		processor._cache_purge_area(start,end)
+#define cpu_flush_icache_page(virt)		processor._flush_icache_page(virt)
 
 #define cpu_switch_mm(pgd,tsk)			cpu_set_pgd(__virt_to_phys((unsigned long)(pgd)))
 
diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/cpu-single.h linux/include/asm-arm/cpu-single.h
--- v2.3.46/linux/include/asm-arm/cpu-single.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/cpu-single.h	Thu Feb 17 23:34:46 2000
@@ -35,6 +35,7 @@
 #define cpu_flush_icache_area		cpu_fn(CPU_NAME,_flush_icache_area)
 #define cpu_cache_wback_area		cpu_fn(CPU_NAME,_cache_wback_area)
 #define cpu_cache_purge_area		cpu_fn(CPU_NAME,_cache_purge_area)
+#define cpu_flush_icache_page		cpu_fn(CPU_NAME,_flush_icache_page)
 
 #ifndef __ASSEMBLY__
 
@@ -65,6 +66,7 @@
 extern void cpu_flush_icache_area(unsigned long start, unsigned long size);
 extern void cpu_cache_wback_area(unsigned long start, unsigned long end);
 extern void cpu_cache_purge_area(unsigned long start, unsigned long end);
+extern void cpu_flush_icache_page(unsigned long virt);
 
 #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd)))
 
diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- v2.3.46/linux/include/asm-arm/pci.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-arm/pci.h	Fri Feb 18 15:07:20 2000
@@ -56,7 +56,7 @@
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
 extern inline dma_addr_t
-pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size)
+pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
 	consistent_sync(ptr, size, 3);
 	return virt_to_bus(ptr);
@@ -70,7 +70,7 @@
  * whatever the device wrote there.
  */
 extern inline void
-pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
+pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
 {
 	/* nothing to do */
 }
@@ -91,7 +91,7 @@
  * the same here.
  */
 extern inline int
-pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	int i;
 
@@ -106,7 +106,7 @@
  * pci_unmap_single() above.
  */
 extern inline void
-pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	/* nothing to do */
 }
@@ -121,7 +121,7 @@
  * device again owns the buffer.
  */
 extern inline void
-pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size)
+pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
 {
 	consistent_sync(bus_to_virt(dma_handle), size, 3);
 }
@@ -133,12 +133,22 @@
  * same rules and usage.
  */
 extern inline void
-pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems)
+pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
 	int i;
 
 	for (i = 0; i < nelems; i++, sg++)
 		consistent_sync(sg->address, sg->length, 3);
+}
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 1;
 }
 
 /* These macros should be used after a pci_map_sg call has been done
diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h
--- v2.3.46/linux/include/asm-arm/proc-armo/cache.h	Mon Nov  1 13:56:27 1999
+++ linux/include/asm-arm/proc-armo/cache.h	Thu Feb 17 23:34:46 2000
@@ -6,6 +6,7 @@
 #define flush_cache_range(mm,start,end)		do { } while (0)
 #define flush_cache_page(vma,vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
+#define flush_icache_page(vma,page)		do { } while (0)
 #define flush_icache_range(start,end)		do { } while (0)
 
 /*
diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h
--- v2.3.46/linux/include/asm-arm/proc-armv/cache.h	Tue Nov 23 22:42:21 1999
+++ linux/include/asm-arm/proc-armv/cache.h	Thu Feb 17 23:34:46 2000
@@ -1,3 +1,5 @@
+#include <asm/mman.h>
+
 /*
  * Cache flushing...
  */
@@ -41,6 +43,12 @@
 
 #define flush_icache_range(_start,_end)					\
 	cpu_flush_icache_area((_start), (_end) - (_start))
+
+#define flush_icache_page(vma,pg)					\
+	do {								\
+		if ((vma)->vm_flags & PROT_EXEC)			\
+			cpu_flush_icache_page(page_address(pg));	\
+	} while (0)
 
 /*
  * We don't have a MEMC chip...
diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/unaligned.h linux/include/asm-arm/unaligned.h
--- v2.3.46/linux/include/asm-arm/unaligned.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/unaligned.h	Thu Feb 17 23:34:46 2000
@@ -1,6 +1,8 @@
 #ifndef __ASM_ARM_UNALIGNED_H
 #define __ASM_ARM_UNALIGNED_H
 
+#include <linux/types.h>
+
 #define get_unaligned(ptr) \
 	((__typeof__(*(ptr)))__get_unaligned_size((ptr), sizeof(*(ptr))))
 
diff -u --recursive --new-file v2.3.46/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- v2.3.46/linux/include/asm-i386/pci.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-i386/pci.h	Sun Feb 20 20:48:17 2000
@@ -52,8 +52,10 @@
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
 extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-					size_t size)
+					size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	return virt_to_bus(ptr);
 }
 
@@ -65,8 +67,10 @@
  * whatever the device wrote there.
  */
 extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-				    size_t size)
+				    size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
 }
 
@@ -86,8 +90,10 @@
  * the same here.
  */
 extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-			     int nents)
+			     int nents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	return nents;
 }
 
@@ -96,8 +102,10 @@
  * pci_unmap_single() above.
  */
 extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-				int nents)
+				int nents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
 }
 
@@ -112,8 +120,10 @@
  */
 extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
-				       size_t size)
+				       size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
 }
 
@@ -125,9 +135,21 @@
  */
 extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
 				   struct scatterlist *sg,
-				   int nelems)
+				   int nelems, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
+}
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 1;
 }
 
 /* These macros should be used after a pci_map_sg call has been done
diff -u --recursive --new-file v2.3.46/linux/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h
--- v2.3.46/linux/include/asm-ia64/pci.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/pci.h	Fri Feb 18 15:07:20 2000
@@ -55,8 +55,10 @@
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
 extern inline dma_addr_t
-pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size)
+pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	return virt_to_bus(ptr);
 }
 
@@ -69,8 +71,10 @@
  * whatever the device wrote there.
  */
 extern inline void
-pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
+pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
 }
 
@@ -91,8 +95,10 @@
  * the same here.
  */
 extern inline int
-pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	return nents;
 }
 
@@ -102,8 +108,10 @@
  * pci_unmap_single() above.
  */
 extern inline void
-pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
 }
 
@@ -118,8 +126,10 @@
  * device again owns the buffer.
  */
 extern inline void
-pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size)
+pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
 }
 
@@ -131,9 +141,21 @@
  * same rules and usage.
  */
 extern inline void
-pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems)
+pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* Nothing to do */
+}
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 1;
 }
 
 /* These macros should be used after a pci_map_sg call has been done
diff -u --recursive --new-file v2.3.46/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- v2.3.46/linux/include/asm-ppc/pci.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-ppc/pci.h	Fri Feb 18 15:07:20 2000
@@ -27,36 +27,58 @@
 extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 				void *vaddr, dma_addr_t dma_handle);
 extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-					size_t size)
+					size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	return virt_to_bus(ptr);
 }
 extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-				    size_t size)
+				    size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* nothing to do */
 }
 extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-			     int nents)
+			     int nents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	return nents;
 }
 extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-				int nents)
+				int nents, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* nothing to do */
 }
 extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
-				       size_t size)
+				       size_t size, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* nothing to do */
 }
 extern inline void pci_dma_syng_sg(struct pci_dev *hwdev,
 				   struct scatterlist *sg,
-				   int nelems)
+				   int nelems, int direction)
 {
+	if (direction == PCI_DMA_NONE)
+		BUG();
 	/* nothing to do */
+}
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 1;
 }
 
 #define sg_dma_address(sg)	(virt_to_bus((sg)->address))
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h
--- v2.3.46/linux/include/asm-sparc/asm_offsets.h	Sat Feb 12 11:22:11 2000
+++ linux/include/asm-sparc/asm_offsets.h	Sun Feb 20 08:49:40 2000
@@ -79,113 +79,113 @@
 #define AOFF_task_pidhash_pprev	0x00000094
 #define ASIZ_task_pidhash_pprev	0x00000004
 #define AOFF_task_wait_chldexit	0x00000098
-#define ASIZ_task_wait_chldexit	0x00000010
-#define AOFF_task_vfork_sem	0x000000a8
+#define ASIZ_task_wait_chldexit	0x00000014
+#define AOFF_task_vfork_sem	0x000000ac
 #define ASIZ_task_vfork_sem	0x00000004
-#define AOFF_task_rt_priority	0x000000ac
+#define AOFF_task_rt_priority	0x000000b0
 #define ASIZ_task_rt_priority	0x00000004
-#define AOFF_task_it_real_value	0x000000b0
+#define AOFF_task_it_real_value	0x000000b4
 #define ASIZ_task_it_real_value	0x00000004
-#define AOFF_task_it_prof_value	0x000000b4
+#define AOFF_task_it_prof_value	0x000000b8
 #define ASIZ_task_it_prof_value	0x00000004
-#define AOFF_task_it_virt_value	0x000000b8
+#define AOFF_task_it_virt_value	0x000000bc
 #define ASIZ_task_it_virt_value	0x00000004
-#define AOFF_task_it_real_incr	0x000000bc
+#define AOFF_task_it_real_incr	0x000000c0
 #define ASIZ_task_it_real_incr	0x00000004
-#define AOFF_task_it_prof_incr	0x000000c0
+#define AOFF_task_it_prof_incr	0x000000c4
 #define ASIZ_task_it_prof_incr	0x00000004
-#define AOFF_task_it_virt_incr	0x000000c4
+#define AOFF_task_it_virt_incr	0x000000c8
 #define ASIZ_task_it_virt_incr	0x00000004
-#define AOFF_task_real_timer	0x000000c8
+#define AOFF_task_real_timer	0x000000cc
 #define ASIZ_task_real_timer	0x00000018
-#define AOFF_task_times	0x000000e0
+#define AOFF_task_times	0x000000e4
 #define ASIZ_task_times	0x00000010
-#define AOFF_task_start_time	0x000000f0
+#define AOFF_task_start_time	0x000000f4
 #define ASIZ_task_start_time	0x00000004
-#define AOFF_task_per_cpu_utime	0x000000f4
+#define AOFF_task_per_cpu_utime	0x000000f8
 #define ASIZ_task_per_cpu_utime	0x00000004
-#define AOFF_task_min_flt	0x000000fc
+#define AOFF_task_min_flt	0x00000100
 #define ASIZ_task_min_flt	0x00000004
-#define AOFF_task_maj_flt	0x00000100
+#define AOFF_task_maj_flt	0x00000104
 #define ASIZ_task_maj_flt	0x00000004
-#define AOFF_task_nswap	0x00000104
+#define AOFF_task_nswap	0x00000108
 #define ASIZ_task_nswap	0x00000004
-#define AOFF_task_cmin_flt	0x00000108
+#define AOFF_task_cmin_flt	0x0000010c
 #define ASIZ_task_cmin_flt	0x00000004
-#define AOFF_task_cmaj_flt	0x0000010c
+#define AOFF_task_cmaj_flt	0x00000110
 #define ASIZ_task_cmaj_flt	0x00000004
-#define AOFF_task_cnswap	0x00000110
+#define AOFF_task_cnswap	0x00000114
 #define ASIZ_task_cnswap	0x00000004
-#define AOFF_task_uid	0x00000118
+#define AOFF_task_uid	0x0000011c
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x0000011c
+#define AOFF_task_euid	0x00000120
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x00000120
+#define AOFF_task_suid	0x00000124
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x00000124
+#define AOFF_task_fsuid	0x00000128
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x00000128
+#define AOFF_task_gid	0x0000012c
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x0000012c
+#define AOFF_task_egid	0x00000130
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x00000130
+#define AOFF_task_sgid	0x00000134
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x00000134
+#define AOFF_task_fsgid	0x00000138
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x00000138
+#define AOFF_task_ngroups	0x0000013c
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x0000013c
+#define AOFF_task_groups	0x00000140
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x000001bc
+#define AOFF_task_cap_effective	0x000001c0
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x000001c0
+#define AOFF_task_cap_inheritable	0x000001c4
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x000001c4
+#define AOFF_task_cap_permitted	0x000001c8
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x000001c8
+#define AOFF_task_user	0x000001cc
 #define ASIZ_task_user	0x00000004
-#define AOFF_task_rlim	0x000001cc
+#define AOFF_task_rlim	0x000001d0
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x0000021c
+#define AOFF_task_used_math	0x00000220
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000021e
+#define AOFF_task_comm	0x00000222
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x00000230
+#define AOFF_task_link_count	0x00000234
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000234
+#define AOFF_task_tty	0x00000238
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x00000238
+#define AOFF_task_semundo	0x0000023c
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x0000023c
+#define AOFF_task_semsleeping	0x00000240
 #define ASIZ_task_semsleeping	0x00000004
-#define AOFF_task_thread	0x00000240
+#define AOFF_task_thread	0x00000248
 #define ASIZ_task_thread	0x00000380
-#define AOFF_task_fs	0x000005c0
+#define AOFF_task_fs	0x000005c8
 #define ASIZ_task_fs	0x00000004
-#define AOFF_task_files	0x000005c4
+#define AOFF_task_files	0x000005cc
 #define ASIZ_task_files	0x00000004
-#define AOFF_task_sigmask_lock	0x000005c8
-#define ASIZ_task_sigmask_lock	0x00000000
-#define AOFF_task_sig	0x000005c8
+#define AOFF_task_sigmask_lock	0x000005d0
+#define ASIZ_task_sigmask_lock	0x00000004
+#define AOFF_task_sig	0x000005d4
 #define ASIZ_task_sig	0x00000004
-#define AOFF_task_signal	0x000005cc
+#define AOFF_task_signal	0x000005d8
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x000005d4
+#define AOFF_task_blocked	0x000005e0
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x000005dc
+#define AOFF_task_sigqueue	0x000005e8
 #define ASIZ_task_sigqueue	0x00000004
-#define AOFF_task_sigqueue_tail	0x000005e0
+#define AOFF_task_sigqueue_tail	0x000005ec
 #define ASIZ_task_sigqueue_tail	0x00000004
-#define AOFF_task_sas_ss_sp	0x000005e4
+#define AOFF_task_sas_ss_sp	0x000005f0
 #define ASIZ_task_sas_ss_sp	0x00000004
-#define AOFF_task_sas_ss_size	0x000005e8
+#define AOFF_task_sas_ss_size	0x000005f4
 #define ASIZ_task_sas_ss_size	0x00000004
-#define AOFF_task_parent_exec_id	0x000005ec
+#define AOFF_task_parent_exec_id	0x000005f8
 #define ASIZ_task_parent_exec_id	0x00000004
-#define AOFF_task_self_exec_id	0x000005f0
+#define AOFF_task_self_exec_id	0x000005fc
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_exit_sem	0x000005f4
-#define ASIZ_task_exit_sem	0x0000001c
+#define AOFF_task_exit_sem	0x00000600
+#define ASIZ_task_exit_sem	0x00000020
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
 #define AOFF_mm_mmap_avl	0x00000004
@@ -201,48 +201,48 @@
 #define AOFF_mm_map_count	0x00000018
 #define ASIZ_mm_map_count	0x00000004
 #define AOFF_mm_mmap_sem	0x0000001c
-#define ASIZ_mm_mmap_sem	0x0000001c
-#define AOFF_mm_page_table_lock	0x00000038
-#define ASIZ_mm_page_table_lock	0x00000000
-#define AOFF_mm_context	0x00000038
+#define ASIZ_mm_mmap_sem	0x00000020
+#define AOFF_mm_page_table_lock	0x0000003c
+#define ASIZ_mm_page_table_lock	0x00000004
+#define AOFF_mm_context	0x00000040
 #define ASIZ_mm_context	0x00000004
-#define AOFF_mm_start_code	0x0000003c
+#define AOFF_mm_start_code	0x00000044
 #define ASIZ_mm_start_code	0x00000004
-#define AOFF_mm_end_code	0x00000040
+#define AOFF_mm_end_code	0x00000048
 #define ASIZ_mm_end_code	0x00000004
-#define AOFF_mm_start_data	0x00000044
+#define AOFF_mm_start_data	0x0000004c
 #define ASIZ_mm_start_data	0x00000004
-#define AOFF_mm_end_data	0x00000048
+#define AOFF_mm_end_data	0x00000050
 #define ASIZ_mm_end_data	0x00000004
-#define AOFF_mm_start_brk	0x0000004c
+#define AOFF_mm_start_brk	0x00000054
 #define ASIZ_mm_start_brk	0x00000004
-#define AOFF_mm_brk	0x00000050
+#define AOFF_mm_brk	0x00000058
 #define ASIZ_mm_brk	0x00000004
-#define AOFF_mm_start_stack	0x00000054
+#define AOFF_mm_start_stack	0x0000005c
 #define ASIZ_mm_start_stack	0x00000004
-#define AOFF_mm_arg_start	0x00000058
+#define AOFF_mm_arg_start	0x00000060
 #define ASIZ_mm_arg_start	0x00000004
-#define AOFF_mm_arg_end	0x0000005c
+#define AOFF_mm_arg_end	0x00000064
 #define ASIZ_mm_arg_end	0x00000004
-#define AOFF_mm_env_start	0x00000060
+#define AOFF_mm_env_start	0x00000068
 #define ASIZ_mm_env_start	0x00000004
-#define AOFF_mm_env_end	0x00000064
+#define AOFF_mm_env_end	0x0000006c
 #define ASIZ_mm_env_end	0x00000004
-#define AOFF_mm_rss	0x00000068
+#define AOFF_mm_rss	0x00000070
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x0000006c
+#define AOFF_mm_total_vm	0x00000074
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000070
+#define AOFF_mm_locked_vm	0x00000078
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x00000074
+#define AOFF_mm_def_flags	0x0000007c
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_cpu_vm_mask	0x00000078
+#define AOFF_mm_cpu_vm_mask	0x00000080
 #define ASIZ_mm_cpu_vm_mask	0x00000004
-#define AOFF_mm_swap_cnt	0x0000007c
+#define AOFF_mm_swap_cnt	0x00000084
 #define ASIZ_mm_swap_cnt	0x00000004
-#define AOFF_mm_swap_address	0x00000080
+#define AOFF_mm_swap_address	0x00000088
 #define ASIZ_mm_swap_address	0x00000004
-#define AOFF_mm_segments	0x00000084
+#define AOFF_mm_segments	0x0000008c
 #define ASIZ_mm_segments	0x00000004
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v2.3.46/linux/include/asm-sparc/page.h	Wed Feb 16 17:03:52 2000
+++ linux/include/asm-sparc/page.h	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.47 2000/01/29 00:41:49 anton Exp $
+/* $Id: page.h,v 1.48 2000/02/16 07:34:51 davem Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h
--- v2.3.46/linux/include/asm-sparc/pci.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc/pci.h	Fri Feb 18 15:07:20 2000
@@ -40,7 +40,7 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size);
+extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
 
 /* Unmap a single streaming mode DMA translation.  The dma_addr and size
  * must match what was provided for in a previous pci_map_single call.  All
@@ -49,7 +49,7 @@
  * After this call, reads by the cpu to the buffer are guarenteed to see
  * whatever the device wrote there.
  */
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size);
+extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
 
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
@@ -66,13 +66,13 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents);
+extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction);
 
 /* Unmap a set of streaming mode DMA translations.
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents);
+extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction);
 
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
@@ -83,7 +83,7 @@
  * next point you give the PCI dma address back to the card, the
  * device again owns the buffer.
  */
-extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size);
+extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
@@ -91,7 +91,17 @@
  * The same as pci_dma_sync_single but for a scatter-gather list,
  * same rules and usage.
  */
-extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems);
+extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 1;
+}
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.3.46/linux/include/asm-sparc/pgtable.h	Wed Feb 16 17:03:52 2000
+++ linux/include/asm-sparc/pgtable.h	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.88 2000/02/06 22:56:09 zaitcev Exp $ */
+/* $Id: pgtable.h,v 1.91 2000/02/16 08:44:52 anton Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -327,15 +327,16 @@
 		pgprot_val(newprot));
 }
 
-BTFIXUPDEF_CALL(pgd_t *, pgd_offset, struct mm_struct *, unsigned long)
-BTFIXUPDEF_CALL(pmd_t *, pmd_offset, pgd_t *, unsigned long)
-BTFIXUPDEF_CALL(pte_t *, pte_offset, pmd_t *, unsigned long)
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-/* to find an entry in a page-table-directory */
-#define pgd_offset(mm,addr) BTFIXUP_CALL(pgd_offset)(mm,addr)
+BTFIXUPDEF_CALL(pmd_t *, pmd_offset, pgd_t *, unsigned long)
+BTFIXUPDEF_CALL(pte_t *, pte_offset, pmd_t *, unsigned long)
 
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(dir,addr) BTFIXUP_CALL(pmd_offset)(dir,addr)
@@ -345,6 +346,8 @@
 
 /* The permissions for pgprot_val to make a page mapped on the obio space */
 extern unsigned int pg_iobits;
+
+#define flush_icache_page(vma, pg)      do { } while(0)
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h
--- v2.3.46/linux/include/asm-sparc/sbus.h	Tue Feb  1 01:35:44 2000
+++ linux/include/asm-sparc/sbus.h	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.21 2000/01/28 13:43:11 jj Exp $
+/* $Id: sbus.h,v 1.22 2000/02/18 13:50:50 davem Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -97,22 +97,27 @@
 	for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
 
 /* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev)	(1)
-#define sbus_can_burst64(sdev)		(1)
+#define sbus_can_dma_64bit(sdev)	(0) /* actually, sparc_cpu_model==sun4d */
+#define sbus_can_burst64(sdev)		(0) /* actually, sparc_cpu_model==sun4d */
 extern void sbus_set_sbus64(struct sbus_dev *, int);
 
 /* These yield IOMMU mappings in consistent mode. */
 extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
 extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32);
 
+#define SBUS_DMA_BIDIRECTIONAL	0
+#define SBUS_DMA_TODEVICE	1
+#define SBUS_DMA_FROMDEVICE	2
+#define	SBUS_DMA_NONE		3
+
 /* All the rest use streaming mode mappings. */
-extern u32 sbus_map_single(struct sbus_dev *, void *, long);
-extern void sbus_unmap_single(struct sbus_dev *, u32, long);
-extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int);
-extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int);
+extern u32 sbus_map_single(struct sbus_dev *, void *, long, int);
+extern void sbus_unmap_single(struct sbus_dev *, u32, long, int);
+extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
+extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 /* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single(struct sbus_dev *, u32, long);
-extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int);
+extern void sbus_dma_sync_single(struct sbus_dev *, u32, long, int);
+extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 #endif /* !(_SPARC_SBUS_H) */
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.3.46/linux/include/asm-sparc64/asm_offsets.h	Sat Feb 12 11:22:11 2000
+++ linux/include/asm-sparc64/asm_offsets.h	Sun Feb 20 08:49:41 2000
@@ -85,84 +85,84 @@
 #define AOFF_task_pidhash_pprev	0x000000f8
 #define ASIZ_task_pidhash_pprev	0x00000008
 #define AOFF_task_wait_chldexit	0x00000100
-#define ASIZ_task_wait_chldexit	0x00000020
-#define AOFF_task_vfork_sem	0x00000120
+#define ASIZ_task_wait_chldexit	0x00000028
+#define AOFF_task_vfork_sem	0x00000128
 #define ASIZ_task_vfork_sem	0x00000008
-#define AOFF_task_rt_priority	0x00000128
+#define AOFF_task_rt_priority	0x00000130
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000130
+#define AOFF_task_it_real_value	0x00000138
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000138
+#define AOFF_task_it_prof_value	0x00000140
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000140
+#define AOFF_task_it_virt_value	0x00000148
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000148
+#define AOFF_task_it_real_incr	0x00000150
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000150
+#define AOFF_task_it_prof_incr	0x00000158
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000158
+#define AOFF_task_it_virt_incr	0x00000160
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000160
+#define AOFF_task_real_timer	0x00000168
 #define ASIZ_task_real_timer	0x00000030
-#define AOFF_task_times	0x00000190
+#define AOFF_task_times	0x00000198
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x000001b0
+#define AOFF_task_start_time	0x000001b8
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x000001b8
+#define AOFF_task_per_cpu_utime	0x000001c0
 #define ASIZ_task_per_cpu_utime	0x00000008
-#define AOFF_task_min_flt	0x000001c8
+#define AOFF_task_min_flt	0x000001d0
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x000001d0
+#define AOFF_task_maj_flt	0x000001d8
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000001d8
+#define AOFF_task_nswap	0x000001e0
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000001e0
+#define AOFF_task_cmin_flt	0x000001e8
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000001e8
+#define AOFF_task_cmaj_flt	0x000001f0
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000001f0
+#define AOFF_task_cnswap	0x000001f8
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_uid	0x000001fc
+#define AOFF_task_uid	0x00000204
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x00000200
+#define AOFF_task_euid	0x00000208
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x00000204
+#define AOFF_task_suid	0x0000020c
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x00000208
+#define AOFF_task_fsuid	0x00000210
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x0000020c
+#define AOFF_task_gid	0x00000214
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x00000210
+#define AOFF_task_egid	0x00000218
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x00000214
+#define AOFF_task_sgid	0x0000021c
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x00000218
+#define AOFF_task_fsgid	0x00000220
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x0000021c
+#define AOFF_task_ngroups	0x00000224
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000220
+#define AOFF_task_groups	0x00000228
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x000002a0
+#define AOFF_task_cap_effective	0x000002a8
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x000002a4
+#define AOFF_task_cap_inheritable	0x000002ac
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x000002a8
+#define AOFF_task_cap_permitted	0x000002b0
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x000002b0
+#define AOFF_task_user	0x000002b8
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x000002b8
+#define AOFF_task_rlim	0x000002c0
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000358
+#define AOFF_task_used_math	0x00000360
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000035a
+#define AOFF_task_comm	0x00000362
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000036c
+#define AOFF_task_link_count	0x00000374
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000370
+#define AOFF_task_tty	0x00000378
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000378
+#define AOFF_task_semundo	0x00000380
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000380
+#define AOFF_task_semsleeping	0x00000388
 #define ASIZ_task_semsleeping	0x00000008
 #define AOFF_task_thread	0x00000390
 #define ASIZ_task_thread	0x00000450
@@ -171,28 +171,28 @@
 #define AOFF_task_files	0x000007e8
 #define ASIZ_task_files	0x00000008
 #define AOFF_task_sigmask_lock	0x000007f0
-#define ASIZ_task_sigmask_lock	0x00000000
-#define AOFF_task_sig	0x000007f0
+#define ASIZ_task_sigmask_lock	0x00000004
+#define AOFF_task_sig	0x000007f8
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x000007f8
+#define AOFF_task_signal	0x00000800
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000800
+#define AOFF_task_blocked	0x00000808
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000808
+#define AOFF_task_sigqueue	0x00000810
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000810
+#define AOFF_task_sigqueue_tail	0x00000818
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000818
+#define AOFF_task_sas_ss_sp	0x00000820
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000820
+#define AOFF_task_sas_ss_size	0x00000828
 #define ASIZ_task_sas_ss_size	0x00000008
-#define AOFF_task_parent_exec_id	0x00000828
+#define AOFF_task_parent_exec_id	0x00000830
 #define ASIZ_task_parent_exec_id	0x00000004
-#define AOFF_task_self_exec_id	0x0000082c
+#define AOFF_task_self_exec_id	0x00000834
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_exit_sem	0x00000830
-#define ASIZ_task_exit_sem	0x00000030
-#define ASIZ_task	0x00000860
+#define AOFF_task_exit_sem	0x00000838
+#define ASIZ_task_exit_sem	0x00000038
+#define ASIZ_task	0x00000870
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -208,50 +208,50 @@
 #define AOFF_mm_map_count	0x00000028
 #define ASIZ_mm_map_count	0x00000004
 #define AOFF_mm_mmap_sem	0x00000030
-#define ASIZ_mm_mmap_sem	0x00000030
-#define AOFF_mm_page_table_lock	0x00000060
-#define ASIZ_mm_page_table_lock	0x00000000
-#define AOFF_mm_context	0x00000060
+#define ASIZ_mm_mmap_sem	0x00000038
+#define AOFF_mm_page_table_lock	0x00000068
+#define ASIZ_mm_page_table_lock	0x00000004
+#define AOFF_mm_context	0x00000070
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000068
+#define AOFF_mm_start_code	0x00000078
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000070
+#define AOFF_mm_end_code	0x00000080
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000078
+#define AOFF_mm_start_data	0x00000088
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000080
+#define AOFF_mm_end_data	0x00000090
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x00000088
+#define AOFF_mm_start_brk	0x00000098
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x00000090
+#define AOFF_mm_brk	0x000000a0
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x00000098
+#define AOFF_mm_start_stack	0x000000a8
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_arg_start	0x000000a0
+#define AOFF_mm_arg_start	0x000000b0
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x000000a8
+#define AOFF_mm_arg_end	0x000000b8
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x000000b0
+#define AOFF_mm_env_start	0x000000c0
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x000000b8
+#define AOFF_mm_env_end	0x000000c8
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000c0
+#define AOFF_mm_rss	0x000000d0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000c8
+#define AOFF_mm_total_vm	0x000000d8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000d0
+#define AOFF_mm_locked_vm	0x000000e0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000d8
+#define AOFF_mm_def_flags	0x000000e8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000e0
+#define AOFF_mm_cpu_vm_mask	0x000000f0
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000e8
+#define AOFF_mm_swap_cnt	0x000000f8
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x000000f0
+#define AOFF_mm_swap_address	0x00000100
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x000000f8
+#define AOFF_mm_segments	0x00000108
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000100
+#define ASIZ_mm	0x00000110
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.3.46/linux/include/asm-sparc64/floppy.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-sparc64/floppy.h	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.26 2000/02/12 23:32:35 davem Exp $
+/* $Id: floppy.h,v 1.28 2000/02/18 13:50:54 davem Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -273,7 +273,7 @@
 static struct pci_dev *sun_pci_ebus_dev;
 static int sun_pci_broken_drive = -1;
 static unsigned int sun_pci_dma_addr = -1U;
-static int sun_pci_dma_len;
+static int sun_pci_dma_len, sun_pci_dma_direction;
 
 extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
@@ -369,7 +369,8 @@
 	if (sun_pci_dma_addr != -1U)
 		pci_unmap_single(sun_pci_ebus_dev,
 				 sun_pci_dma_addr,
-				 sun_pci_dma_len);
+				 sun_pci_dma_len,
+				 sun_pci_dma_direction);
 	sun_pci_dma_addr = -1U;
 }
 
@@ -388,10 +389,13 @@
 	 * For EBus WRITE means to system memory, which is
 	 * READ for us.
 	 */
-	if (mode == DMA_MODE_WRITE)
+	if (mode == DMA_MODE_WRITE) {
 		dcsr &= ~(EBUS_DCSR_WRITE);
-	else
+		sun_pci_dma_direction = PCI_DMA_TODEVICE;
+	} else {
 		dcsr |= EBUS_DCSR_WRITE;
+		sun_pci_dma_direction = PCI_DMA_FROMDEVICE;
+	}
 	writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 }
 
@@ -407,7 +411,8 @@
 
 	addr = sun_pci_dma_addr = pci_map_single(sun_pci_ebus_dev,
 						 buffer,
-						 sun_pci_dma_len);
+						 sun_pci_dma_len,
+						 sun_pci_dma_direction);
 	writel(addr, &sun_pci_fd_ebus_dma->dacr);
 }
 
@@ -560,12 +565,9 @@
 
 #endif /* CONFIG_PCI */
 
-static struct linux_prom_registers fd_regs[2];
-
 static unsigned long __init sun_floppy_init(void)
 {
 	char state[128];
-	int fd_node, num_regs;
 	struct sbus_bus *bus;
 	struct sbus_dev *sdev = NULL;
 	static int initialized = 0;
@@ -714,21 +716,19 @@
 		return 0;
 #endif
 	}
-	fd_node = sdev->prom_node;
-	prom_getproperty(fd_node, "status", state, sizeof(state));
+	prom_getproperty(sdev->prom_node, "status", state, sizeof(state));
 	if(!strncmp(state, "disabled", 8))
 		return 0;
-	num_regs = prom_getproperty(fd_node, "reg", (char *) fd_regs,
-				    sizeof(fd_regs));
-	num_regs = (num_regs / sizeof(fd_regs[0]));
 
 	/*
-	 * We cannot do sparc_alloc_io here: it does request_region,
+	 * We cannot do sbus_ioremap here: it does request_region,
 	 * which the generic floppy driver tries to do once again.
+	 * But we must use the sdev resource values as they have
+	 * had parent ranges applied.
 	 */
 	sun_fdc = (struct sun_flpy_controller *)
-		((unsigned long)fd_regs[0].phys_addr + 
-		 (((unsigned long)fd_regs[0].which_io) << 32UL));
+		(sdev->resource[0].start +
+		 ((sdev->resource[0].flags & 0x1ffUL) << 32UL));
 
 	/* Last minute sanity check... */
 	if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- v2.3.46/linux/include/asm-sparc64/io.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc64/io.h	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.31 2000/02/08 05:11:38 jj Exp $ */
+/* $Id: io.h,v 1.32 2000/02/15 10:04:54 jj Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
@@ -82,6 +82,10 @@
 
 #define inb_p inb
 #define outb_p outb
+#define inw_p inw
+#define outw_p outw
+#define inl_p inl
+#define outl_p outl
 
 extern void outsb(unsigned long addr, const void *src, unsigned long count);
 extern void outsw(unsigned long addr, const void *src, unsigned long count);
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.3.46/linux/include/asm-sparc64/page.h	Wed Feb 16 17:03:52 2000
+++ linux/include/asm-sparc64/page.h	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.29 1999/12/09 10:32:43 davem Exp $ */
+/* $Id: page.h,v 1.30 2000/02/16 07:34:54 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h
--- v2.3.46/linux/include/asm-sparc64/pbm.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc64/pbm.h	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: pbm.h,v 1.19 1999/12/17 12:32:13 jj Exp $
+/* $Id: pbm.h,v 1.20 2000/02/18 13:50:55 davem Exp $
  * pbm.h: UltraSparc PCI controller software state.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -69,6 +69,18 @@
 	 * these counters.  You have been duly warned. -DaveM
 	 */
 	u16		lowest_free[PBM_NCLUSTERS];
+
+	/* Here a PCI controller driver describes the areas of
+	 * PCI memory space where DMA to/from physical memory
+	 * are addressed.  Drivers interrogate the PCI layer
+	 * if their device has addressing limitations.  They
+	 * do so via pci_dma_supported, and pass in a mask of
+	 * DMA address bits their device can actually drive.
+	 *
+	 * The test for being usable is:
+	 * 	(device_mask & dma_addr_mask) == dma_addr_mask
+	 */
+	u32 dma_addr_mask;
 };
 
 /* This describes a PCI bus module's streaming buffer. */
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/pci.h linux/include/asm-sparc64/pci.h
--- v2.3.46/linux/include/asm-sparc64/pci.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/pci.h	Fri Feb 18 15:07:20 2000
@@ -40,7 +40,7 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size);
+extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
 
 /* Unmap a single streaming mode DMA translation.  The dma_addr and size
  * must match what was provided for in a previous pci_map_single call.  All
@@ -49,7 +49,7 @@
  * After this call, reads by the cpu to the buffer are guarenteed to see
  * whatever the device wrote there.
  */
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size);
+extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
 
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
@@ -66,13 +66,13 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents);
+extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction);
 
 /* Unmap a set of streaming mode DMA translations.
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents);
+extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction);
 
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
@@ -83,7 +83,7 @@
  * next point you give the PCI dma address back to the card, the
  * device again owns the buffer.
  */
-extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size);
+extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
@@ -91,7 +91,14 @@
  * The same as pci_dma_sync_single but for a scatter-gather list,
  * same rules and usage.
  */
-extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems);
+extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.46/linux/include/asm-sparc64/pgtable.h	Wed Feb 16 17:03:52 2000
+++ linux/include/asm-sparc64/pgtable.h	Thu Feb 17 09:26:31 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.119 2000/02/14 02:53:44 davem Exp $
+/* $Id: pgtable.h,v 1.120 2000/02/16 07:34:54 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/sbus.h linux/include/asm-sparc64/sbus.h
--- v2.3.46/linux/include/asm-sparc64/sbus.h	Tue Feb  1 01:35:44 2000
+++ linux/include/asm-sparc64/sbus.h	Fri Feb 18 15:07:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.13 2000/01/28 13:43:14 jj Exp $
+/* $Id: sbus.h,v 1.14 2000/02/18 13:50:55 davem Exp $
  * sbus.h: Defines for the Sun SBus.
  *
  * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
@@ -98,14 +98,19 @@
 extern void *sbus_alloc_consistent(struct sbus_dev *, size_t, dma_addr_t *dma_addrp);
 extern void sbus_free_consistent(struct sbus_dev *, size_t, void *, dma_addr_t);
 
+#define SBUS_DMA_BIDIRECTIONAL	0
+#define SBUS_DMA_TODEVICE	1
+#define SBUS_DMA_FROMDEVICE	2
+#define	SBUS_DMA_NONE		3
+
 /* All the rest use streaming mode mappings. */
-extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t);
-extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t);
-extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int);
-extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int);
+extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
+extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
+extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
+extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 /* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t);
-extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int);
+extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int);
+extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 #endif /* !(_SPARC64_SBUS_H) */
diff -u --recursive --new-file v2.3.46/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h
--- v2.3.46/linux/include/linux/apm_bios.h	Mon Dec 20 18:48:22 1999
+++ linux/include/linux/apm_bios.h	Sun Feb 20 20:37:09 2000
@@ -3,7 +3,7 @@
 
 /*
  * Include file for the interface to an APM BIOS
- * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
+ * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -89,32 +89,6 @@
 #define	APM_FUNC_TIMER_DISABLE	0
 #define	APM_FUNC_TIMER_ENABLE	1
 #define	APM_FUNC_TIMER_GET	2
-
-/*
- * Maximum number of events stored
- */
-#define APM_MAX_EVENTS		20
-
-/*
- * The per-file APM data
- */
-struct apm_bios_struct {
-	int		magic;
-	struct apm_bios_struct *	next;
-	int		suser;
-	int		suspends_pending;
-	int		standbys_pending;
-	int		suspends_read;
-	int		standbys_read;
-	int		event_head;
-	int		event_tail;
-	apm_event_t	events[APM_MAX_EVENTS];
-};
-
-/*
- * The magic number in apm_bios_struct
- */
-#define APM_BIOS_MAGIC		0x4101
 
 /*
  * in init/main.c
diff -u --recursive --new-file v2.3.46/linux/include/linux/auto_fs.h linux/include/linux/auto_fs.h
--- v2.3.46/linux/include/linux/auto_fs.h	Thu Feb 10 17:11:21 2000
+++ linux/include/linux/auto_fs.h	Sun Feb 20 20:48:22 2000
@@ -81,11 +81,4 @@
 #define AUTOFS_IOC_SETTIMEOUT _IOWR(0x93,0x64,unsigned long)
 #define AUTOFS_IOC_EXPIRE     _IOR(0x93,0x65,struct autofs_packet_expire)
 
-#ifdef __KERNEL__
-
-/* Init function */
-int init_autofs_fs(void);
-
-#endif /* __KERNEL__ */
-
 #endif /* _LINUX_AUTO_FS_H */
diff -u --recursive --new-file v2.3.46/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.3.46/linux/include/linux/blkdev.h	Wed Feb 16 17:03:52 2000
+++ linux/include/linux/blkdev.h	Sun Feb 20 20:48:59 2000
@@ -129,7 +129,6 @@
 extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size);
 extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size);
 extern void generic_unplug_device(void * data);
-extern void generic_plug_device (request_queue_t *q, kdev_t dev);
 extern void generic_make_request(int rw, struct buffer_head * bh);
 extern request_queue_t * blk_get_queue(kdev_t dev);
 
diff -u --recursive --new-file v2.3.46/linux/include/linux/byteorder/big_endian.h linux/include/linux/byteorder/big_endian.h
--- v2.3.46/linux/include/linux/byteorder/big_endian.h	Fri Dec  5 05:40:24 1997
+++ linux/include/linux/byteorder/big_endian.h	Thu Feb 17 09:20:13 2000
@@ -14,6 +14,18 @@
 #define __constant_ntohl(x) ((__u32)(x))
 #define __constant_htons(x) ((__u16)(x))
 #define __constant_ntohs(x) ((__u16)(x))
+#define __constant_cpu_to_le64(x) ___swab64((x))
+#define __constant_le64_to_cpu(x) ___swab64((x))
+#define __constant_cpu_to_le32(x) ___swab32((x))
+#define __constant_le32_to_cpu(x) ___swab32((x))
+#define __constant_cpu_to_le16(x) ___swab16((x))
+#define __constant_le16_to_cpu(x) ___swab16((x))
+#define __constant_cpu_to_be64(x) ((__u64)(x))
+#define __constant_be64_to_cpu(x) ((__u64)(x))
+#define __constant_cpu_to_be32(x) ((__u32)(x))
+#define __constant_be32_to_cpu(x) ((__u32)(x))
+#define __constant_cpu_to_be16(x) ((__u16)(x))
+#define __constant_be16_to_cpu(x) ((__u16)(x))
 #define __cpu_to_le64(x) __swab64((x))
 #define __le64_to_cpu(x) __swab64((x))
 #define __cpu_to_le32(x) __swab32((x))
diff -u --recursive --new-file v2.3.46/linux/include/linux/byteorder/little_endian.h linux/include/linux/byteorder/little_endian.h
--- v2.3.46/linux/include/linux/byteorder/little_endian.h	Tue Sep  1 11:49:36 1998
+++ linux/include/linux/byteorder/little_endian.h	Thu Feb 17 09:20:13 2000
@@ -14,6 +14,18 @@
 #define __constant_ntohl(x) ___swab32((x))
 #define __constant_htons(x) ___swab16((x))
 #define __constant_ntohs(x) ___swab16((x))
+#define __constant_cpu_to_le64(x) ((__u64)(x))
+#define __constant_le64_to_cpu(x) ((__u64)(x))
+#define __constant_cpu_to_le32(x) ((__u32)(x))
+#define __constant_le32_to_cpu(x) ((__u32)(x))
+#define __constant_cpu_to_le16(x) ((__u16)(x))
+#define __constant_le16_to_cpu(x) ((__u16)(x))
+#define __constant_cpu_to_be64(x) ___swab64((x))
+#define __constant_be64_to_cpu(x) ___swab64((x))
+#define __constant_cpu_to_be32(x) ___swab32((x))
+#define __constant_be32_to_cpu(x) ___swab32((x))
+#define __constant_cpu_to_be16(x) ___swab16((x))
+#define __constant_be16_to_cpu(x) ___swab16((x))
 #define __cpu_to_le64(x) ((__u64)(x))
 #define __le64_to_cpu(x) ((__u64)(x))
 #define __cpu_to_le32(x) ((__u32)(x))
diff -u --recursive --new-file v2.3.46/linux/include/linux/byteorder/pdp_endian.h linux/include/linux/byteorder/pdp_endian.h
--- v2.3.46/linux/include/linux/byteorder/pdp_endian.h	Mon Jan 12 19:47:22 1998
+++ linux/include/linux/byteorder/pdp_endian.h	Thu Feb 17 09:20:13 2000
@@ -34,6 +34,18 @@
 #define __constant_ntohl(x) ___swahb32((x))
 #define __constant_htons(x) ___swab16((x))
 #define __constant_ntohs(x) ___swab16((x))
+#define __constant_cpu_to_le64(x) I DON'T KNOW
+#define __constant_le64_to_cpu(x) I DON'T KNOW
+#define __constant_cpu_to_le32(x) ___swahw32((x))
+#define __constant_le32_to_cpu(x) ___swahw32((x))
+#define __constant_cpu_to_le16(x) ((__u16)(x)
+#define __constant_le16_to_cpu(x) ((__u16)(x)
+#define __constant_cpu_to_be64(x) I DON'T KNOW
+#define __constant_be64_to_cpu(x) I DON'T KNOW
+#define __constant_cpu_to_be32(x) ___swahb32((x))
+#define __constant_be32_to_cpu(x) ___swahb32((x))
+#define __constant_cpu_to_be16(x) ___swab16((x))
+#define __constant_be16_to_cpu(x) ___swab16((x))
 #define __cpu_to_le64(x) I DON'T KNOW
 #define __le64_to_cpu(x) I DON'T KNOW
 #define __cpu_to_le32(x) ___swahw32((x))
diff -u --recursive --new-file v2.3.46/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.3.46/linux/include/linux/dcache.h	Fri Jan  7 19:13:23 2000
+++ linux/include/linux/dcache.h	Sun Feb 20 20:41:00 2000
@@ -98,6 +98,12 @@
 					 * renamed" and has to be
 					 * deleted on the last dput()
 					 */
+#define	DCACHE_NFSD_DISCONNECTED 0x0004	/* This dentry is not currently connected to the
+					 * dcache tree. Its parent will either be itself,
+					 * or will have this flag as well.
+					 * If this dentry points to a directory, then
+					 * s_nfsd_free_path semaphore will be down
+					 */
 
 /*
  * d_drop() unhashes the entry from the parent
diff -u --recursive --new-file v2.3.46/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.46/linux/include/linux/fs.h	Wed Feb 16 17:03:52 2000
+++ linux/include/linux/fs.h	Sun Feb 20 20:47:42 2000
@@ -435,6 +435,7 @@
 #define I_DIRTY		1
 #define I_LOCK		2
 #define I_FREEING	4
+#define I_CLEAR		8
 
 extern void __mark_inode_dirty(struct inode *);
 static inline void mark_inode_dirty(struct inode *inode)
@@ -614,6 +615,15 @@
 	 * even looking at it. You had been warned.
 	 */
 	struct semaphore s_vfs_rename_sem;	/* Kludge */
+
+	/* The next field is used by knfsd when converting a (inode number based)
+	 * file handle into a dentry. As it builds a path in the dcache tree from
+	 * the bottom up, there may for a time be a subpath of dentrys which is not
+	 * connected to the main tree.  This semaphore ensure that there is only ever
+	 * one such free path per filesystem.  Note that unconnected files (or other
+	 * non-directories) are allowed, but not unconnected diretories.
+	 */
+	struct semaphore s_nfsd_free_path_sem;
 };
 
 /*
@@ -676,6 +686,10 @@
 	int (*revalidate) (struct dentry *);
 };
 
+/*
+ * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
+ * without the big kernel lock held in all filesystems.
+ */
 struct super_operations {
 	void (*read_inode) (struct inode *);
 	void (*write_inode) (struct inode *);
diff -u --recursive --new-file v2.3.46/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.46/linux/include/linux/ide.h	Wed Feb 16 17:03:52 2000
+++ linux/include/linux/ide.h	Sun Feb 20 20:52:08 2000
@@ -157,11 +157,11 @@
  * Timeouts for various operations:
  */
 #define WAIT_DRQ	(5*HZ/100)	/* 50msec - spec allows up to 20ms */
-#ifdef CONFIG_APM
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 #define WAIT_READY	(5*HZ)		/* 5sec - some laptops are very slow */
 #else
 #define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
-#endif /* CONFIG_APM */
+#endif /* CONFIG_APM || CONFIG_APM_MODULE */
 #define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?)
 				            if all ATAPI CD is closed at boot */
 #define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
@@ -379,6 +379,7 @@
 	u32		dmatable_dma;	/* dma physical region descriptor table (dma view) */
 	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
 	int sg_nents;			/* Current number of entries in it */
+	int sg_dma_direction;		/* dma transfer direction */
 	struct hwif_s	*mate;		/* other hwif from same PCI chip */
 	unsigned long	dma_base;	/* base addr for dma ports */
 	unsigned	dma_extra;	/* extra addr for dma ports */
diff -u --recursive --new-file v2.3.46/linux/include/linux/if_bridge.h linux/include/linux/if_bridge.h
--- v2.3.46/linux/include/linux/if_bridge.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/if_bridge.h	Sun Feb 20 20:49:04 2000
@@ -0,0 +1,109 @@
+/*
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: if_bridge.h,v 1.1 2000/02/18 16:47:01 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_BRIDGE_H
+#define _LINUX_IF_BRIDGE_H
+
+#include <linux/types.h>
+
+#define BRCTL_VERSION 1
+
+#define BRCTL_GET_VERSION 0
+#define BRCTL_GET_BRIDGES 1
+#define BRCTL_ADD_BRIDGE 2
+#define BRCTL_DEL_BRIDGE 3
+#define BRCTL_ADD_IF 4
+#define BRCTL_DEL_IF 5
+#define BRCTL_GET_BRIDGE_INFO 6
+#define BRCTL_GET_PORT_LIST 7
+#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
+#define BRCTL_SET_BRIDGE_HELLO_TIME 9
+#define BRCTL_SET_BRIDGE_MAX_AGE 10
+#define BRCTL_SET_AGEING_TIME 11
+#define BRCTL_SET_GC_INTERVAL 12
+#define BRCTL_GET_PORT_INFO 13
+#define BRCTL_SET_BRIDGE_STP_STATE 14
+#define BRCTL_SET_BRIDGE_PRIORITY 15
+#define BRCTL_SET_PORT_PRIORITY 16
+#define BRCTL_SET_PATH_COST 17
+#define BRCTL_GET_FDB_ENTRIES 18
+
+#define BR_STATE_DISABLED 0
+#define BR_STATE_LISTENING 1
+#define BR_STATE_LEARNING 2
+#define BR_STATE_FORWARDING 3
+#define BR_STATE_BLOCKING 4
+
+struct __bridge_info
+{
+	__u64 designated_root;
+	__u64 bridge_id;
+	__u32 root_path_cost;
+	__u32 max_age;
+	__u32 hello_time;
+	__u32 forward_delay;
+	__u32 bridge_max_age;
+	__u32 bridge_hello_time;
+	__u32 bridge_forward_delay;
+	__u8 topology_change;
+	__u8 topology_change_detected;
+	__u8 root_port;
+	__u8 stp_enabled;
+	__u32 ageing_time;
+	__u32 gc_interval;
+	__u32 hello_timer_value;
+	__u32 tcn_timer_value;
+	__u32 topology_change_timer_value;
+	__u32 gc_timer_value;
+};
+
+struct __port_info
+{
+	__u64 designated_root;
+	__u64 designated_bridge;
+	__u16 port_id;
+	__u16 designated_port;
+	__u32 path_cost;
+	__u32 designated_cost;
+	__u8 state;
+	__u8 top_change_ack;
+	__u8 config_pending;
+	__u8 unused0;
+	__u32 message_age_timer_value;
+	__u32 forward_delay_timer_value;
+	__u32 hold_timer_value;
+};
+
+struct __fdb_entry
+{
+	__u8 mac_addr[6];
+	__u8 port_no;
+	__u8 is_local;
+	__u32 ageing_timer_value;
+	__u32 unused;
+};
+
+#ifdef __KERNEL__
+
+#include <linux/netdevice.h>
+
+struct net_bridge;
+struct net_bridge_port;
+
+extern int (*br_ioctl_hook)(unsigned long arg);
+extern void (*br_handle_frame_hook)(struct sk_buff *skb);
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/include/linux/input.h linux/include/linux/input.h
--- v2.3.46/linux/include/linux/input.h	Sat Feb 12 11:22:11 2000
+++ linux/include/linux/input.h	Fri Feb 18 10:33:47 2000
@@ -234,12 +234,11 @@
 #define KEY_RECORD		167		
 #define KEY_REWIND		168		
 #define KEY_PHONE		169
-#define KEY_CALENDAR		170
-#define KEY_NOTEPAD		171
-#define KEY_PROG3		172
-#define KEY_PRINT		173
-#define KEY_SOUND		174
-#define KEY_FULLSCREEN		175
+#define KEY_CONFIG		171
+#define KEY_HOMEPAGE		172
+#define KEY_REFRESH		173
+#define KEY_EXIT		174
+#define KEY_MOVE		175
 
 #define KEY_UNKNOWN		180
 
diff -u --recursive --new-file v2.3.46/linux/include/linux/irq.h linux/include/linux/irq.h
--- v2.3.46/linux/include/linux/irq.h	Tue Dec  7 09:32:51 1999
+++ linux/include/linux/irq.h	Sun Feb 20 20:50:18 2000
@@ -11,6 +11,7 @@
 #define IRQ_REPLAY	8	/* IRQ has been replayed but not acked yet */
 #define IRQ_AUTODETECT	16	/* IRQ is being autodetected */
 #define IRQ_WAITING	32	/* IRQ not yet seen - for autodetection */
+#define IRQ_LEVEL	64	/* IRQ level triggered */
 
 /*
  * Interrupt controller descriptor. This is all we need
diff -u --recursive --new-file v2.3.46/linux/include/linux/lists.h linux/include/linux/lists.h
--- v2.3.46/linux/include/linux/lists.h	Mon Mar 30 00:21:41 1998
+++ linux/include/linux/lists.h	Sun Feb 20 14:14:16 2000
@@ -48,7 +48,7 @@
 
 #define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam)
 #define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam)
-#define QUEUE_EMPTY(head, listnam) \
+#define QUEUE_IS_EMPTY(head, listnam) \
 	((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \
 	 ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head)) 
 
diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/debug.h linux/include/linux/lockd/debug.h
--- v2.3.46/linux/include/linux/lockd/debug.h	Wed Aug 18 16:44:09 1999
+++ linux/include/linux/lockd/debug.h	Sun Feb 20 20:48:18 2000
@@ -45,6 +45,7 @@
 #define NLMDBG_CLNTSUBS		0x0020
 #define NLMDBG_SVCSUBS		0x0040
 #define NLMDBG_HOSTCACHE	0x0080
+#define NLMDBG_XDR		0x0100
 #define NLMDBG_ALL		0x7fff
 
 
diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/lockd.h linux/include/linux/lockd/lockd.h
--- v2.3.46/linux/include/linux/lockd/lockd.h	Wed Aug 18 16:44:13 1999
+++ linux/include/linux/lockd/lockd.h	Sun Feb 20 20:52:53 2000
@@ -11,12 +11,16 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/in.h>
 #include <linux/fs.h>
 #include <linux/utsname.h>
 #include <linux/nfsd/nfsfh.h>
 #include <linux/lockd/bind.h>
 #include <linux/lockd/xdr.h>
+#ifdef CONFIG_LOCKD_V4
+#include <linux/lockd/xdr4.h>
+#endif
 #include <linux/lockd/debug.h>
 
 /*
@@ -112,6 +116,9 @@
  */
 extern struct rpc_program	nlm_program;
 extern struct svc_procedure	nlmsvc_procedures[];
+#ifdef CONFIG_LOCKD_V4
+extern struct svc_procedure	nlmsvc_procedures4[];
+#endif
 extern unsigned long		nlmsvc_grace_period;
 extern unsigned long		nlmsvc_timeout;
 
diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/nlm.h linux/include/linux/lockd/nlm.h
--- v2.3.46/linux/include/linux/lockd/nlm.h	Mon Apr  7 11:35:31 1997
+++ linux/include/linux/lockd/nlm.h	Sun Feb 20 10:41:18 2000
@@ -9,6 +9,8 @@
 #ifndef LINUX_LOCKD_NLM_H
 #define LINUX_LOCKD_NLM_H
 
+#include <linux/config.h>
+
 /* Maximum file offset in file_lock.fl_end */
 #ifdef OFFSET_MAX
 # define NLM_OFFSET_MAX		OFFSET_MAX
@@ -18,11 +20,18 @@
 
 /* Return states for NLM */
 enum {
-	NLM_LCK_GRANTED = 0,
-	NLM_LCK_DENIED,
-	NLM_LCK_DENIED_NOLOCKS,
-	NLM_LCK_BLOCKED,
-	NLM_LCK_DENIED_GRACE_PERIOD,
+	NLM_LCK_GRANTED			= 0,
+	NLM_LCK_DENIED			= 1,
+	NLM_LCK_DENIED_NOLOCKS		= 2,
+	NLM_LCK_BLOCKED			= 3,
+	NLM_LCK_DENIED_GRACE_PERIOD	= 4,
+#ifdef CONFIG_LOCKD_V4
+	NLM_DEADLCK			= 5,
+	NLM_ROFS			= 6,
+	NLM_STALE_FH			= 7,
+	NLM_FBIG			= 8,
+	NLM_FAILED			= 9,
+#endif
 };
 
 #define NLM_PROGRAM		100021
diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/xdr4.h linux/include/linux/lockd/xdr4.h
--- v2.3.46/linux/include/linux/lockd/xdr4.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/lockd/xdr4.h	Sun Feb 20 20:48:19 2000
@@ -0,0 +1,41 @@
+/*
+ * linux/include/linux/lockd/xdr.h
+ *
+ * XDR types for the NLM protocol
+ *
+ * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#ifndef LOCKD_XDR4_H
+#define LOCKD_XDR4_H
+
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/lockd/xdr.h>
+
+/* error codes new to NLMv4 */
+extern u32	nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig, nlm4_failed;
+
+
+int	nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_encode_void(struct svc_rqst *, u32 *, void *);
+int	nlm4svc_decode_void(struct svc_rqst *, u32 *, void *);
+int	nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
+/*
+int	nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+int	nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+int	nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+int	nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+ */
+
+#endif /* LOCKD_XDR4_H */
diff -u --recursive --new-file v2.3.46/linux/include/linux/lvm.h linux/include/linux/lvm.h
--- v2.3.46/linux/include/linux/lvm.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/lvm.h	Thu Feb 17 16:13:05 2000
@@ -0,0 +1,829 @@
+/*
+ * kernel/lvm.h
+ *
+ * Copyright (C) 1997 - 2000  Heinz Mauelshagen, Germany
+ *
+ * February-November 1997
+ * May-July 1998
+ * January-March,July,September,October,Dezember 1999
+ * January 2000
+ *
+ * lvm is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * lvm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ *
+ */
+
+/*
+ * Changelog
+ *
+ *    10/10/1997 - beginning of new structure creation
+ *    12/05/1998 - incorporated structures from lvm_v1.h and deleted lvm_v1.h
+ *    07/06/1998 - avoided LVM_KMALLOC_MAX define by using vmalloc/vfree
+ *                 instead of kmalloc/kfree
+ *    01/07/1998 - fixed wrong LVM_MAX_SIZE
+ *    07/07/1998 - extended pe_t structure by ios member (for statistic)
+ *    02/08/1998 - changes for official char/block major numbers
+ *    07/08/1998 - avoided init_module() and cleanup_module() to be static
+ *    29/08/1998 - seprated core and disk structure type definitions
+ *    01/09/1998 - merged kernel integration version (mike)
+ *    20/01/1999 - added LVM_PE_DISK_OFFSET macro for use in
+ *                 vg_read_with_pv_and_lv(), pv_move_pe(), pv_show_pe_text()...
+ *    18/02/1999 - added definition of time_disk_t structure for;
+ *                 keeps time stamps on disk for nonatomic writes (future)
+ *    15/03/1999 - corrected LV() and VG() macro definition to use argument
+ *                 instead of minor
+ *    03/07/1999 - define for genhd.c name handling
+ *    23/07/1999 - implemented snapshot part
+ *    08/12/1999 - changed LVM_LV_SIZE_MAX macro to reflect current 1TB limit
+ *    01/01/2000 - extended lv_v2 core structure by wait_queue member
+ *    12/02/2000 - integrated Andrea Arcagnelli's snapshot work
+ *
+ */
+
+
+#ifndef _LVM_H_INCLUDE
+#define _LVM_H_INCLUDE
+
+#define	_LVM_H_VERSION	"LVM 0.8final (15/2/2000)"
+
+/*
+ * preprocessor definitions
+ */
+/* if you like emergency reset code in the driver */
+#define	LVM_TOTAL_RESET
+
+#define LVM_GET_INODE
+#define	LVM_HD_NAME
+
+/* lots of debugging output (see driver source)
+   #define DEBUG_LVM_GET_INFO
+   #define DEBUG
+   #define DEBUG_MAP
+   #define DEBUG_MAP_SIZE
+   #define DEBUG_IOCTL
+   #define DEBUG_READ
+   #define DEBUG_GENDISK
+   #define DEBUG_VG_CREATE
+   #define DEBUG_LVM_BLK_OPEN
+   #define DEBUG_KFREE
+ */
+
+#include <linux/version.h>
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#include <linux/kdev_t.h>
+#undef __KERNEL__
+#else
+#include <linux/kdev_t.h>
+#endif
+
+#include <linux/major.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION ( 2, 3 ,0)
+#include <linux/spinlock.h>
+#else
+#include <asm/spinlock.h>
+#endif
+
+#include <asm/semaphore.h>
+#include <asm/page.h>
+
+#if !defined ( LVM_BLK_MAJOR) || !defined ( LVM_CHAR_MAJOR)
+#error Bad include/linux/major.h - LVM MAJOR undefined
+#endif
+
+
+#define LVM_STRUCT_VERSION	1	/* structure version */
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/* set the default structure version */
+#if ( LVM_STRUCT_VERSION == 1)
+#define pv_t pv_v1_t
+#define lv_t lv_v2_t
+#define vg_t vg_v1_t
+#define pv_disk_t pv_disk_v1_t
+#define lv_disk_t lv_disk_v1_t
+#define vg_disk_t vg_disk_v1_t
+#define lv_exception_t lv_v2_exception_t
+#endif
+
+
+/*
+ * i/o protocoll version
+ *
+ * defined here for the driver and defined seperate in the
+ * user land LVM parts
+ *
+ */
+#define	LVM_DRIVER_IOP_VERSION	        6
+
+#define LVM_NAME        "lvm"
+
+/*
+ * VG/LV indexing macros
+ */
+/* character minor maps directly to volume group */
+#define	VG_CHR(a) ( a)
+
+/* block minor indexes into a volume group/logical volume indirection table */
+#define	VG_BLK(a)	( vg_lv_map[a].vg_number)
+#define LV_BLK(a)	( vg_lv_map[a].lv_number)
+
+/*
+ * absolute limits for VGs, PVs per VG and LVs per VG
+ */
+#define ABS_MAX_VG	99
+#define ABS_MAX_PV	256
+#define ABS_MAX_LV	256	/* caused by 8 bit minor */
+
+#define MAX_VG  ABS_MAX_VG
+#define MAX_LV	ABS_MAX_LV
+#define	MAX_PV	ABS_MAX_PV
+
+#if ( MAX_VG > ABS_MAX_VG)
+#undef MAX_VG
+#define MAX_VG ABS_MAX_VG
+#endif
+
+#if ( MAX_LV > ABS_MAX_LV)
+#undef MAX_LV
+#define MAX_LV ABS_MAX_LV
+#endif
+
+
+/*
+ * VGDA: default disk spaces and offsets
+ *
+ *   there's space after the structures for later extensions.
+ *
+ *   offset            what                                size
+ *   ---------------   ----------------------------------  ------------
+ *   0                 physical volume structure           ~500 byte
+ *
+ *   1K                volume group structure              ~200 byte
+ *
+ *   5K                time stamp structure                ~
+ *
+ *   6K                namelist of physical volumes        128 byte each
+ *
+ *   6k + n * 128byte  n logical volume structures         ~300 byte each
+ *
+ *   + m * 328byte     m physical extent alloc. structs    4 byte each
+ *
+ *   End of disk -     first physical extent               typical 4 megabyte
+ *   PE total *
+ *   PE size
+ *
+ *
+ */
+
+/* DONT TOUCH THESE !!! */
+/* base of PV structure in disk partition */
+#define	LVM_PV_DISK_BASE  	0L
+
+/* size reserved for PV structure on disk */
+#define	LVM_PV_DISK_SIZE  	1024L
+
+/* base of VG structure in disk partition */
+#define	LVM_VG_DISK_BASE  	LVM_PV_DISK_SIZE
+
+/* size reserved for VG structure */
+#define	LVM_VG_DISK_SIZE  	( 9 * 512L)
+
+/* size reserved for timekeeping */
+#define	LVM_TIMESTAMP_DISK_BASE	( LVM_VG_DISK_BASE +  LVM_VG_DISK_SIZE)
+#define	LVM_TIMESTAMP_DISK_SIZE	512L	/* reserved for timekeeping */
+
+/* name list of physical volumes on disk */
+#define	LVM_PV_NAMELIST_DISK_BASE ( LVM_TIMESTAMP_DISK_BASE + \
+                                    LVM_TIMESTAMP_DISK_SIZE)
+
+/* now for the dynamically calculated parts of the VGDA */
+#define	LVM_LV_DISK_OFFSET(a, b) ( (a)->lv_on_disk.base + sizeof ( lv_t) * b)
+#define	LVM_DISK_SIZE(pv) 	 ( (pv)->pe_on_disk.base + \
+                                   (pv)->pe_on_disk.size)
+#define	LVM_PE_DISK_OFFSET(pe, pv)	( pe * pv->pe_size + \
+					  ( LVM_DISK_SIZE ( pv) / SECTOR_SIZE))
+#define	LVM_PE_ON_DISK_BASE(pv) \
+   { int rest; \
+     pv->pe_on_disk.base = pv->lv_on_disk.base + pv->lv_on_disk.size; \
+     if ( ( rest = pv->pe_on_disk.base % SECTOR_SIZE) != 0) \
+        pv->pe_on_disk.base += ( SECTOR_SIZE - rest); \
+   }
+/* END default disk spaces and offsets for PVs */
+
+
+/*
+ * LVM_PE_T_MAX corresponds to:
+ *
+ * 8KB PE size can map a ~512 MB logical volume at the cost of 1MB memory,
+ *
+ * 128MB PE size can map a 8TB logical volume at the same cost of memory.
+ *
+ * Default PE size of 4 MB gives a maximum logical volume size of 256 GB.
+ *
+ * Maximum PE size of 16GB gives a maximum logical volume size of 1024 TB.
+ *
+ * AFAIK, the actual kernels limit this to 1 TB.
+ *
+ * Should be a sufficient spectrum ;*)
+ */
+
+/* This is the usable size of disk_pe_t.le_num !!!        v     v */
+#define	LVM_PE_T_MAX		( ( 1 << ( sizeof ( uint16_t) * 8)) - 2)
+
+#define	LVM_LV_SIZE_MAX(a)	( ( long long) LVM_PE_T_MAX * (a)->pe_size > ( long long) 2*1024*1024*1024 ? ( long long) 2*1024*1024*1024 : ( long long) LVM_PE_T_MAX * (a)->pe_size)
+#define	LVM_MIN_PE_SIZE		( 8L * 2)	/* 8 KB in sectors */
+#define	LVM_MAX_PE_SIZE		( 16L * 1024L * 1024L * 2)	/* 16GB in sectors */
+#define	LVM_DEFAULT_PE_SIZE	( 4096L * 2)	/* 4 MB in sectors */
+#define	LVM_DEFAULT_STRIPE_SIZE	16L	/* 16 KB  */
+#define	LVM_MIN_STRIPE_SIZE	( PAGE_SIZE>>9)	/* PAGESIZE in sectors */
+#define	LVM_MAX_STRIPE_SIZE	( 512L * 2)	/* 512 KB in sectors */
+#define	LVM_MAX_STRIPES		128	/* max # of stripes */
+#define	LVM_MAX_SIZE            ( 1024LU * 1024 * 1024 * 2)	/* 1TB[sectors] */
+#define	LVM_MAX_MIRRORS    	2	/* future use */
+#define	LVM_MIN_READ_AHEAD	2	/* minimum read ahead sectors */
+#define	LVM_MAX_READ_AHEAD	120	/* maximum read ahead sectors */
+#define	LVM_MAX_LV_IO_TIMEOUT	60	/* seconds I/O timeout (future use) */
+#define	LVM_PARTITION           0xfe	/* LVM partition id */
+#define	LVM_NEW_PARTITION       0x8e	/* new LVM partition id (10/09/1999) */
+#define	LVM_PE_SIZE_PV_SIZE_REL	5	/* max relation PV size and PE size */
+
+#define	LVM_SNAPSHOT_MAX_CHUNK	1024	/* 1024 KB */
+#define	LVM_SNAPSHOT_DEF_CHUNK	64	/* 64  KB */
+#define	LVM_SNAPSHOT_MIN_CHUNK	1	/* 1   KB */
+
+#define	UNDEF	-1
+#define FALSE	0
+#define TRUE	1
+
+
+/*
+ * ioctls
+ */
+/* volume group */
+#define	VG_CREATE               _IOW ( 0xfe, 0x00, 1)
+#define	VG_REMOVE               _IOW ( 0xfe, 0x01, 1)
+
+#define	VG_EXTEND               _IOW ( 0xfe, 0x03, 1)
+#define	VG_REDUCE               _IOW ( 0xfe, 0x04, 1)
+
+#define	VG_STATUS               _IOWR ( 0xfe, 0x05, 1)
+#define	VG_STATUS_GET_COUNT     _IOWR ( 0xfe, 0x06, 1)
+#define	VG_STATUS_GET_NAMELIST  _IOWR ( 0xfe, 0x07, 1)
+
+#define	VG_SET_EXTENDABLE       _IOW ( 0xfe, 0x08, 1)
+
+
+/* logical volume */
+#define	LV_CREATE               _IOW ( 0xfe, 0x20, 1)
+#define	LV_REMOVE               _IOW ( 0xfe, 0x21, 1)
+
+#define	LV_ACTIVATE             _IO ( 0xfe, 0x22)
+#define	LV_DEACTIVATE           _IO ( 0xfe, 0x23)
+
+#define	LV_EXTEND               _IOW ( 0xfe, 0x24, 1)
+#define	LV_REDUCE               _IOW ( 0xfe, 0x25, 1)
+
+#define	LV_STATUS_BYNAME        _IOWR ( 0xfe, 0x26, 1)
+#define	LV_STATUS_BYINDEX       _IOWR ( 0xfe, 0x27, 1)
+
+#define LV_SET_ACCESS           _IOW ( 0xfe, 0x28, 1)
+#define LV_SET_ALLOCATION       _IOW ( 0xfe, 0x29, 1)
+#define LV_SET_STATUS           _IOW ( 0xfe, 0x2a, 1)
+
+#define LE_REMAP                _IOW ( 0xfe, 0x2b, 1)
+
+
+/* physical volume */
+#define	PV_STATUS               _IOWR ( 0xfe, 0x40, 1)
+#define	PV_CHANGE               _IOWR ( 0xfe, 0x41, 1)
+#define	PV_FLUSH                _IOW ( 0xfe, 0x42, 1)
+
+/* physical extent */
+#define	PE_LOCK_UNLOCK          _IOW ( 0xfe, 0x50, 1)
+
+/* i/o protocol version */
+#define	LVM_GET_IOP_VERSION     _IOR ( 0xfe, 0x98, 1)
+
+#ifdef LVM_TOTAL_RESET
+/* special reset function for testing purposes */
+#define	LVM_RESET               _IO ( 0xfe, 0x99)
+#endif
+
+/* lock the logical volume manager */
+#define	LVM_LOCK_LVM            _IO ( 0xfe, 0x100)
+/* END ioctls */
+
+
+/*
+ * Status flags
+ */
+/* volume group */
+#define	VG_ACTIVE            0x01	/* vg_status */
+#define	VG_EXPORTED          0x02	/*     "     */
+#define	VG_EXTENDABLE        0x04	/*     "     */
+
+#define	VG_READ              0x01	/* vg_access */
+#define	VG_WRITE             0x02	/*     "     */
+
+/* logical volume */
+#define	LV_ACTIVE            0x01	/* lv_status */
+#define	LV_SPINDOWN          0x02	/*     "     */
+
+#define	LV_READ              0x01	/* lv_access */
+#define	LV_WRITE             0x02	/*     "     */
+#define	LV_SNAPSHOT          0x04	/*     "     */
+#define	LV_SNAPSHOT_ORG      0x08	/*     "     */
+
+#define	LV_BADBLOCK_ON       0x01	/* lv_badblock */
+
+#define	LV_STRICT            0x01	/* lv_allocation */
+#define	LV_CONTIGUOUS        0x02	/*       "       */
+
+/* physical volume */
+#define	PV_ACTIVE            0x01	/* pv_status */
+#define	PV_ALLOCATABLE       0x02	/* pv_allocatable */
+
+
+/*
+ * Structure definitions core/disk follow
+ *
+ * conditional conversion takes place on big endian architectures
+ * in functions * pv_copy_*(), vg_copy_*() and lv_copy_*()
+ *
+ */
+
+#define	NAME_LEN		128	/* don't change!!! */
+#define	UUID_LEN		16	/* don't change!!! */
+
+/* remap physical sector/rdev pairs */
+typedef struct
+{
+    struct list_head hash;
+    ulong rsector_org;
+    kdev_t rdev_org;
+    ulong rsector_new;
+    kdev_t rdev_new;
+} lv_block_exception_t;
+
+
+/* disk stored pe information */
+typedef struct
+  {
+    uint16_t lv_num;
+    uint16_t le_num;
+  }
+disk_pe_t;
+
+/* disk stored PV, VG, LV and PE size and offset information */
+typedef struct
+  {
+    uint32_t base;
+    uint32_t size;
+  }
+lvm_disk_data_t;
+
+
+/*
+ * Structure Physical Volume (PV) Version 1
+ */
+
+/* core */
+typedef struct
+  {
+    uint8_t id[2];		/* Identifier */
+    uint16_t version;		/* HM lvm version */
+    lvm_disk_data_t pv_on_disk;
+    lvm_disk_data_t vg_on_disk;
+    lvm_disk_data_t pv_namelist_on_disk;
+    lvm_disk_data_t lv_on_disk;
+    lvm_disk_data_t pe_on_disk;
+    uint8_t pv_name[NAME_LEN];
+    uint8_t vg_name[NAME_LEN];
+    uint8_t system_id[NAME_LEN];	/* for vgexport/vgimport */
+    kdev_t pv_dev;
+    uint32_t pv_number;
+    uint32_t pv_status;
+    uint32_t pv_allocatable;
+    uint32_t pv_size;		/* HM */
+    uint32_t lv_cur;
+    uint32_t pe_size;
+    uint32_t pe_total;
+    uint32_t pe_allocated;
+    uint32_t pe_stale;		/* for future use */
+
+    disk_pe_t *pe;		/* HM */
+    struct inode *inode;	/* HM */
+  }
+pv_v1_t;
+
+/* disk */
+typedef struct
+  {
+    uint8_t id[2];		/* Identifier */
+    uint16_t version;		/* HM lvm version */
+    lvm_disk_data_t pv_on_disk;
+    lvm_disk_data_t vg_on_disk;
+    lvm_disk_data_t pv_namelist_on_disk;
+    lvm_disk_data_t lv_on_disk;
+    lvm_disk_data_t pe_on_disk;
+    uint8_t pv_name[NAME_LEN];
+    uint8_t vg_name[NAME_LEN];
+    uint8_t system_id[NAME_LEN];	/* for vgexport/vgimport */
+    uint32_t pv_major;
+    uint32_t pv_number;
+    uint32_t pv_status;
+    uint32_t pv_allocatable;
+    uint32_t pv_size;		/* HM */
+    uint32_t lv_cur;
+    uint32_t pe_size;
+    uint32_t pe_total;
+    uint32_t pe_allocated;
+  }
+pv_disk_v1_t;
+
+
+/*
+ * Structure Physical Volume (PV) Version 2 (future!)
+ */
+
+typedef struct
+  {
+    uint8_t id[2];		/* Identifier */
+    uint16_t version;		/* HM lvm version */
+    lvm_disk_data_t pv_on_disk;
+    lvm_disk_data_t vg_on_disk;
+    lvm_disk_data_t pv_uuid_on_disk;
+    lvm_disk_data_t lv_on_disk;
+    lvm_disk_data_t pe_on_disk;
+    uint8_t pv_name[NAME_LEN];
+    uint8_t vg_name[NAME_LEN];
+    uint8_t system_id[NAME_LEN];	/* for vgexport/vgimport */
+    kdev_t pv_dev;
+    uint32_t pv_number;
+    uint32_t pv_status;
+    uint32_t pv_allocatable;
+    uint32_t pv_size;		/* HM */
+    uint32_t lv_cur;
+    uint32_t pe_size;
+    uint32_t pe_total;
+    uint32_t pe_allocated;
+    uint32_t pe_stale;		/* for future use */
+    disk_pe_t *pe;		/* HM */
+    struct inode *inode;	/* HM */
+    /* delta to version 1 starts here */
+    uint8_t pv_uuid[UUID_LEN];
+    uint32_t pv_atime;		/* PV access time */
+    uint32_t pv_ctime;		/* PV creation time */
+    uint32_t pv_mtime;		/* PV modification time */
+  }
+pv_v2_t;
+
+
+/*
+ * Structures for Logical Volume (LV)
+ */
+
+/* core PE information */
+typedef struct
+  {
+    kdev_t dev;
+    uint32_t pe;		/* to be changed if > 2TB */
+    uint32_t reads;
+    uint32_t writes;
+  }
+pe_t;
+
+typedef struct
+  {
+    uint8_t lv_name[NAME_LEN];
+    kdev_t old_dev;
+    kdev_t new_dev;
+    ulong old_pe;
+    ulong new_pe;
+  }
+le_remap_req_t;
+
+
+
+/*
+ * Structure Logical Volume (LV) Version 1
+ */
+
+/* disk */
+typedef struct
+  {
+    uint8_t lv_name[NAME_LEN];
+    uint8_t vg_name[NAME_LEN];
+    uint32_t lv_access;
+    uint32_t lv_status;
+    uint32_t lv_open;		/* HM */
+    uint32_t lv_dev;		/* HM */
+    uint32_t lv_number;		/* HM */
+    uint32_t lv_mirror_copies;	/* for future use */
+    uint32_t lv_recovery;	/*       "        */
+    uint32_t lv_schedule;	/*       "        */
+    uint32_t lv_size;
+    uint32_t dummy;
+    uint32_t lv_current_le;	/* for future use */
+    uint32_t lv_allocated_le;
+    uint32_t lv_stripes;
+    uint32_t lv_stripesize;
+    uint32_t lv_badblock;	/* for future use */
+    uint32_t lv_allocation;
+    uint32_t lv_io_timeout;	/* for future use */
+    uint32_t lv_read_ahead;	/* HM, for future use */
+  }
+lv_disk_v1_t;
+
+
+/*
+ * Structure Logical Volume (LV) Version 2
+ */
+
+/* core */
+typedef struct lv_v2
+  {
+    uint8_t lv_name[NAME_LEN];
+    uint8_t vg_name[NAME_LEN];
+    uint32_t lv_access;
+    uint32_t lv_status;
+    uint32_t lv_open;		/* HM */
+    kdev_t lv_dev;		/* HM */
+    uint32_t lv_number;		/* HM */
+    uint32_t lv_mirror_copies;	/* for future use */
+    uint32_t lv_recovery;	/*       "        */
+    uint32_t lv_schedule;	/*       "        */
+    uint32_t lv_size;
+    pe_t *lv_current_pe;	/* HM */
+    uint32_t lv_current_le;	/* for future use */
+    uint32_t lv_allocated_le;
+    uint32_t lv_stripes;
+    uint32_t lv_stripesize;
+    uint32_t lv_badblock;	/* for future use */
+    uint32_t lv_allocation;
+    uint32_t lv_io_timeout;	/* for future use */
+    uint32_t lv_read_ahead;
+
+    /* delta to version 1 starts here */
+    struct lv_v2 *lv_snapshot_org;
+    struct lv_v2 *lv_snapshot_prev;
+    struct lv_v2 *lv_snapshot_next;
+    lv_block_exception_t *lv_block_exception;
+    uint32_t lv_remap_ptr;
+    uint32_t lv_remap_end;
+    uint32_t lv_chunk_size;
+    uint32_t lv_snapshot_minor;
+    struct kiobuf * lv_iobuf;
+    struct semaphore lv_snapshot_sem;
+    struct list_head * lv_snapshot_hash_table;
+    unsigned long lv_snapshot_hash_mask;
+} lv_v2_t;
+
+/* disk */
+typedef struct
+  {
+    uint8_t lv_name[NAME_LEN];
+    uint8_t vg_name[NAME_LEN];
+    uint32_t lv_access;
+    uint32_t lv_status;
+    uint32_t lv_open;		/* HM */
+    uint32_t lv_dev;		/* HM */
+    uint32_t lv_number;		/* HM */
+    uint32_t lv_mirror_copies;	/* for future use */
+    uint32_t lv_recovery;	/*       "        */
+    uint32_t lv_schedule;	/*       "        */
+    uint32_t lv_size;
+    uint32_t dummy;
+    uint32_t lv_current_le;	/* for future use */
+    uint32_t lv_allocated_le;
+    uint32_t lv_stripes;
+    uint32_t lv_stripesize;
+    uint32_t lv_badblock;	/* for future use */
+    uint32_t lv_allocation;
+    uint32_t lv_io_timeout;	/* for future use */
+    uint32_t lv_read_ahead;	/* HM, for future use */
+  }
+lv_disk_v2_t;
+
+
+/*
+ * Structure Volume Group (VG) Version 1
+ */
+
+typedef struct
+  {
+    uint8_t vg_name[NAME_LEN];	/* volume group name */
+    uint32_t vg_number;		/* volume group number */
+    uint32_t vg_access;		/* read/write */
+    uint32_t vg_status;		/* active or not */
+    uint32_t lv_max;		/* maximum logical volumes */
+    uint32_t lv_cur;		/* current logical volumes */
+    uint32_t lv_open;		/* open    logical volumes */
+    uint32_t pv_max;		/* maximum physical volumes */
+    uint32_t pv_cur;		/* current physical volumes FU */
+    uint32_t pv_act;		/* active physical volumes */
+    uint32_t dummy;		/* was obsolete max_pe_per_pv */
+    uint32_t vgda;		/* volume group descriptor arrays FU */
+    uint32_t pe_size;		/* physical extent size in sectors */
+    uint32_t pe_total;		/* total of physical extents */
+    uint32_t pe_allocated;	/* allocated physical extents */
+    uint32_t pvg_total;		/* physical volume groups FU */
+    struct proc_dir_entry *proc;
+    pv_t *pv[ABS_MAX_PV + 1];	/* physical volume struct pointers */
+    lv_t *lv[ABS_MAX_LV + 1];	/* logical  volume struct pointers */
+  }
+vg_v1_t;
+
+typedef struct
+  {
+    uint8_t vg_name[NAME_LEN];	/* volume group name */
+    uint32_t vg_number;		/* volume group number */
+    uint32_t vg_access;		/* read/write */
+    uint32_t vg_status;		/* active or not */
+    uint32_t lv_max;		/* maximum logical volumes */
+    uint32_t lv_cur;		/* current logical volumes */
+    uint32_t lv_open;		/* open    logical volumes */
+    uint32_t pv_max;		/* maximum physical volumes */
+    uint32_t pv_cur;		/* current physical volumes FU */
+    uint32_t pv_act;		/* active physical volumes */
+    uint32_t dummy;
+    uint32_t vgda;		/* volume group descriptor arrays FU */
+    uint32_t pe_size;		/* physical extent size in sectors */
+    uint32_t pe_total;		/* total of physical extents */
+    uint32_t pe_allocated;	/* allocated physical extents */
+    uint32_t pvg_total;		/* physical volume groups FU */
+  }
+vg_disk_v1_t;
+
+/*
+ * Structure Volume Group (VG) Version 2
+ */
+
+typedef struct
+  {
+    uint8_t vg_name[NAME_LEN];	/* volume group name */
+    uint32_t vg_number;		/* volume group number */
+    uint32_t vg_access;		/* read/write */
+    uint32_t vg_status;		/* active or not */
+    uint32_t lv_max;		/* maximum logical volumes */
+    uint32_t lv_cur;		/* current logical volumes */
+    uint32_t lv_open;		/* open    logical volumes */
+    uint32_t pv_max;		/* maximum physical volumes */
+    uint32_t pv_cur;		/* current physical volumes FU */
+    uint32_t pv_act;		/* future: active physical volumes */
+    uint32_t max_pe_per_pv;	/* OBSOLETE maximum PE/PV */
+    uint32_t vgda;		/* volume group descriptor arrays FU */
+    uint32_t pe_size;		/* physical extent size in sectors */
+    uint32_t pe_total;		/* total of physical extents */
+    uint32_t pe_allocated;	/* allocated physical extents */
+    uint32_t pvg_total;		/* physical volume groups FU */
+    struct proc_dir_entry *proc;
+    pv_t *pv[ABS_MAX_PV + 1];	/* physical volume struct pointers */
+    lv_t *lv[ABS_MAX_LV + 1];	/* logical  volume struct pointers */
+    /* delta to version 1 starts here */
+    uint8_t vg_uuid[UUID_LEN];	/*  volume group UUID */
+    time_t vg_atime;		/* VG access time */
+    time_t vg_ctime;		/* VG creation time */
+    time_t vg_mtime;		/* VG modification time */
+  }
+vg_v2_t;
+
+
+/*
+ * Timekeeping structure on disk (0.7 feature)
+ *
+ * Holds several timestamps for start/stop time of non
+ * atomic VGDA disk i/o operations
+ *
+ */
+
+typedef struct
+  {
+    uint32_t seconds;		/* seconds since the epoch */
+    uint32_t jiffies;		/* micro timer */
+  }
+lvm_time_t;
+
+#define	TIMESTAMP_ID_SIZE	2
+typedef struct
+  {
+    uint8_t id[TIMESTAMP_ID_SIZE];	/* Identifier */
+    lvm_time_t pv_vg_lv_pe_io_begin;
+    lvm_time_t pv_vg_lv_pe_io_end;
+    lvm_time_t pv_io_begin;
+    lvm_time_t pv_io_end;
+    lvm_time_t vg_io_begin;
+    lvm_time_t vg_io_end;
+    lvm_time_t lv_io_begin;
+    lvm_time_t lv_io_end;
+    lvm_time_t pe_io_begin;
+    lvm_time_t pe_io_end;
+    lvm_time_t pe_move_io_begin;
+    lvm_time_t pe_move_io_end;
+    uint8_t dummy[LVM_TIMESTAMP_DISK_SIZE -
+		  TIMESTAMP_ID_SIZE -
+		  12 * sizeof (lvm_time_t)];
+    /* ATTENTION  ^^ */
+  }
+timestamp_disk_t;
+
+/* same on disk and in core so far */
+typedef timestamp_disk_t timestamp_t;
+
+/* function identifiers for timestamp actions */
+typedef enum
+  {
+    PV_VG_LV_PE_IO_BEGIN,
+    PV_VG_LV_PE_IO_END,
+    PV_IO_BEGIN,
+    PV_IO_END,
+    VG_IO_BEGIN,
+    VG_IO_END,
+    LV_IO_BEGIN,
+    LV_IO_END,
+    PE_IO_BEGIN,
+    PE_IO_END,
+    PE_MOVE_IO_BEGIN,
+    PE_MOVE_IO_END
+  }
+ts_fct_id_t;
+
+
+/*
+ * Request structures for ioctls
+ */
+
+/* Request structure PV_STATUS */
+typedef struct
+  {
+    char pv_name[NAME_LEN];
+    pv_t *pv;
+  }
+pv_status_req_t, pv_change_req_t;
+
+/* Request structure PV_FLUSH */
+typedef struct
+  {
+    char pv_name[NAME_LEN];
+    kdev_t pv_dev;
+  }
+pv_flush_req_t;
+
+
+/* Request structure PE_MOVE */
+typedef struct
+  {
+    enum
+      {
+	LOCK_PE, UNLOCK_PE
+      }
+    lock;
+    struct
+      {
+	kdev_t lv_dev;
+	kdev_t pv_dev;
+	uint32_t pv_offset;
+      }
+    data;
+  }
+pe_lock_req_t;
+
+
+/* Request structure LV_STATUS_BYNAME */
+typedef struct
+  {
+    char lv_name[NAME_LEN];
+    lv_t *lv;
+  }
+lv_status_byname_req_t, lv_req_t;
+
+/* Request structure LV_STATUS_BYINDEX */
+typedef struct
+  {
+    ulong lv_index;
+    lv_t *lv;
+  }
+lv_status_byindex_req_t;
+
+#endif /* #ifndef _LVM_H_INCLUDE */
diff -u --recursive --new-file v2.3.46/linux/include/linux/major.h linux/include/linux/major.h
--- v2.3.46/linux/include/linux/major.h	Fri Jan 21 18:19:17 2000
+++ linux/include/linux/major.h	Thu Feb 17 16:13:05 2000
@@ -83,6 +83,8 @@
 #define IDE4_MAJOR	56
 #define IDE5_MAJOR	57
 
+#define LVM_BLK_MAJOR	58	/* Logical Volume Manager */
+
 #define SCSI_DISK1_MAJOR	65
 #define SCSI_DISK2_MAJOR	66
 #define SCSI_DISK3_MAJOR	67
@@ -92,8 +94,6 @@
 #define SCSI_DISK7_MAJOR	71
 
 
-#define LVM_BLK_MAJOR	58	/* Logical Volume Manager */
-
 #define COMPAQ_SMART2_MAJOR	72
 #define COMPAQ_SMART2_MAJOR1	73
 #define COMPAQ_SMART2_MAJOR2	74
@@ -103,15 +103,11 @@
 #define COMPAQ_SMART2_MAJOR6	78
 #define COMPAQ_SMART2_MAJOR7	79
 
-#define LVM_BLK_MAJOR	58	/* Logical Volume Manager */
-
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
 #define DASD_MAJOR      94	/* Official assignations from Peter */
 
-#define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
-
 #define MDISK_MAJOR     95	/* Official assignations from Peter */
 
 #define I2O_MAJOR		80	/* 80->87 */
@@ -124,6 +120,8 @@
 #define AURORA_MAJOR 79
 
 #define PHONE_MAJOR	100
+
+#define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
 
 #define RTF_MAJOR	150
 #define RAW_MAJOR	162
diff -u --recursive --new-file v2.3.46/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.3.46/linux/include/linux/netdevice.h	Sun Feb 13 19:29:04 2000
+++ linux/include/linux/netdevice.h	Sun Feb 20 20:48:57 2000
@@ -174,14 +174,17 @@
 	unsigned long	hh_data[16/sizeof(unsigned long)];
 };
 
+/* These flag bits are private to the generic network queueing
+ * layer, they may not be explicitly referenced by any other
+ * code.
+ */
+
 enum netdev_state_t
 {
-	LINK_STATE_XOFF=0,
-	LINK_STATE_DOWN,
-	LINK_STATE_START,
-	LINK_STATE_RXSEM,
-	LINK_STATE_TXSEM,
-	LINK_STATE_SCHED
+	__LINK_STATE_XOFF=0,
+	__LINK_STATE_START,
+	__LINK_STATE_PRESENT,
+	__LINK_STATE_SCHED
 };
 
 
@@ -313,9 +316,6 @@
 	/* Called after last user reference disappears. */
 	void			(*destructor)(struct net_device *dev);
 
-	/* Bridge stuff */
-	int			bridge_port_id;		
-	
 	/* Pointers to interface service routines.	*/
 	int			(*open)(struct net_device *dev);
 	int			(*stop)(struct net_device *dev);
@@ -356,6 +356,9 @@
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 	int			(*accept_fastpath)(struct net_device *, struct dst_entry*);
 
+	/* bridge stuff */
+	struct net_bridge_port	*br_port;
+
 #ifdef CONFIG_NET_FASTROUTE
 #define NETDEV_FASTROUTE_HMASK 0xF
 	/* Semi-private data. Keep it at the end of device struct. */
@@ -431,7 +434,7 @@
 
 extern __inline__ void __netif_schedule(struct net_device *dev)
 {
-	if (!test_and_set_bit(LINK_STATE_SCHED, &dev->state)) {
+	if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) {
 		unsigned long flags;
 		int cpu = smp_processor_id();
 
@@ -445,26 +448,59 @@
 
 extern __inline__ void netif_schedule(struct net_device *dev)
 {
-	if (!test_bit(LINK_STATE_XOFF, &dev->state))
+	if (!test_bit(__LINK_STATE_XOFF, &dev->state))
 		__netif_schedule(dev);
 }
 
 extern __inline__ void netif_start_queue(struct net_device *dev)
 {
-	clear_bit(LINK_STATE_XOFF, &dev->state);
+	clear_bit(__LINK_STATE_XOFF, &dev->state);
 }
 
 extern __inline__ void netif_wake_queue(struct net_device *dev)
 {
-	if (test_and_clear_bit(LINK_STATE_XOFF, &dev->state))
+	if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
 		__netif_schedule(dev);
 }
 
 extern __inline__ void netif_stop_queue(struct net_device *dev)
 {
-	set_bit(LINK_STATE_XOFF, &dev->state);
+	set_bit(__LINK_STATE_XOFF, &dev->state);
+}
+
+extern __inline__ int netif_queue_stopped(struct net_device *dev)
+{
+	return test_bit(__LINK_STATE_XOFF, &dev->state);
+}
+
+extern __inline__ int netif_running(struct net_device *dev)
+{
+	return test_bit(__LINK_STATE_START, &dev->state);
 }
 
+/* Hot-plugging. */
+extern __inline__ int netif_device_present(struct net_device *dev)
+{
+	return test_bit(__LINK_STATE_PRESENT, &dev->state);
+}
+
+extern __inline__ void netif_device_detach(struct net_device *dev)
+{
+	if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) &&
+	    netif_running(dev))
+		netif_stop_queue(dev);
+}
+
+extern __inline__ void netif_device_attach(struct net_device *dev)
+{
+	if (test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) &&
+	    netif_running(dev))
+		netif_wake_queue(dev);
+}
+
+/* Use this variant when it is known for sure that it
+ * is executing from interrupt context.
+ */
 extern __inline__ void dev_kfree_skb_irq(struct sk_buff *skb)
 {
 	if (atomic_dec_and_test(&skb->users)) {
@@ -479,7 +515,18 @@
 	}
 }
 
+/* Use this variant in places where it could be invoked
+ * either from interrupt or non-interrupt context.
+ */
+extern __inline__ void dev_kfree_skb_any(struct sk_buff *skb)
+{
+	if (in_irq())
+		dev_kfree_skb_irq(skb);
+	else
+		dev_kfree_skb(skb);
+}
 
+extern void		net_call_rx_atomic(void (*fn)(void));
 #define HAVE_NETIF_RX 1
 extern void		netif_rx(struct sk_buff *skb);
 extern int		dev_ioctl(unsigned int cmd, void *);
diff -u --recursive --new-file v2.3.46/linux/include/linux/nfsd/xdr3.h linux/include/linux/nfsd/xdr3.h
--- v2.3.46/linux/include/linux/nfsd/xdr3.h	Tue Dec 14 01:27:24 1999
+++ linux/include/linux/nfsd/xdr3.h	Sun Feb 20 20:48:14 2000
@@ -296,19 +296,5 @@
 int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name,
 				int namlen, off_t offset, ino_t ino);
 
-#ifdef __KERNEL__
-
-/*
- * This is needed in nfs_readdir for encoding NFS3 directory cookies.
- */
-static inline u32 *
-enc64(u32 *p, u64 val)
-{
-	*p++ = htonl(val >> 32);
-	*p++ = htonl(val & 0xffffffff);
-	return p;
-}
-
-#endif /* __KERNEL__ */
 
 #endif /* _LINUX_NFSD_XDR3_H */
diff -u --recursive --new-file v2.3.46/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.46/linux/include/linux/pci.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/pci.h	Sun Feb 20 20:48:23 2000
@@ -286,6 +286,12 @@
 #include <linux/ioport.h>
 #include <linux/list.h>
 
+/* This defines the direction arg to the DMA mapping routines. */
+#define PCI_DMA_BIDIRECTIONAL	0
+#define PCI_DMA_TODEVICE	1
+#define PCI_DMA_FROMDEVICE	2
+#define PCI_DMA_NONE		3
+
 #include <asm/pci.h>
 
 #define DEVICE_COUNT_COMPATIBLE	4
@@ -568,7 +574,39 @@
 { return NULL; }
 
 extern inline void pci_set_master(struct pci_dev *dev) { }
-extern inline int pci_enable_device(struct pci_dev *dev) { return 0; }
+extern inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
+extern inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; }
+
+#else
+
+/*
+ * a helper function which helps ensure correct pci_driver
+ * setup and cleanup for commonly-encountered hotplug/modular cases
+ *
+ * This MUST stay in a header, as it checks for -DMODULE
+ */
+extern inline int pci_module_init(struct pci_driver *drv)
+{
+	int rc = pci_register_driver (drv);
+
+	if (rc > 0)
+		return 0;
+
+	/* iff CONFIG_HOTPLUG and built into kernel, we should
+	 * leave the driver around for future hotplug events.
+	 * For the module case, a hotplug daemon of some sort
+	 * should load a module in response to an insert event. */
+#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
+	if (rc == 0)
+		return 0;
+#endif
+
+	/* if we get here, we need to clean up pci driver instance
+	 * and return some sort of error */
+	pci_unregister_driver (drv);
+	
+	return -ENODEV;
+}
 
 #endif /* !CONFIG_PCI */
 
diff -u --recursive --new-file v2.3.46/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.3.46/linux/include/linux/pci_ids.h	Sat Feb 12 11:22:11 2000
+++ linux/include/linux/pci_ids.h	Sun Feb 20 08:48:45 2000
@@ -167,6 +167,8 @@
 #define PCI_DEVICE_ID_ATI_RAGE128_RF	0x5246
 #define PCI_DEVICE_ID_ATI_RAGE128_RK	0x524b
 #define PCI_DEVICE_ID_ATI_RAGE128_RL	0x524c
+#define PCI_DEVICE_ID_ATI_RAGE128_PF	0x5046
+#define PCI_DEVICE_ID_ATI_RAGE128_PR	0x5052
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
diff -u --recursive --new-file v2.3.46/linux/include/linux/pm.h linux/include/linux/pm.h
--- v2.3.46/linux/include/linux/pm.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/pm.h	Sun Feb 20 20:47:37 2000
@@ -105,7 +105,7 @@
 	struct list_head entry;
 };
 
-#if defined(CONFIG_ACPI) || defined(CONFIG_APM)
+#if defined(CONFIG_ACPI) || defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 
 extern int pm_active;
 
@@ -141,7 +141,7 @@
 extern inline void pm_access(struct pm_dev *dev) {}
 extern inline void pm_dev_idle(struct pm_dev *dev) {}
 
-#else // CONFIG_ACPI || CONFIG_APM
+#else /* CONFIG_ACPI || CONFIG_APM || CONFIG_APM_MODULE */
 
 #define PM_IS_ACTIVE() 0
 
@@ -169,11 +169,11 @@
 extern inline void pm_access(struct pm_dev *dev) {}
 extern inline void pm_dev_idle(struct pm_dev *dev) {}
 
-#endif // CONFIG_ACPI || CONFIG_APM
+#endif /* CONFIG_ACPI || CONFIG_APM || CONFIG_APM_MODULE */
 
 extern void (*pm_idle)(void);
 extern void (*pm_power_off)(void);
 
-#endif // __KERNEL__
+#endif /* __KERNEL__ */
 
 #endif /* _LINUX_PM_H */
diff -u --recursive --new-file v2.3.46/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.46/linux/include/linux/sched.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/sched.h	Sun Feb 20 20:47:49 2000
@@ -389,44 +389,45 @@
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
  */
-#define INIT_TASK(name) \
-/* state etc */	{ 0,0,0,KERNEL_DS,&default_exec_domain,0, \
-/* avg_slice */	0, -1, \
-/* counter */	DEF_PRIORITY,DEF_PRIORITY,SCHED_OTHER, \
-/* mm */	NULL, &init_mm, \
-/* has_cpu */	0,0, \
-/* run_list */	LIST_HEAD_INIT(init_task.run_list), \
-/* next_task */	&init_task,&init_task, \
-/* last_proc */	0, \
-/* binfmt */	NULL, \
-/* ec,brk... */	0,0,0,0,0,0, \
-/* pid etc.. */	0,0,0,0,0, \
-/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
-/* pidhash */	NULL, NULL, \
-/* chld wait */	__WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \
-/* timeout */	0,0,0,0,0,0,0, \
-/* timer */	{ NULL, NULL, 0, 0, it_real_fn }, \
-/* utime */	{0,0,0,0},0, \
-/* per CPU times */ {0, }, {0, }, \
-/* flt */	0,0,0,0,0,0, \
-/* swp */	0, \
-/* process credentials */					\
-/* uid etc */	0,0,0,0,0,0,0,0,				\
-/* suppl grps*/ 0, {0,},					\
-/* caps */      CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \
-/* user */	NULL,						\
-/* rlimits */   INIT_RLIMITS, \
-/* math */	0, \
-/* comm */	"swapper", \
-/* fs info */	0,NULL, \
-/* ipc */	NULL, NULL, \
-/* thread */	INIT_THREAD, \
-/* fs */	&init_fs, \
-/* files */	&init_files, \
-/* signals */	SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
-/* exec cts */	0,0, \
-/* exit_sem */	__MUTEX_INITIALIZER(name.exit_sem),	\
+#define INIT_TASK(tsk)	\
+{									\
+    state:		0,						\
+    flags:		0,						\
+    sigpending:		0,						\
+    addr_limit:		KERNEL_DS,					\
+    exec_domain:	&default_exec_domain,				\
+    lock_depth:		-1,						\
+    counter:		DEF_PRIORITY,					\
+    priority:		DEF_PRIORITY,					\
+    policy:		SCHED_OTHER,					\
+    mm:			NULL,						\
+    active_mm:		&init_mm,					\
+    run_list:		LIST_HEAD_INIT(tsk.run_list),			\
+    next_task:		&tsk,						\
+    prev_task:		&tsk,						\
+    p_opptr:		&tsk,						\
+    p_pptr:		&tsk,						\
+    wait_chldexit:	__WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
+    real_timer:		{						\
+	function:		it_real_fn				\
+    },									\
+    cap_effective:	CAP_INIT_EFF_SET,				\
+    cap_inheritable:	CAP_INIT_INH_SET,				\
+    cap_permitted:	CAP_FULL_SET,					\
+    rlim:		INIT_RLIMITS,					\
+    comm:		"swapper",					\
+    thread:		INIT_THREAD,					\
+    fs:			&init_fs,					\
+    files:		&init_files,					\
+    sigmask_lock:	SPIN_LOCK_UNLOCKED,				\
+    sig:		&init_signals,					\
+    signal:		{{0}},						\
+    blocked:		{{0}},						\
+    sigqueue:		NULL,						\
+    sigqueue_tail:	&tsk.sigqueue,					\
+    exit_sem:		__MUTEX_INITIALIZER(tsk.exit_sem)		\
 }
+
 
 #ifndef INIT_TASK_SIZE
 # define INIT_TASK_SIZE	2048*sizeof(long)
diff -u --recursive --new-file v2.3.46/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.3.46/linux/include/linux/skbuff.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/skbuff.h	Sun Feb 20 20:48:33 2000
@@ -96,7 +96,6 @@
 	unsigned char	is_clone,		/* We are a clone				*/
 			cloned, 		/* head may be cloned (check refcnt to be sure). */
   			pkt_type,		/* Packet class					*/
-  			pkt_bridged,		/* Tracker for bridging 			*/
   			ip_summed;		/* Driver fed us an IP checksum			*/
 	__u32		priority;		/* Packet queueing priority			*/
 	atomic_t	users;			/* User count - see datagram.c,tcp.c 		*/
diff -u --recursive --new-file v2.3.46/linux/include/linux/spinlock.h linux/include/linux/spinlock.h
--- v2.3.46/linux/include/linux/spinlock.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/spinlock.h	Sun Feb 20 20:47:38 2000
@@ -41,9 +41,9 @@
 /*
  * Your basic spinlocks, allowing only a single CPU anywhere
  *
- * Gcc-2.7.x has a nasty bug with empty initializers.
+ * Most gcc versions have a nasty bug with empty initializers.
  */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+#if (__GNUC__ > 2)
   typedef struct { } spinlock_t;
   #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
 #else
@@ -104,9 +104,9 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  *
- * Gcc-2.7.x has a nasty bug with empty initializers.
+ * Most gcc versions have a nasty bug with empty initializers.
  */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+#if (__GNUC__ > 2)
   typedef struct { } rwlock_t;
   #define RW_LOCK_UNLOCKED (rwlock_t) { }
 #else
diff -u --recursive --new-file v2.3.46/linux/include/linux/sunrpc/xdr.h linux/include/linux/sunrpc/xdr.h
--- v2.3.46/linux/include/linux/sunrpc/xdr.h	Sun Dec 27 22:18:30 1998
+++ linux/include/linux/sunrpc/xdr.h	Sun Feb 20 20:48:08 2000
@@ -1,7 +1,7 @@
 /*
  * include/linux/sunrpc/xdr.h
  *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  */
 
 #ifndef _SUNRPC_XDR_H_
@@ -64,6 +64,25 @@
 u32 *	xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
 u32 *	xdr_decode_netobj(u32 *p, struct xdr_netobj *);
 u32 *	xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len);
+
+/*
+ * Decode 64bit quantities (NFSv3 support)
+ */
+static inline u32 *
+xdr_encode_hyper(u32 *p, __u64 val)
+{
+	*p++ = htonl(val >> 32);
+	*p++ = htonl(val & 0xFFFFFFFF);
+	return p;
+}
+
+static inline u32 *
+xdr_decode_hyper(u32 *p, __u64 *valp)
+{
+	*valp  = ((__u64) ntohl(*p++)) << 32;
+	*valp |= ntohl(*p++);
+	return p;
+}
 
 /*
  * Adjust iovec to reflect end of xdr'ed data (RPC client XDR)
diff -u --recursive --new-file v2.3.46/linux/include/net/br.h linux/include/net/br.h
--- v2.3.46/linux/include/net/br.h	Tue Jan  4 13:57:21 2000
+++ linux/include/net/br.h	Wed Dec 31 16:00:00 1969
@@ -1,330 +0,0 @@
-#include <linux/config.h>
-/*
- * Constants and structure definitions for the bridging code
- */
-
-#if !defined(One)
-#define Zero    0
-#define One	1
-#endif  /* !defined(One) */
-
-#if !defined(TRUE)
-#define FALSE   0
-#define TRUE	1
-#endif /* !defined(TRUE) */
-
-/** port states. **/
-#define Disabled	0			  /* (4.4 5)	 */
-#define Listening	1			  /* (4.4.2)	 */
-#define Learning	2			  /* (4.4.3)	 */
-#define Forwarding	3			  /* (4 4 4)	 */
-#define Blocking	4			  /* (4.4.1)	 */
-
-
-/* MAG Yich! Easiest way of giving a configurable number of ports
- * If you want more than 32, change BR_MAX_PORTS and recompile brcfg!
- */
-#define BR_MAX_PORTS (32)
-#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS
-#undef CONFIG_BRIDGE_NUM_PORTS
-#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS
-#endif
-#define No_of_ports CONFIG_BRIDGE_NUM_PORTS
-/* arbitrary choice, to allow the code below to compile */
-
-#define All_ports (No_of_ports + 1)
-
-/*
- * We time out our entries in the FDB after this many seconds.
- */
-#define FDB_TIMEOUT	20 /* JRP: 20s as NSC bridge code, was 300 for Linux */
-
-/*
- * the following defines are the initial values used when the 
- * bridge is booted.  These may be overridden when this bridge is
- * not the root bridge.  These are the recommended default values 
- * from the 802.1d specification.
- */
-#define BRIDGE_MAX_AGE		20
-#define BRIDGE_HELLO_TIME	2
-#define BRIDGE_FORWARD_DELAY	15
-#define HOLD_TIME		1
-
-/* broacast/multicast storm limitation. This per source. */
-#define MAX_MCAST_PER_PERIOD    4
-#define MCAST_HOLD_TIME		(10*HZ/100)
-
-#define Default_path_cost 10
-
-/*
- * minimum increment possible to avoid underestimating age, allows for BPDU
- * transmission time
- */
-#define Message_age_increment 1
-
-#define No_port 0
-/*
- * reserved value for Bridge's root port parameter indicating no root port,
- * used when Bridge is the root - also used to indicate the source when
- * a frame is being generated by a higher layer protocol on this host
- */
-
-/** Configuration BPDU Parameters (4.5.1) **/
-
-typedef struct {
-	union {
-		struct {
-			unsigned short priority;
-			unsigned char ula[6];
-		} p_u;
-		unsigned int id[2];
-	} bi;
-} bridge_id_t;
-
-#define BRIDGE_PRIORITY	bi.p_u.priority
-#define BRIDGE_ID_ULA	bi.p_u.ula
-#define BRIDGE_ID	bi.id
-
-/* JRP: on the network the flags field is between "type" and "root_id"
- * this is unfortunated! To make the code portable to a RISC machine
- * the pdus are now massaged a little bit for processing
- */ 
-#define TOPOLOGY_CHANGE		0x01
-#define TOPOLOGY_CHANGE_ACK	0x80
-#define BRIDGE_BPDU_8021_CONFIG_SIZE            35	/* real size */
-#define BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET	 4
-#define BRIDGE_BPDU_8021_PROTOCOL_ID 0
-#define BRIDGE_BPDU_8021_PROTOCOL_VERSION_ID 0
-#define BRIDGE_LLC1_HS 3
-#define BRIDGE_LLC1_DSAP 0x42
-#define BRIDGE_LLC1_SSAP 0x42
-#define BRIDGE_LLC1_CTRL 0x03
-
-typedef struct {
-	unsigned short	protocol_id;	
-	unsigned char	protocol_version_id;
-	unsigned char   type;
-	bridge_id_t      root_id;		  /* (4.5.1.1)	 */
-	unsigned int     root_path_cost;	  /* (4.5.1.2)	 */
-	bridge_id_t      bridge_id;		  /* (4.5.1.3)	 */
-	unsigned short   port_id;		  /* (4.5.1.4)	 */
-	unsigned short   message_age;		  /* (4.5.1.5)	 */
-	unsigned short   max_age;		  /* (4.5.1.6)	 */
-	unsigned short   hello_time;		  /* (4.5.1.7)	 */
-	unsigned short   forward_delay;		  /* (4.5.1.8)	 */
-	unsigned char   top_change_ack;
-	unsigned char   top_change;
-} Config_bpdu;
-
-#ifdef __LITTLE_ENDIAN
-#define config_bpdu_hton(config_bpdu) \
-        (config_bpdu)->root_path_cost = htonl((config_bpdu)->root_path_cost); \
-        (config_bpdu)->port_id = htons((config_bpdu)->port_id); \
-        (config_bpdu)->message_age = htons((config_bpdu)->message_age); \
-        (config_bpdu)->max_age = htons((config_bpdu)->max_age); \
-        (config_bpdu)->hello_time = htons((config_bpdu)->hello_time); \
-        (config_bpdu)->forward_delay = htons((config_bpdu)->forward_delay);
-#else
-#define config_bpdu_hton(config_bpdu)
-#endif
-#define config_bpdu_ntoh config_bpdu_hton
-
-
-/** Topology Change Notification BPDU Parameters (4.5.2) **/
-
-typedef struct {
-	unsigned short	protocol_id;	
-	unsigned char	protocol_version_id;
-	unsigned char   type;
-} Tcn_bpdu;
-
-#define BPDU_TYPE_CONFIG	0
-#define BPDU_TYPE_TOPO_CHANGE	128
-
-/** Bridge Parameters (4.5.3) **/
-typedef struct {
-	bridge_id_t      designated_root;	  /* (4.5.3.1)	 */
-	unsigned int     root_path_cost;	  /* (4.5.3.2)	 */
-	unsigned int 	 root_port;		  /* (4.5.3.3)	 */
-	unsigned short   max_age;		  /* (4.5.3.4)	 */
-	unsigned short   hello_time;		  /* (4.5.3.5)	 */
-	unsigned short   forward_delay;		  /* (4.5.3.6)	 */
-	bridge_id_t      bridge_id;		  /* (4.5.3.7)	 */
-	unsigned short   bridge_max_age;	  /* (4.5.3.8)	 */
-	unsigned short   bridge_hello_time;	  /* (4.5.3.9)	 */
-	unsigned short   bridge_forward_delay;	  /* (4.5.3.10)	 */
-	unsigned int     top_change_detected;	  /* (4.5.3.11) */
-	unsigned int     top_change;		  /* (4.5.3.12)	 */
-	unsigned short   topology_change_time;	  /* (4.5.3.13)	 */
-	unsigned short   hold_time;		  /* (4.5.3.14)	 */
-	unsigned int	 instance;
-} Bridge_data;
-
-/** Port Parameters (4.5.5) **/
-typedef struct {
-	unsigned short   port_id;		  /* (4.5.5.1)	 */
-	unsigned int     state;			  /* (4.5.5.2)	 */
-	unsigned int     path_cost;		  /* (4.5.5.3)	 */
-	bridge_id_t      designated_root;	  /* (4.5.5.4)	 */
-	unsigned int     designated_cost;	  /* (4.5.5.5)	 */
-	bridge_id_t      designated_bridge;	  /* (4.5.5.6)	 */
-	unsigned short   designated_port;	  /* (4.5.5.7)	 */
-	unsigned int     top_change_ack;	  /* (4.5.5.8)	 */
-	unsigned int     config_pending;	  /* (4.5.5.9)	 */
-        bridge_id_t      ifmac; 
-        char             ifname[IFNAMSIZ]; /* Make life easier for brcfg */
-        struct net_device *dev;	
-	struct fdb *fdb;	/* head of per port fdb chain */
-} Port_data;
-
-
-
-/** types to support timers for this pseudo-implementation. **/
-typedef struct {
-	unsigned int     active;			  /* timer in use. */
-	unsigned int     value;			  /* current value of timer,
-						   * counting up. */
-} Timer;
-
-struct fdb {
-	unsigned char ula[6];
-	unsigned char pad[2];
-	unsigned short port;
-	unsigned int timer;
-	unsigned short flags;
-#define FDB_ENT_VALID	0x01
-	unsigned short mcast_count;
-	unsigned int   mcast_timer;		/* oldest xxxxxcast */
-	
-/* AVL tree of all addresses, sorted by address */
-	short fdb_avl_height;
-	struct fdb *fdb_avl_left;
-	struct fdb *fdb_avl_right;
-/* linked list of addresses for each port */
-	struct fdb *fdb_next;
-};
-
-/* data returned on BRCMD_DISPLAY_FDB */
-struct fdb_info {
-	unsigned char ula[6];
-	unsigned char port;
-        unsigned char flags;
-        unsigned int timer;
-};
-struct fdb_info_hdr {
-	int	copied;			/* nb of entries copied to user */
-	int	not_copied;		/* when user buffer is too small */
-	int	cmd_time;
-};	
-
-#define IS_BRIDGED	0x2e
-
-
-#define BR_MAX_PROTOCOLS 32
-#define BR_MAX_PROT_STATS BR_MAX_PROTOCOLS
-
-/* policy values for policy field */
-#define BR_ACCEPT 1
-#define BR_REJECT 0
-
-/* JRP: extra statistics for debug */
-typedef struct {
-	/* br_receive_frame counters */
-	int port_disable_up_stack;
-	int rcv_bpdu;
-	int notForwarding;
-	int forwarding_up_stack;
-	int unknown_state;
-
-	/* br_tx_frame counters */
-	int port_disable;
-	int port_not_disable;
-
-	/* br_forward counters */
-	int local_multicast;
-	int forwarded_multicast;	/* up stack as well */
-	int flood_unicast;
-	int aged_flood_unicast;
-	int forwarded_unicast;
-	int forwarded_unicast_up_stack;
-	int forwarded_ip_up_stack;
-	int forwarded_ip_up_stack_lie;	/* received on alternate device */
-	int arp_for_local_mac;
-	int drop_same_port;
-	int drop_same_port_aged;
-	int drop_multicast;
-} br_stats_counter;
-
-struct br_stat {
-	unsigned int flags;
-	Bridge_data bridge_data;
-	unsigned int policy;
-	unsigned int exempt_protocols;
-	unsigned short protocols[BR_MAX_PROTOCOLS];
-	unsigned short prot_id[BR_MAX_PROT_STATS];	/* Protocol encountered */
-	unsigned int prot_counter[BR_MAX_PROT_STATS];	/* How many packets ? */
-	br_stats_counter packet_cnts;
-	unsigned int	num_ports;
-	Port_data port_data[BR_MAX_PORTS + 1];
-};
-
-/* defined flags for br_stat.flags */
-#define BR_UP		0x0001	/* bridging enabled */
-#define BR_DEBUG	0x0002	/* debugging enabled */
-#define BR_PROT_STATS	0x0004	/* protocol statistics enabled */
-#define BR_STP_DISABLED	0x0008	/* Spanning tree protocol disabled */
-
-struct br_cf {
-	unsigned int cmd;
-	unsigned int arg1;
-	unsigned int arg2;
-};
-
-/* defined cmds */
-#define	BRCMD_BRIDGE_ENABLE	1
-#define	BRCMD_BRIDGE_DISABLE	2
-#define	BRCMD_PORT_ENABLE	3	/* arg1 = port */
-#define	BRCMD_PORT_DISABLE	4	/* arg1 = port */
-#define	BRCMD_SET_BRIDGE_PRIORITY	5	/* arg1 = priority */
-#define	BRCMD_SET_PORT_PRIORITY	6	/* arg1 = port, arg2 = priority */
-#define	BRCMD_SET_PATH_COST	7	/* arg1 = port, arg2 = cost */
-#define	BRCMD_DISPLAY_FDB	8
-#define	BRCMD_ENABLE_DEBUG	9
-#define	BRCMD_DISABLE_DEBUG	10
-#define BRCMD_SET_POLICY	11	/* arg1 = default policy (1==bridge all) */
-#define BRCMD_EXEMPT_PROTOCOL	12	/* arg1 = protocol (see net/if_ether.h) */
-#define BRCMD_ENABLE_PROT_STATS	13
-#define BRCMD_DISABLE_PROT_STATS 14
-#define BRCMD_ZERO_PROT_STATS	15
-#define BRCMD_TOGGLE_STP	16
-#define BRCMD_IF_ENABLE		17	/* arg1 = if_index */
-#define BRCMD_IF_DISABLE	18	/* arg1 = if_index */
-#define BRCMD_SET_IF_PRIORITY	19	/* arg1 = if_index, arg2 = priority */
-#define	BRCMD_SET_IF_PATH_COST	20	/* arg1 = if_index, arg2 = cost */
-
-/* prototypes of exported bridging functions... */
-
-#ifdef __KERNEL__
-void br_init(void);
-int br_receive_frame(struct sk_buff *skb);	/* 3.5 */
-int br_tx_frame(struct sk_buff *skb);
-int brg_init(void);
-int br_ioctl(unsigned int cmd, void *arg);
-void requeue_fdb(struct fdb *node, int new_port);
-
-struct fdb *br_avl_find_addr(unsigned char addr[6]);
-struct fdb *br_avl_insert (struct fdb * new_node);
-void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length);
-void br_avl_delete_by_port(int port);
-int br_call_bridge(struct sk_buff *skb, unsigned short type);
-void br_spacedevice_register(void);
-
-/* externs */
-
-extern struct br_stat br_stats;
-extern Port_data port_info[];
-
-#endif
-
-
- 
diff -u --recursive --new-file v2.3.46/linux/include/net/pkt_sched.h linux/include/net/pkt_sched.h
--- v2.3.46/linux/include/net/pkt_sched.h	Thu Feb 10 17:11:23 2000
+++ linux/include/net/pkt_sched.h	Sun Feb 20 20:49:03 2000
@@ -7,9 +7,14 @@
 
 #define PSCHED_CLOCK_SOURCE	PSCHED_JIFFIES
 
+#include <linux/config.h>
 #include <linux/pkt_sched.h>
 #include <net/pkt_cls.h>
 
+#ifdef CONFIG_X86_TSC
+#include <asm/msr.h>
+#endif
+
 struct rtattr;
 struct Qdisc;
 
@@ -247,11 +252,11 @@
 
 #define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz)
 
-#if CPU == 586 || CPU == 686
+#ifdef CONFIG_X86_TSC
 
 #define PSCHED_GET_TIME(stamp) \
 ({ u64 __cur; \
-   __asm__ __volatile__ (".byte 0x0f,0x31" :"=A" (__cur)); \
+   rdtscll(__cur); \
    (stamp) = __cur>>psched_clock_scale; \
 })
 
@@ -430,7 +435,7 @@
 
 extern __inline__ void qdisc_run(struct net_device *dev)
 {
-	while (!test_bit(LINK_STATE_XOFF, &dev->state) &&
+	while (!netif_queue_stopped(dev) &&
 	       qdisc_restart(dev)<0)
 		/* NOTHING */;
 }
diff -u --recursive --new-file v2.3.46/linux/include/net/profile.h linux/include/net/profile.h
--- v2.3.46/linux/include/net/profile.h	Wed Aug 18 16:43:31 1999
+++ linux/include/net/profile.h	Sun Feb 20 20:47:38 2000
@@ -9,6 +9,10 @@
 #include <linux/kernel.h>
 #include <asm/system.h>
 
+#ifdef CONFIG_X86_TSC
+#include <asm/msr.h>
+#endif
+
 struct net_profile_slot
 {
 	char   id[16];
@@ -25,14 +29,11 @@
 extern struct timeval net_profile_adjust;
 extern void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved);
 
-#if CPU == 586 || CPU == 686
-
+#ifdef CONFIG_X86_TSC
 
 extern __inline__ void  net_profile_stamp(struct timeval *pstamp)
 {
-	__asm__ __volatile__ (".byte 0x0f,0x31"
-		:"=a" (pstamp->tv_usec),
-		"=d" (pstamp->tv_sec));
+	rdtsc(pstamp->tv_usec, pstamp->tv_sec);
 }
 
 extern __inline__ void  net_profile_accumulate(struct timeval *entered,
diff -u --recursive --new-file v2.3.46/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.46/linux/kernel/ksyms.c	Wed Feb 16 17:03:52 2000
+++ linux/kernel/ksyms.c	Sun Feb 20 20:37:09 2000
@@ -376,6 +376,7 @@
 EXPORT_SYMBOL(loops_per_sec);
 #endif
 EXPORT_SYMBOL(kstat);
+EXPORT_SYMBOL(nr_running);
 
 /* misc */
 EXPORT_SYMBOL(panic);
@@ -461,6 +462,7 @@
 
 /* library functions */
 EXPORT_SYMBOL(strnicmp);
+EXPORT_SYMBOL(strspn);
 
 /* software interrupts */
 EXPORT_SYMBOL(tasklet_hi_vec);
@@ -468,6 +470,8 @@
 EXPORT_SYMBOL(bh_task_vec);
 EXPORT_SYMBOL(init_bh);
 EXPORT_SYMBOL(remove_bh);
+EXPORT_SYMBOL(tasklet_init);
+EXPORT_SYMBOL(tasklet_kill);
 
 /* init task, for moving kthread roots - ought to export a function ?? */
 
diff -u --recursive --new-file v2.3.46/linux/kernel/pm.c linux/kernel/pm.c
--- v2.3.46/linux/kernel/pm.c	Thu Feb 10 17:11:23 2000
+++ linux/kernel/pm.c	Sun Feb 20 20:37:09 2000
@@ -168,3 +168,4 @@
 EXPORT_SYMBOL(pm_unregister_all);
 EXPORT_SYMBOL(pm_send_request);
 EXPORT_SYMBOL(pm_find);
+EXPORT_SYMBOL(pm_active);
diff -u --recursive --new-file v2.3.46/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.46/linux/kernel/sched.c	Thu Feb 10 17:11:23 2000
+++ linux/kernel/sched.c	Sun Feb 20 20:26:10 2000
@@ -141,7 +141,7 @@
 #endif
 
 	/* .. and a slight advantage to the current MM */
-	if (p->mm == this_mm)
+	if (p->mm == this_mm || !p->mm)
 		weight += 1;
 	weight += p->priority;
 
@@ -173,7 +173,7 @@
  */
 static inline int preemption_goodness(struct task_struct * prev, struct task_struct * p, int cpu)
 {
-	return goodness(p, cpu, prev->mm) - goodness(prev, cpu, prev->mm);
+	return goodness(p, cpu, prev->active_mm) - goodness(prev, cpu, prev->active_mm);
 }
 
 /*
diff -u --recursive --new-file v2.3.46/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.46/linux/mm/filemap.c	Wed Feb 16 17:03:52 2000
+++ linux/mm/filemap.c	Wed Feb 16 20:23:47 2000
@@ -1945,8 +1945,6 @@
 			count -= status;
 			pos += status;
 			buf += status;
-			if (pos > inode->i_size)
-				inode->i_size = pos;
 		}
 unlock:
 		/* Mark it unlocked again and drop the page.. */
diff -u --recursive --new-file v2.3.46/linux/mm/memory.c linux/mm/memory.c
--- v2.3.46/linux/mm/memory.c	Sun Feb 13 19:29:04 2000
+++ linux/mm/memory.c	Wed Feb 16 20:23:47 2000
@@ -862,6 +862,7 @@
 	struct vm_area_struct * mpnt;
 	struct address_space *mapping = inode->i_mapping;
 
+	inode->i_size = offset;
 	truncate_inode_pages(mapping, offset);
 	spin_lock(&mapping->i_shared_lock);
 	if (!mapping->i_mmap)
diff -u --recursive --new-file v2.3.46/linux/mm/mremap.c linux/mm/mremap.c
--- v2.3.46/linux/mm/mremap.c	Wed Feb 16 17:03:52 2000
+++ linux/mm/mremap.c	Sun Feb 20 20:25:19 2000
@@ -275,7 +275,7 @@
 	ret = -ENOMEM;
 	if (flags & MREMAP_MAYMOVE) {
 		if (!(flags & MREMAP_FIXED)) {
-			new_addr = get_unmapped_area(addr, new_len);
+			new_addr = get_unmapped_area(0, new_len);
 			if (!new_addr)
 				goto out;
 		}
diff -u --recursive --new-file v2.3.46/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.46/linux/mm/page_alloc.c	Sat Feb 12 11:22:11 2000
+++ linux/mm/page_alloc.c	Sun Feb 20 20:25:19 2000
@@ -258,7 +258,9 @@
 		 */
 		if (!(current->flags & PF_MEMALLOC))
 		{
-			if (classfree(z) > z->pages_high)
+			unsigned long free = classfree(z);
+
+			if (free > z->pages_high)
 			{
 				if (z->low_on_memory)
 					z->low_on_memory = 0;
@@ -270,11 +272,11 @@
 				if (z->low_on_memory)
 					goto balance;
 
-				if (classfree(z) <= z->pages_low)
+				if (free <= z->pages_low)
 				{
 					wake_up_interruptible(&kswapd_wait);
 
-					if (classfree(z) <= z->pages_min)
+					if (free <= z->pages_min)
 					{
 						z->low_on_memory = 1;
 						goto balance;
@@ -296,16 +298,6 @@
 			if (page)
 				return page;
 		}
-	}
-
-	/*
-	 * If we can schedule, do so, and make sure to yield.
-	 * We may be a real-time process, and if kswapd is
-	 * waiting for us we need to allow it to run a bit.
-	 */
-	if (gfp_mask & __GFP_WAIT) {
-		current->policy |= SCHED_YIELD;
-		schedule();
 	}
 
 nopage:
diff -u --recursive --new-file v2.3.46/linux/net/Changes linux/net/Changes
--- v2.3.46/linux/net/Changes	Sun Jun  7 10:37:42 1998
+++ linux/net/Changes	Fri Feb 18 14:51:22 2000
@@ -6,7 +6,6 @@
 
 o	Should unix domain connect never block ?
 o	Screend loadable firewall module
-o	Fix merging the bridge code
 o	Remove kernel RARP and replace with user mode daemon.
 o	Merge ARM half word trap fixes for ethernet headers
 o	Stop route addition to downed interfaces
diff -u --recursive --new-file v2.3.46/linux/net/Config.in linux/net/Config.in
--- v2.3.46/linux/net/Config.in	Wed Dec 29 13:13:21 1999
+++ linux/net/Config.in	Fri Feb 18 14:51:22 2000
@@ -61,11 +61,8 @@
    fi
    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
-   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
-   if [ "$CONFIG_BRIDGE" != "n" ]; then
-       int '  Maximum number of bridged interfaces' CONFIG_BRIDGE_NUM_PORTS 8
-   fi
-bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
+   tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
+   bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
 #   if [ "$CONFIG_LLC" = "y" ]; then
 #      bool '  Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
 #   fi
diff -u --recursive --new-file v2.3.46/linux/net/Makefile linux/net/Makefile
--- v2.3.46/linux/net/Makefile	Thu Aug 26 13:05:42 1999
+++ linux/net/Makefile	Fri Feb 18 14:51:22 2000
@@ -67,6 +67,10 @@
 
 ifeq ($(CONFIG_BRIDGE),y)
 SUB_DIRS += bridge
+else
+  ifeq ($(CONFIG_BRIDGE),m)
+    MOD_SUB_DIRS += bridge
+  endif
 endif
 
 ifeq ($(CONFIG_IPX),y)
diff -u --recursive --new-file v2.3.46/linux/net/README linux/net/README
--- v2.3.46/linux/net/README	Fri Jan  7 19:13:23 2000
+++ linux/net/README	Fri Feb 18 14:51:22 2000
@@ -7,6 +7,7 @@
     [token ring	]	p.norton@computer.org
 appletalk		jschlst@turbolinux.com
 ax25			g4klx@g4klx.demon.co.uk
+bridge			buytenh@openrock.net
 core			alan@lxorguk.ukuu.org.uk
 decnet			SteveW@ACM.org
 ethernet		alan@lxorguk.ukuu.org.uk
diff -u --recursive --new-file v2.3.46/linux/net/bridge/Makefile linux/net/bridge/Makefile
--- v2.3.46/linux/net/bridge/Makefile	Tue Apr 28 11:10:10 1998
+++ linux/net/bridge/Makefile	Fri Feb 18 14:51:22 2000
@@ -1,5 +1,5 @@
 #
-# Makefile for the Linux Bridge layer.
+# Makefile for the IEEE 802.1d ethernet bridging layer.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
@@ -7,15 +7,10 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-O_TARGET := bridge.o
-O_OBJS	 := br.o br_tree.o
-M_OBJS   := $(O_TARGET)
-
-ifeq ($(CONFIG_SYSCTL),y)
-O_OBJS += sysctl_net_bridge.o
-endif
+O_TARGET	:= bridge.o
+O_OBJS		:= br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
+			br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
+			br_stp_if.o br_stp_timer.o
+M_OBJS		:= $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
-
-tar:
-		tar -cvf /dev/f1 .
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.3.46/linux/net/bridge/br.c	Tue Jan  4 13:57:21 2000
+++ linux/net/bridge/br.c	Fri Feb 18 14:51:22 2000
@@ -1,2740 +1,67 @@
 /*
- *	Linux NET3 Bridge Support
+ *	Generic parts
+ *	Linux ethernet bridge
  *
- *	Originally by John Hayes (Network Plumbing).
- *	Minor hacks to get it to run with 1.3.x by Alan Cox <Alan.Cox@linux.org>
- *	More hacks to be able to switch protocols on and off by Christoph Lameter
- *	<clameter@debian.org>
- *	Software and more Documentation for the bridge is available from ftp.debian.org
- *	in the bridgex package
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br.c,v 1.39 2000/02/18 16:47:11 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
- *
- * Fixes:
- *	Yury Shevchuk	:	Bridge with non bridging ports
- *	Jean-Rene Peulve: jr.peulve@aix.pacwan.net 		Jan/Feb 98
- *			support Linux 2.0
- *			Handle Receive config bpdu
- *			kick mark_bh to send Spanning Tree pdus
- *			bridgeId comparison using htonl()
- *			make STP interoperable with other vendors
- *			wrong test in root_selection()
- *			add more STP debug info 
- *			some performance improvments
- *			do not clear bridgeId.mac  while setting priority
- *			do not reset port priority when starting bridge
- *			make port priority from user value and port number
- *			maintains user port state out of device state
- *			broacast/multicast storm limitation
- *			forwarding statistics
- *			stop br_tick when bridge is turn off
- *			add local MACs in avl_tree to forward up stack
- *			fake receive on right port for IP/ARP 
- *			ages tree even if packet does not cross bridge
- *			add BRCMD_DISPLAY_FDB (ioctl for now)
- *
- *	Alan Cox:	Merged Jean-Rene's stuff, reformatted stuff a bit
- *			so blame me first if its broken ;)
- *
- *	Robert Pintarelli:	fixed bug in bpdu time values
- *
- *      Matthew Grant:  start ports disabled.  
- *                      auto-promiscuous mode on port enable/disable
- *                      fleshed out interface event handling, interfaces 
- *                        now register with bridge on module load as well as ifup
- *                      port control ioctls with ifindex support
- *                      brg0 logical ethernet interface
- *                      reworked brcfg to take interface arguments
- *                      added support for changing the hardware address
- *                      generally made bridge a lot more usable.
- *	
- *	Todo:
- *	Use a netlink notifier so a daemon can maintain the bridge
- *	port group (could we also do multiple groups ????).
- *		A nice /proc file interface.
- *		Put the path costs in the port info and devices.
- *		Put the bridge port number in the device structure for speed.
- *		Bridge SNMP stats.
- *	
  */
- 
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
 
+#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/net.h>
-#include <linux/inet.h>
+#include <linux/miscdevice.h>
 #include <linux/netdevice.h>
-#include <linux/inetdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <linux/version.h>
 #include <linux/init.h>
+#include <linux/if_bridge.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/rtnetlink.h>
-#include <net/br.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-
-#ifndef min
-#define min(a, b) (((a) <= (b)) ? (a) : (b))
-#endif
-
-static void transmit_config(int port_no);
-static int root_bridge(void);
-static int supersedes_port_info(int port_no, Config_bpdu *config);
-static void record_config_information(int port_no, Config_bpdu *config);
-static void record_config_timeout_values(Config_bpdu *config);
-static void config_bpdu_generation(void);
-static int designated_port(int port_no);
-static void reply(int port_no);
-static void transmit_tcn(void);
-static void configuration_update(void);
-static void root_selection(void);
-static void designated_port_selection(void);
-static void become_designated_port(int port_no);
-static void port_state_selection(void);
-static void make_forwarding(int port_no);
-static void topology_change_detection(void);
-static void topology_change_acknowledged(void);
-static void acknowledge_topology_change(int port_no);
-static void make_blocking(int port_no);
-static void set_port_state(int port_no, int state);
-static void received_config_bpdu(int port_no, Config_bpdu *config);
-static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn);
-static void hello_timer_expiry(void);
-static void message_age_timer_expiry(int port_no);
-static void forward_delay_timer_expiry(int port_no);
-static int designated_for_some_port(void);
-static void tcn_timer_expiry(void);
-static void topology_change_timer_expiry(void);
-static void hold_timer_expiry(int port_no);
-static void br_init_port(int port_no);
-static void enable_port(int port_no);
-static void disable_port(int port_no);
-static void set_bridge_priority(bridge_id_t *new_bridge_id);
-static void set_port_priority(int port_no);
-static void set_path_cost(int port_no, unsigned short path_cost);
-static void start_hello_timer(void);
-static void stop_hello_timer(void);
-static int hello_timer_expired(void);
-static void start_tcn_timer(void);
-static void stop_tcn_timer(void);
-static int tcn_timer_expired(void);
-static void start_topology_change_timer(void);
-static void stop_topology_change_timer(void);
-static int topology_change_timer_expired(void);
-static void start_message_age_timer(int port_no, unsigned short message_age);
-static void stop_message_age_timer(int port_no);
-static int message_age_timer_expired(int port_no);
-static void start_forward_delay_timer(int port_no);
-static void stop_forward_delay_timer(int port_no);
-static int forward_delay_timer_expired(int port_no);
-static void start_hold_timer(int port_no);
-static void stop_hold_timer(int port_no);
-static int hold_timer_expired(int port_no);
-static int br_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
-static void br_tick(unsigned long arg);
-static int br_forward(struct sk_buff *skb, int port);	/* 3.7 */
-static int br_port_cost(struct net_device *dev);	/* 4.10.2 */
-static void br_bpdu(struct sk_buff *skb, int port); /* consumes skb */
-static int br_cmp(unsigned int *a, unsigned int *b);
-static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu);
-static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu);
-static int find_port(struct net_device *dev);
-static void br_add_local_mac(unsigned char *mac);
-static int br_flood(struct sk_buff *skb, int port);
-static int br_drop(struct sk_buff *skb);
-static int br_learn(struct sk_buff *skb, int port);	/* 3.8 */
-static int br_protocol_ok(unsigned short protocol);
-static int br_find_port(int ifindex);
-static void br_get_ifnames(void);
-static int brg_rx(struct sk_buff *skb, int port);
-
-static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
-static Bridge_data     bridge_info;			  /* (4.5.3)	 */
-Port_data       port_info[All_ports];		  /* (4.5.5)	 */
-
-/* MAG: Maximum port registered - used to speed up flooding and to make
- * have a large ports array more efficient
- */
-static int max_port_used = 0; 
-
-/* JRP: fdb cache 1/port save kmalloc/kfree on every frame */
-struct fdb	*newfdb[All_ports];
-int allocated_fdb_cnt = 0;
-
-/* broacast/multicast storm limitation */
-int max_mcast_per_period = MAX_MCAST_PER_PERIOD;
-int mcast_hold_time	 = MCAST_HOLD_TIME;
-
-/* JRP: next two bpdu are copied to skbuff so we need only 1 of each */
-static Config_bpdu	config_bpdu;
-static Tcn_bpdu		tcn_bpdu;
-static unsigned char	port_priority[All_ports];
-static unsigned char	user_port_state[All_ports];
-
-static Timer    hello_timer;			  /* (4.5.4.1)	 */
-static Timer    tcn_timer;			  /* (4.5.4.2)	 */
-static Timer    topology_change_timer;		  /* (4.5.4.3)	 */
-static Timer    message_age_timer[All_ports];	  /* (4.5.6.1)	 */
-static Timer    forward_delay_timer[All_ports];	  /* (4.5.6.2)	 */
-static Timer    hold_timer[All_ports];		  /* (4.5.6.3)	 */
-
-/* entries timeout after this many seconds */
-unsigned int fdb_aging_time = FDB_TIMEOUT; 
-
-struct br_stat br_stats;
-#define br_stats_cnt br_stats.packet_cnts
-
-static struct timer_list tl; /* for 1 second timer... */
-
-/*
- * the following structure is required so that we receive
- * event notifications when network devices are enabled and
- * disabled (ifconfig up and down).
- */
-static struct notifier_block br_dev_notifier={
-	br_device_event,
-	NULL,
-	0
-};
-
-
-/* 
- * the following data is for the bridge network device
- */
-struct brg_if {
-  struct net_device dev;
-  char name[IFNAMSIZ];
-};
-static struct brg_if brg_if;
-
-/* 
- * Here to save linkage? problems
- */
-
-static inline int find_port(struct net_device *dev)
-{
-	int i;
-
-	for (i = One; i <= No_of_ports; i++)
-		if (port_info[i].dev == dev)
-			return(i);
-	return(0);
-}
-
-/*
- * Implementation of Protocol specific bridging
- *
- * The protocols to be bridged or not to be bridged are stored in a hashed array. This is the old type
- * of unlinked hash array where one simply takes the next cell if the one the hash function points to
- * is occupied.
- */
-
-#define BR_PROTOCOL_HASH(x) (x % BR_MAX_PROTOCOLS)
-
-/* Checks if that protocol type is to be bridged */
-
-static int inline br_protocol_ok(unsigned short protocol)
-{
-	unsigned x;
-	
-	/* See if protocol statistics are to be kept */
-	if (br_stats.flags & BR_PROT_STATS)
-	{
-		for(x=0;x<BR_MAX_PROT_STATS && br_stats.prot_id[x]!=protocol && br_stats.prot_id[x];x++);
-		if (x<BR_MAX_PROT_STATS)
-		{
-			br_stats.prot_id[x]=protocol;br_stats.prot_counter[x]++;
-		}
-	}
-
-	for (x=BR_PROTOCOL_HASH(protocol); br_stats.protocols[x]!=0;) 
-	{
-		if (br_stats.protocols[x]==protocol)
-			return !br_stats.policy;
-		x++;
-		if (x==BR_MAX_PROTOCOLS)
-			x=0;
-	}
-	return br_stats.policy;
-}
-
-/* Add a protocol to be handled opposite to the standard policy of the bridge */
-
-static int br_add_exempt_protocol(unsigned short p)
-{
-	unsigned x;
-	if (p == 0) return -EINVAL;
-	if (br_stats.exempt_protocols > BR_MAX_PROTOCOLS-2) return -EXFULL;
-	for (x=BR_PROTOCOL_HASH(p);br_stats.protocols[x]!=0;) {
-		if (br_stats.protocols[x]==p) return 0;	/* Attempt to add the protocol a second time */
-		x++;
-		if (x==BR_MAX_PROTOCOLS) x=0;
-	}
-	br_stats.protocols[x]=p;
-	br_stats.exempt_protocols++;
-	return 0;
-}
-
-/* Valid Policies are 0=No Protocols bridged 1=Bridge all protocols */
-static int br_set_policy(int policy)
-{
-	if (policy>1) return -EINVAL;
-	br_stats.policy=policy;
-	/* Policy change means initializing the exempt table */
-	memset(br_stats.protocols,0,sizeof(br_stats.protocols));
-	br_stats.exempt_protocols = 0;
-	return 0;
-}
-
-
-/** Elements of Procedure (4.6) **/
-
-/*
- * this section of code was graciously borrowed from the IEEE 802.1d
- * specification section 4.9.1 starting on pg 69.  It has been
- * modified somewhat to fit within our framework and structure.  It
- * implements the spanning tree algorithm that is the heart of the
- * 802.1d bridging protocol.
- */
-
-static void transmit_config(int port_no)	  /* (4.6.1)	 */
-{
-	if (hold_timer[port_no].active) {	  /* (4.6.1.3.1)	 */
-		port_info[port_no].config_pending = TRUE;	/* (4.6.1.3.1)	 */
-	} else {				  /* (4.6.1.3.2)	 */
-		config_bpdu.type = BPDU_TYPE_CONFIG;
-		config_bpdu.root_id = bridge_info.designated_root;
-		/* (4.6.1.3.2(1)) */
-		config_bpdu.root_path_cost = bridge_info.root_path_cost;
-		/* (4.6.1.3.2(2)) */
-		config_bpdu.bridge_id = bridge_info.bridge_id;
-		/* (4.6.1.3.2(3)) */
-		config_bpdu.port_id = port_info[port_no].port_id;
-		/*
-		 * (4.6.1.3.2(4))
-		 */
-		if (root_bridge()) {
-			config_bpdu.message_age = Zero;	/* (4.6.1.3.2(5)) */
-		} else {
-			config_bpdu.message_age
-				= (message_age_timer[bridge_info.root_port].value
-				+ Message_age_increment) << 8;	/* (4.6.1.3.2(6)) */
-		}
-
-		config_bpdu.max_age = bridge_info.max_age << 8;/* (4.6.1.3.2(7)) */
-		config_bpdu.hello_time = bridge_info.hello_time << 8;
-		config_bpdu.forward_delay = bridge_info.forward_delay << 8;
-		config_bpdu.top_change_ack = 
-			port_info[port_no].top_change_ack;
-							/* (4.6.1.3.2(8)) */
-		port_info[port_no].top_change_ack = 0;
-
-		config_bpdu.top_change = 
-			bridge_info.top_change; 	/* (4.6.1.3.2(9)) */
-
-		send_config_bpdu(port_no, &config_bpdu);
-		port_info[port_no].config_pending = FALSE;	/* (4.6.1.3.2(10)) */
-		start_hold_timer(port_no);	  /* (4.6.1.3.2(11)) */
-	}
-/* JRP: we want the frame to be xmitted even if no other traffic.
- *	net_bh() will do a dev_transmit() that kicks all devices
- */
-	mark_bh(NET_BH);
-}
-
-static int root_bridge(void)
-{
-	return (br_cmp(bridge_info.designated_root.BRIDGE_ID,
-		 bridge_info.bridge_id.BRIDGE_ID)?FALSE:TRUE);
-}
-
-static int supersedes_port_info(int port_no, Config_bpdu *config)	  /* (4.6.2.2)	 */
-{
-	return (
-		(br_cmp(config->root_id.BRIDGE_ID,
-		 port_info[port_no].designated_root.BRIDGE_ID) < 0)	/* (4.6.2.2.1)	 */ 
-		||
-		((br_cmp(config->root_id.BRIDGE_ID,
-		  port_info[port_no].designated_root.BRIDGE_ID) == 0
-		  )
-		 &&
-		 ((config->root_path_cost
-		   < port_info[port_no].designated_cost	/* (4.6.2.2.2)	 */
-		   )
-		  ||
-		  ((config->root_path_cost
-		    == port_info[port_no].designated_cost
-		    )
-		   &&
-		   ((br_cmp(config->bridge_id.BRIDGE_ID,
-		     port_info[port_no].designated_bridge.BRIDGE_ID) < 0	/* (4.6.2.2.3)    */
-		     )
-		    ||
-		    ((br_cmp(config->bridge_id.BRIDGE_ID,
-		      port_info[port_no].designated_bridge.BRIDGE_ID) == 0
-		      )				  /* (4.6.2.2.4)	 */
-		     &&
-		     ((br_cmp(config->bridge_id.BRIDGE_ID,
-			bridge_info.bridge_id.BRIDGE_ID) != 0
-		       )			  /* (4.6.2.2.4(1)) */
-		      ||
-		      (config->port_id <=
-		       port_info[port_no].designated_port
-		       )			  /* (4.6.2.2.4(2)) */
-		      ))))))
-		);
-}
-
-static void record_config_information(int port_no, Config_bpdu *config)	  /* (4.6.2)	 */
-{
-	port_info[port_no].designated_root = config->root_id;	/* (4.6.2.3.1)   */
-	port_info[port_no].designated_cost = config->root_path_cost;
-	port_info[port_no].designated_bridge = config->bridge_id;
-	port_info[port_no].designated_port = config->port_id;
-	start_message_age_timer(port_no, config->message_age);	/* (4.6.2.3.2)   */
-}
-
-static void record_config_timeout_values(Config_bpdu *config)		  /* (4.6.3)	 */
-{
-	bridge_info.max_age = config->max_age >> 8;	  /* (4.6.3.3)	 */
-	bridge_info.hello_time = config->hello_time >> 8;
-	bridge_info.forward_delay = config->forward_delay >> 8;
-	bridge_info.top_change = config->top_change >> 8;
-}
-
-static void config_bpdu_generation(void)
-{						  /* (4.6.4)	 */
-	int             port_no;
-	for (port_no = One; port_no <= No_of_ports; port_no++) {	/* (4.6.4.3) */
-		if (designated_port(port_no)	  /* (4.6.4.3)	 */
-				&&
-				(port_info[port_no].state != Disabled)
-			) {
-			transmit_config(port_no); /* (4.6.4.3)	 */
-		}				  /* (4.6.1.2)	 */
-	}
-}
-
-static int designated_port(int port_no)
-{
-	return ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
-		 bridge_info.bridge_id.BRIDGE_ID) == 0
-		 )
-		&&
-		(port_info[port_no].designated_port
-		 == port_info[port_no].port_id
-		 )
-		);
-}
-
-static void reply(int port_no)					  /* (4.6.5)	 */
-{
-	transmit_config(port_no);		  /* (4.6.5.3)	 */
-}
-
-static void transmit_tcn(void)
-{						  /* (4.6.6)	 */
-	int             port_no;
-
-	port_no = bridge_info.root_port;
-	tcn_bpdu.type = BPDU_TYPE_TOPO_CHANGE;
-	send_tcn_bpdu(port_no, &tcn_bpdu);	/* (4.6.6.3)     */
-}
-
-static void configuration_update(void)	/* (4.6.7) */
-{
-	root_selection();			  /* (4.6.7.3.1)	 */
-	/* (4.6.8.2)	 */
-	designated_port_selection();		  /* (4.6.7.3.2)	 */
-	/* (4.6.9.2)	 */
-}
-
-static void root_selection(void)
-{						  /* (4.6.8) */
-	int             root_port;
-	int             port_no;
-	root_port = No_port;
-	for (port_no = One; port_no <= No_of_ports; port_no++) {	/* (4.6.8.3.1) */
-		if (((!designated_port(port_no))
-		     &&
-		     (port_info[port_no].state != Disabled)
-		     &&
-		(br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
-			bridge_info.bridge_id.BRIDGE_ID) < 0)
-			)
-				&&
-				((root_port == No_port)
-				 ||
-				 (br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
-				  port_info[root_port].designated_root.BRIDGE_ID) < 0
-				  )
-				 ||
-				 ((br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
-				   port_info[root_port].designated_root.BRIDGE_ID) == 0
-				   )
-				  &&
-				  (((port_info[port_no].designated_cost
-				     + port_info[port_no].path_cost
-				     )
-				    <
-				    (port_info[root_port].designated_cost
-				     + port_info[root_port].path_cost
-				     )		  /* (4.6.8.3.1(2)) */
-				    )
-				   ||
-				   (((port_info[port_no].designated_cost
-				      + port_info[port_no].path_cost
-				      )
-				     ==
-				     (port_info[root_port].designated_cost
-				      + port_info[root_port].path_cost
-				      )
-				     )
-				    &&
-				    ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
-				    port_info[root_port].designated_bridge.BRIDGE_ID) < 0
-				      )		  /* (4.6.8.3.1(3)) */
-				     ||
-				     ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
-				   port_info[root_port].designated_bridge.BRIDGE_ID) == 0
-				       )
-				      &&
-				      ((port_info[port_no].designated_port
-				      < port_info[root_port].designated_port
-					)	  /* (4.6.8.3.1(4)) */
-				       ||
-				       ((port_info[port_no].designated_port
-/* JRP: was missing an "=" ! */	      == port_info[root_port].designated_port
-					 )
-					&&
-					(port_info[port_no].port_id
-					 < port_info[root_port].port_id
-					 )	  /* (4.6.8.3.1(5)) */
-					))))))))) {
-			root_port = port_no;
-		}
-	}
-	bridge_info.root_port = root_port;	  /* (4.6.8.3.1)	 */
-
-	if (root_port == No_port) {		  /* (4.6.8.3.2)	 */
-#ifdef DEBUG_STP
-		if (br_stats.flags & BR_DEBUG)
-			printk(KERN_DEBUG "root_selection: becomes root\n");
-#endif
-		bridge_info.designated_root = bridge_info.bridge_id;
-		/* (4.6.8.3.2(1)) */
-		bridge_info.root_path_cost = Zero;/* (4.6.8.3.2(2)) */
-	} else {				  /* (4.6.8.3.3)	 */
-		bridge_info.designated_root = port_info[root_port].designated_root;
-		/* (4.6.8.3.3(1)) */
-		bridge_info.root_path_cost = (port_info[root_port].designated_cost
-					    + port_info[root_port].path_cost
-			);			  /* (4.6.8.3.3(2)) */
-	}
-}
-
-static void designated_port_selection(void)
-{						  /* (4.6.9)	 */
-	int             port_no;
-
-	for (port_no = One; port_no <= No_of_ports; port_no++) {	/* (4.6.9.3)	 */
-		if(port_info[port_no].state == Disabled)
-			continue;
-		if (designated_port(port_no)	  /* (4.6.9.3.1)	 */
-				||
-				(
-				 br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
-				 bridge_info.designated_root.BRIDGE_ID) != 0
-				 )
-				||
-				(bridge_info.root_path_cost
-				 < port_info[port_no].designated_cost
-				 )		  /* (4.6.9.3.3)	 */
-				||
-				((bridge_info.root_path_cost
-				  == port_info[port_no].designated_cost
-				  )
-				 &&
-				 ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
-				   port_info[port_no].designated_bridge.BRIDGE_ID) < 0
-				   )		  /* (4.6.9.3.4)	 */
-				  ||
-				  ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
-				    port_info[port_no].designated_bridge.BRIDGE_ID) == 0
-				    )
-				   &&
-				   (port_info[port_no].port_id
-				    <= port_info[port_no].designated_port
-				    )		  /* (4.6.9.3.5)	 */
-				   )))) {
-			become_designated_port(port_no);	/* (4.6.10.3.2.2) */
-		}
-	}
-}
-
-static void become_designated_port(int port_no)
-{						  /* (4.6.10)	 */
-
-	/* (4.6.10.3.1) */
-	port_info[port_no].designated_root = bridge_info.designated_root;
-	/* (4.6.10.3.2) */
-	port_info[port_no].designated_cost = bridge_info.root_path_cost;
-	/* (4.6.10.3.3) */
-	port_info[port_no].designated_bridge = bridge_info.bridge_id;
-	/* (4.6.10.3.4) */
-	port_info[port_no].designated_port = port_info[port_no].port_id;
-}
-
-static void port_state_selection(void)
-{						  /* (4.6.11) */
-	int             port_no;
-	char		*state_str;
-	for (port_no = One; port_no <= No_of_ports; port_no++) {
-
-		if(port_info[port_no].state == Disabled)
-			continue;
-		if (port_no == bridge_info.root_port) {	/* (4.6.11.3.1) */
-			state_str = "root";
-			port_info[port_no].config_pending = FALSE;	/* (4.6.11.3.1(1)) */
-			port_info[port_no].top_change_ack = 0;
-			make_forwarding(port_no); /* (4.6.11.3.1(2)) */
-		} else if (designated_port(port_no)) {	/* (4.6.11.3.2) */
-			state_str = "designated";
-			stop_message_age_timer(port_no);	/* (4.6.11.3.2(1)) */
-			make_forwarding(port_no); /* (4.6.11.3.2(2)) */
-		} else {			  /* (4.6.11.3.3) */
-			state_str = "blocking";
-			port_info[port_no].config_pending = FALSE;	/* (4.6.11.3.3(1)) */
-			port_info[port_no].top_change_ack = 0;
-			make_blocking(port_no);	  /* (4.6.11.3.3(2)) */
-		}
-#ifdef DEBUG_STP
-		if (br_stats.flags & BR_DEBUG)
-			printk(KERN_DEBUG "port_state_selection: becomes %s port %d\n",
-				state_str, port_no);
-#endif
-		
-	}
-
-}
-
-static void make_forwarding(int port_no)
-{						  /* (4.6.12) */
-	if (port_info[port_no].state == Blocking) {	/* (4.6.12.3) */
-		set_port_state(port_no, Listening);	/* (4.6.12.3.1) */
-		start_forward_delay_timer(port_no);	/* (4.6.12.3.2) */
-	}
-}
-
-static void topology_change_detection(void)
-{						  /* (4.6.14)       */
-#ifdef DEBUG_STP
-	if ((br_stats.flags & BR_DEBUG)
-	    && (bridge_info.top_change_detected == 0))
-		printk(KERN_DEBUG "topology_change_detected\n");
-#endif
-	if (root_bridge()) {			  /* (4.6.14.3.1)   */
-		bridge_info.top_change = 1;
-		start_topology_change_timer();	  /* (4.6.14.3.1(2)) */
-	} else if (!(bridge_info.top_change_detected)) {
-		transmit_tcn();			  /* (4.6.14.3.2(1)) */
-		start_tcn_timer();		  /* (4.6.14.3.2(2)) */
-	}
-	bridge_info.top_change_detected = 1;	/* (4.6.14.3.3) */
-}
+#include "br_private.h"
 
-static void topology_change_acknowledged(void)
-{						  /* (4.6.15) */
-#ifdef DEBUG_STP
-	if (br_stats.flags & BR_DEBUG)
-		printk(KERN_DEBUG "topology_change_acked\n");
-#endif
-	bridge_info.top_change_detected = 0;	/* (4.6.15.3.1) */
-	stop_tcn_timer();			  /* (4.6.15.3.2) */
-}
-
-static void acknowledge_topology_change(int port_no)
-{						  /* (4.6.16) */
-	port_info[port_no].top_change_ack = 1;
-	transmit_config(port_no);		  /* (4.6.16.3.2) */
-}
-
-static void make_blocking(int port_no)				  /* (4.6.13)	 */
-{
-
-	if ((port_info[port_no].state != Disabled)
-			&&
-			(port_info[port_no].state != Blocking)
-	/* (4.6.13.3)	 */
-		) {
-		if ((port_info[port_no].state == Forwarding)
-				||
-				(port_info[port_no].state == Learning)
-			) {
-			topology_change_detection();	/* (4.6.13.3.1) */
-			/* (4.6.14.2.3)	 */
-		}
-		set_port_state(port_no, Blocking);/* (4.6.13.3.2) */
-		stop_forward_delay_timer(port_no);/* (4.6.13.3.3) */
-	}
-}
-
-static void set_port_state(int port_no, int state)
+void br_dec_use_count()
 {
-	port_info[port_no].state = state;
+	MOD_DEC_USE_COUNT;
 }
 
-static void received_config_bpdu(int port_no, Config_bpdu *config)		  /* (4.7.1)	 */
+void br_inc_use_count()
 {
-	int root;
-
-	root = root_bridge();
-	if (port_info[port_no].state != Disabled) {
-
-#ifdef DEBUG_STP
-		if (br_stats.flags & BR_DEBUG)
-			printk(KERN_DEBUG "received_config_bpdu: port %d\n",
-				port_no);
-#endif
-		if (supersedes_port_info(port_no, config)) {	/* (4.7.1.1)	 *//* (4.
-								 * 6.2.2)	 */
-			record_config_information(port_no, config);	/* (4.7.1.1.1)	 */
-			/* (4.6.2.2)	 */
-			configuration_update();	  /* (4.7.1.1.2)	 */
-			/* (4.6.7.2.1)	 */
-			port_state_selection();	  /* (4.7.1.1.3)	 */
-			/* (4.6.11.2.1)	 */
-			if ((!root_bridge()) && root) {	/* (4.7.1.1.4)	 */
-				stop_hello_timer();
-				if (bridge_info.top_change_detected) {	/* (4.7.1.1.5 */
-					stop_topology_change_timer();
-					transmit_tcn();	/* (4.6.6.1)	 */
-					start_tcn_timer();
-				}
-			}
-			if (port_no == bridge_info.root_port) {
-				record_config_timeout_values(config);	/* (4.7.1.1.6)	 */
-				/* (4.6.3.2)	 */
-				config_bpdu_generation();	/* (4.6.4.2.1)	 */
-				if (config->top_change_ack) {	/* (4.7.1.1.7)    */
-					topology_change_acknowledged();	/* (4.6.15.2)	 */
-				}
-			}
-		} else if (designated_port(port_no)) {	/* (4.7.1.2)	 */
-			reply(port_no);		  /* (4.7.1.2.1)	 */
-			/* (4.6.5.2)	 */
-		}
-	}
+	MOD_INC_USE_COUNT;
 }
 
-static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)			  /* (4.7.2)	 */
+static int __init br_init(void)
 {
-	if (port_info[port_no].state != Disabled) {
-#ifdef DEBUG_STP
-		if (br_stats.flags & BR_DEBUG)
-			printk(KERN_DEBUG "received_tcn_bpdu: port %d\n",
-				port_no);
-#endif
-		if (designated_port(port_no)) {
-			topology_change_detection();	/* (4.7.2.1)	 */
-			/* (4.6.14.2.1)	 */
-			acknowledge_topology_change(port_no);	/* (4.7.2.2)	 */
-		}				  /* (4.6.16.2)	 */
-	}
-}
+	printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
 
-static void hello_timer_expiry(void)
-{						  /* (4.7.3)	 */
-	config_bpdu_generation();		  /* (4.6.4.2.2)	 */
-	start_hello_timer();
-}
-
-static void message_age_timer_expiry(int port_no) /* (4.7.4)	 */
-{
-	int root;
-	root = root_bridge();
+	br_handle_frame_hook = br_handle_frame;
+	br_ioctl_hook = br_ioctl_deviceless_stub;
+	register_netdevice_notifier(&br_device_notifier);
 
-#ifdef DEBUG_STP
-	if (br_stats.flags & BR_DEBUG)
-		printk(KERN_DEBUG "message_age_timer_expiry: port %d\n",
-			port_no);
-#endif
-	become_designated_port(port_no);	  /* (4.7.4.1)	 */
-	/* (4.6.10.2.1)	 */
-	configuration_update();			  /* (4.7.4.2)	 */
-	/* (4.6.7.2.2)	 */
-	port_state_selection();			  /* (4.7.4.3)	 */
-	/* (4.6.11.2.2)	 */
-	if ((root_bridge()) && (!root)) {	  /* (4.7.4.4)	 */
-
-		bridge_info.max_age = bridge_info.bridge_max_age;	/* (4.7.4.4.1)    */
-		bridge_info.hello_time = bridge_info.bridge_hello_time;
-		bridge_info.forward_delay = bridge_info.bridge_forward_delay;
-		topology_change_detection();	  /* (4.7.4.4.2)	 */
-		/* (4.6.14.2.4)	 */
-		stop_tcn_timer();		  /* (4.7.4.4.3)	 */
-		config_bpdu_generation();	  /* (4.7.4.4.4)	 */
-		/* (4.6.4.4.3)	 */
-		start_hello_timer();
-	}
-}
-
-static void forward_delay_timer_expiry(int port_no)	/* (4.7.5)	 */
-{
-	if (port_info[port_no].state == Listening) 
-	{						/* (4.7.5.1)	 */
-		set_port_state(port_no, Learning);	/* (4.7.5.1.1)	 */
-		start_forward_delay_timer(port_no);	/* (4.7.5.1.2)	 */
-	}
-	else if (port_info[port_no].state == Learning) 
-	{
-							/* (4.7.5.2) */
-		set_port_state(port_no, Forwarding);	/* (4.7.5.2.1) */
-		if (designated_for_some_port()) 
-		{ 					/* (4.7.5.2.2) */
-			topology_change_detection();	/* (4.6.14.2.2) */
-
-		}
-	}
-}
-
-static int designated_for_some_port(void)
-{
-	int port_no;
-
-	for (port_no = One; port_no <= No_of_ports; port_no++) 
-	{
-		if(port_info[port_no].state == Disabled)
-			continue;
-		if ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
-				bridge_info.bridge_id.BRIDGE_ID) == 0)) 
-		{
-			return (TRUE);
-		}
-	}
-	return (FALSE);
-}
-
-static void tcn_timer_expiry(void)
-{						  /* (4.7.6)	 */
-	transmit_tcn();				  /* (4.7.6.1)	 */
-	start_tcn_timer();			  /* (4.7.6.2)	 */
-}
-
-static void topology_change_timer_expiry(void)
-{						  /* (4.7.7)	 */
-	bridge_info.top_change_detected = 0;	/* (4.7.7.1) */
-	bridge_info.top_change = 0;
-	  /* (4.7.7.2)	 */
-}
-
-static void hold_timer_expiry(int port_no)	  /* (4.7.8)	 */
-{
-	if (port_info[port_no].config_pending) 
-	{
-		transmit_config(port_no);	  /* (4.7.8.1)	 */
-	}					  /* (4.6.1.2.3)	 */
-}
-
-/* Vova Oksman: Write the buffer (contents of the Bridge table) */
-/* to a PROCfs file                                             */
-static int br_tree_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	int size;
-	int len=0;
-	off_t pos=0;
-	char* pbuffer;
-
-	if(0==offset)
-	{
-		/* first time write the header */
-		size = sprintf(buffer,"%s","MAC address           Device     Flags     Age (sec.)\n");
-		len=size;
-	}
-
-	pbuffer=&buffer[len];
-	sprintf_avl(&pbuffer,NULL,&pos,&len,offset,length);
-
-	*start = buffer+len-(pos-offset);	/* Start of wanted data */
-	len = pos-offset;			/* Start slop */
-	if (len>length)
-		len = length;			/* Ending slop */
-
-	return len;
-}
-
-void __init br_init(void)
-{						  /* (4.8.1)	 */
-	int port_no;
-
-	printk(KERN_INFO "NET4: Ethernet Bridge 006 for NET4.0\n");
-
-	/* Set up brg device information */
-	bridge_info.instance = 0;
-	brg_init();
-
-	max_port_used = 0;
-	
-	/*
-	 * Form initial topology change time.
-	 * The topology change timer is only used if this is the root bridge.
-	 */
-	
-	bridge_info.topology_change_time = BRIDGE_MAX_AGE + BRIDGE_FORWARD_DELAY;       /* (4.5.3.13) */
-
-	bridge_info.designated_root = bridge_info.bridge_id;	/* (4.8.1.1)	 */
-	bridge_info.root_path_cost = Zero;
-	bridge_info.root_port = No_port;
-#ifdef DEBUG_STP
-	printk(KERN_INFO "br_init: becomes root\n");
-#endif
-
-	bridge_info.bridge_max_age = BRIDGE_MAX_AGE;
-	bridge_info.bridge_hello_time = BRIDGE_HELLO_TIME;
-	bridge_info.bridge_forward_delay = BRIDGE_FORWARD_DELAY;
-	bridge_info.hold_time = HOLD_TIME;
-
-	bridge_info.max_age = bridge_info.bridge_max_age;	/* (4.8.1.2)	 */
-	bridge_info.hello_time = bridge_info.bridge_hello_time;
-	bridge_info.forward_delay = bridge_info.bridge_forward_delay;
-
-	bridge_info.top_change_detected = 0;
-	bridge_info.top_change = 0;
-	stop_tcn_timer();
-	stop_topology_change_timer();
-	memset(newfdb, 0, sizeof(newfdb));
-	for (port_no = One; port_no <= No_of_ports; port_no++) {	/* (4.8.1.4) */
-		/* initial state = Disable */
-		user_port_state[port_no] = Disabled;
-		port_priority[port_no] = 128;
-		br_init_port(port_no);
-		disable_port(port_no);
-	}
-#if 0 /* JRP: We are not UP ! Wait for the start command */
-	port_state_selection();			  /* (4.8.1.5)	 */
-	config_bpdu_generation();		  /* (4.8.1.6)	 */
-	/* initialize system timer */
-	tl.expires = jiffies+HZ;	/* 1 second */
-	tl.function = br_tick;
-	add_timer(&tl);
-#endif	
-
-	register_netdevice_notifier(&br_dev_notifier);
-	br_stats.flags = 0; /*BR_UP | BR_DEBUG*/;	/* enable bridge */
-	br_stats.policy = BR_ACCEPT;			/* Enable bridge to accpet all protocols */
-	br_stats.exempt_protocols = 0;
-	/*start_hello_timer();*/
-	/* Vova Oksman: register the function for the PROCfs "bridge" file */
-	proc_net_create("bridge", 0, br_tree_get_info);
-}
-
-static inline unsigned short make_port_id(int port_no)
-{
-	 return (port_priority[port_no] << 8) | port_no;
-}
-
-static void br_init_port(int port_no)
-{
-	port_info[port_no].port_id = make_port_id(port_no);
-	become_designated_port(port_no);	  /* (4.8.1.4.1) */
-	set_port_state(port_no, Blocking);	  /* (4.8.1.4.2)    */
-	port_info[port_no].top_change_ack = 0;
-	port_info[port_no].config_pending = FALSE;/* (4.8.1.4.4)	 */
-	stop_message_age_timer(port_no);	  /* (4.8.1.4.5)	 */
-	stop_forward_delay_timer(port_no);	  /* (4.8.1.4.6)	 */
-	stop_hold_timer(port_no);		  /* (4.8.1.4.7)	 */
-}
-
-static void enable_port(int port_no)				  /* (4.8.2)	 */
-{
-	br_init_port(port_no);
-	port_state_selection();			  /* (4.8.2.7)	 */
-}						  /* */
-
-static void disable_port(int port_no)				  /* (4.8.3)	 */
-{
-	int         root;
-
-	root = root_bridge();
-	become_designated_port(port_no);	  /* (4.8.3.1)	 */
-	set_port_state(port_no, Disabled);	  /* (4.8.3.2)	 */
-	port_info[port_no].top_change_ack = 0;
-	port_info[port_no].config_pending = FALSE;/* (4.8.3.4)	 */
-	stop_message_age_timer(port_no);	  /* (4.8.3.5)	 */
-	stop_forward_delay_timer(port_no);	  /* (4.8.3.6)	 */
-	configuration_update();
-	port_state_selection();			  /* (4.8.3.7)	 */
-	if ((root_bridge()) && (!root)) {	  /* (4.8.3.8)	 */
-		bridge_info.max_age = bridge_info.bridge_max_age;	/* (4.8.3.8.1)    */
-		bridge_info.hello_time = bridge_info.bridge_hello_time;
-		bridge_info.forward_delay = bridge_info.bridge_forward_delay;
-		topology_change_detection();	  /* (4.8.3.8.2)    */
-		stop_tcn_timer();		  /* (4.8.3.8.3)    */
-		config_bpdu_generation();	  /* (4.8.3.8.4)    */
-		start_hello_timer();
-	}
-}
-
-
-static void set_bridge_priority(bridge_id_t *new_bridge_id)
-                                 		  /* (4.8.4)	 */
-{
-
-	int root;
-	int port_no;
-	root = root_bridge();
-	for (port_no = One; port_no <= No_of_ports; port_no++) {	/* (4.8.4.2) */
-		if(port_info[port_no].state == Disabled)
-			continue;
-		if (designated_port(port_no)) {
-			port_info[port_no].designated_bridge = *new_bridge_id;
-		}
-	}
-
-	bridge_info.bridge_id = *new_bridge_id;	  /* (4.8.4.3)	 */
-	configuration_update();			  /* (4.8.4.4)	 */
-	port_state_selection();			  /* (4.8.4.5)	 */
-	if ((root_bridge()) && (!root)) {	  /* (4.8.4.6)	 */
-		bridge_info.max_age = bridge_info.bridge_max_age;	/* (4.8.4.6.1)    */
-		bridge_info.hello_time = bridge_info.bridge_hello_time;
-		bridge_info.forward_delay = bridge_info.bridge_forward_delay;
-		topology_change_detection();	  /* (4.8.4.6.2)    */
-		stop_tcn_timer();		  /* (4.8.4.6.3)    */
-		config_bpdu_generation(),	  /* (4.8.4.6.4)    */
-		start_hello_timer();
-	}
-}
-
-static void set_port_priority(int port_no)
-                                  		  /* (4.8.5)	 */
-{int new_port_id = make_port_id(port_no);
-
-	if (designated_port(port_no)) {		  /* (4.8.5.2)	 */
-		port_info[port_no].designated_port = new_port_id;
-	}
-	port_info[port_no].port_id = new_port_id; /* (4.8.5.3)	 */
-	if ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
-	     port_info[port_no].designated_bridge.BRIDGE_ID) == 0
-	     )
-			&&
-			(port_info[port_no].port_id
-			 < port_info[port_no].designated_port
-
-			 )
-		) 
-	{
-		become_designated_port(port_no);  /* (4.8.5.4.1) */
-		port_state_selection();		  /* (4.8.5.4.2) */
-	}
-}
-
-static void set_path_cost(int port_no, unsigned short path_cost)
-                                                  /* (4.8.6)	 */
-{
-	port_info[port_no].path_cost = path_cost; /* (4.8.6.1)	 */
-	configuration_update();			  /* (4.8.6.2)	 */
-	port_state_selection();			  /* (4.8.6.3)	 */
-}
-
-static void br_tick(unsigned long arg)
-{
-	int port_no;
-
-	if(!(br_stats.flags & BR_UP))
-		return;			 /* JRP: we have been shot down */
-
-	if (hello_timer_expired())
-		hello_timer_expiry();
-
-	if (tcn_timer_expired())
-		tcn_timer_expiry();
-
-	if (topology_change_timer_expired())
-		topology_change_timer_expiry();
-
-	for (port_no = One; port_no <= No_of_ports; port_no++) 
-	{
-		if(port_info[port_no].state == Disabled)
-			continue;
-
-		if (forward_delay_timer_expired(port_no)) 
-			forward_delay_timer_expiry(port_no);
-
-		if (message_age_timer_expired(port_no))
-			message_age_timer_expiry(port_no);
-
-		if (hold_timer_expired(port_no))
-			hold_timer_expiry(port_no);
-	}
-	/* call me again sometime... */
-	tl.expires = jiffies+HZ;	/* 1 second */
-	tl.function = br_tick;
-	add_timer(&tl);
-}
-
-static void start_hello_timer(void)
-{
-	hello_timer.value = 0;
-	hello_timer.active = TRUE;
-}
-
-static void stop_hello_timer(void)
-{
-	hello_timer.active = FALSE;
-}
-
-static int hello_timer_expired(void)
-{
-	if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) 
-	{
-		hello_timer.active = FALSE;
-		return (TRUE);
-	}
-	return (FALSE);
-}
-
-static void start_tcn_timer(void)
-{
-	tcn_timer.value = 0;
-	tcn_timer.active = TRUE;
-}
-
-static void stop_tcn_timer(void)
-{
-	tcn_timer.active = FALSE;
-}
-
-static int tcn_timer_expired(void)
-{
-	if (tcn_timer.active && (++tcn_timer.value >= bridge_info.bridge_hello_time)) 
-	{
-		tcn_timer.active = FALSE;
-		return (TRUE);
-	}
-	return (FALSE);
-
-}
-
-static void start_topology_change_timer(void)
-{
-	topology_change_timer.value = 0;
-	topology_change_timer.active = TRUE;
-}
-
-static void stop_topology_change_timer(void)
-{
-	topology_change_timer.active = FALSE;
-}
-
-static int topology_change_timer_expired(void)
-{
-	if (topology_change_timer.active
-		&& (++topology_change_timer.value >= bridge_info.topology_change_time )) 
-	{
-		topology_change_timer.active = FALSE;
-		return (TRUE);
-	}
-	return (FALSE);
-}
-
-static void start_message_age_timer(int port_no, unsigned short message_age)
-{
-	message_age_timer[port_no].value = message_age;
-	message_age_timer[port_no].active = TRUE;
-}
-
-static void stop_message_age_timer(int port_no)
-{
-	message_age_timer[port_no].active = FALSE;
-}
-
-static int message_age_timer_expired(int port_no)
-{
-	if (message_age_timer[port_no].active && (++message_age_timer[port_no].value >= bridge_info.max_age)) 
-	{
-		message_age_timer[port_no].active = FALSE;
-		return (TRUE);
-	}
-	return (FALSE);
-}
-
-static void start_forward_delay_timer(int port_no)
-{
-	forward_delay_timer[port_no].value = 0;
-	forward_delay_timer[port_no].active = TRUE;
-}
-
-static void stop_forward_delay_timer(int port_no)
-{
-	forward_delay_timer[port_no].active = FALSE;
-}
-
-static int forward_delay_timer_expired(int port_no)
-{
-	if (forward_delay_timer[port_no].active && (++forward_delay_timer[port_no].value >= bridge_info.forward_delay)) 
-	{
-		forward_delay_timer[port_no].active = FALSE;
-		return (TRUE);
-	}
-	return (FALSE);
-}
-
-static void start_hold_timer(int port_no)
-{
-	hold_timer[port_no].value = 0;
-	hold_timer[port_no].active = TRUE;
-}
-
-static void stop_hold_timer(int port_no)
-{
-	hold_timer[port_no].active = FALSE;
-}
-
-static int hold_timer_expired(int port_no)
-{
-	if (hold_timer[port_no].active &&
-		   (++hold_timer[port_no].value >= bridge_info.hold_time)) 
-	{
-		hold_timer[port_no].active = FALSE;
-		return (TRUE);
-	}
-	return (FALSE);
-
-}
-
-static struct sk_buff *alloc_bridge_skb(int port_no, int pdu_size, char *pdu_name)
-{
-	struct sk_buff *skb;
-	struct net_device *dev = port_info[port_no].dev;
-	struct ethhdr *eth;
-	int size = dev->hard_header_len + BRIDGE_LLC1_HS + pdu_size;
-	unsigned char *llc_buffer;
-	int pad_size = 60 - size; 
- 
-	size = 60;	/* minimum Ethernet frame - CRC */
-
-	if (port_info[port_no].state == Disabled) 
-	{
-		printk(KERN_DEBUG "send_%s_bpdu: port %i not valid\n", pdu_name, port_no);
-		return NULL;
-	}
-
-  	skb = alloc_skb(size, GFP_ATOMIC);
-  	if (skb == NULL) 
- 	{
- 		printk(KERN_DEBUG "send_%s_bpdu: no skb available\n", pdu_name);
- 		return NULL;
- 	}
-  	skb->dev = dev;
- 	skb->mac.raw = skb->nh.raw = skb_put(skb,size);
- 	memset(skb->nh.raw + 60 - pad_size, 0xa5, pad_size);
-  	eth = skb->mac.ethernet;
-  	memcpy(eth->h_dest, bridge_ula, ETH_ALEN);
-  	memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
- 
-  	if (br_stats.flags & BR_DEBUG)
- 		printk(KERN_DEBUG "send_%s_bpdu: port %i src %02x:%02x:%02x:%02x:%02x:%02x\n",
- 			pdu_name,
-  			port_no,
-  			eth->h_source[0],
-  			eth->h_source[1],
-  			eth->h_source[2],
-  			eth->h_source[3],
-  			eth->h_source[4],
- 			eth->h_source[5]);
-#if 0
- /* 8038 is used in older DEC spanning tree protocol which uses a
-  * different pdu layout as well
-  */
- 	eth->h_proto = htons(0x8038);
-#endif
-	eth->h_proto = htons(pdu_size + BRIDGE_LLC1_HS);
-  
-  	skb->nh.raw += skb->dev->hard_header_len;
- 	llc_buffer = skb->nh.raw;
- 	*llc_buffer++ = BRIDGE_LLC1_DSAP;
- 	*llc_buffer++ = BRIDGE_LLC1_SSAP;
- 	*llc_buffer++ = BRIDGE_LLC1_CTRL;
- 	/* set nh.raw to where the bpdu starts */
- 	skb->nh.raw += BRIDGE_LLC1_HS;
-  
- 	/* mark that we've been here... */
-  	skb->pkt_bridged = IS_BRIDGED;
- 	return skb;
-}
- 
-static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu)
-{
-	struct sk_buff *skb;
-	
-	/*
-	 *	Keep silent when disabled or when STP disabled
-	 */
-	 
-	if(!(br_stats.flags & BR_UP) || (br_stats.flags & BR_STP_DISABLED))
-		return -1;
-
-	/*
-	 *	Create and send the message
-	 */
-	 
- 	skb = alloc_bridge_skb(port_no, BRIDGE_BPDU_8021_CONFIG_SIZE,
-				"config");
-	if (skb == NULL)
-		return(-1);
-
-	/* copy fields before "flags" */
-	memcpy(skb->nh.raw, config_bpdu, BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
-
-	/* build the "flags" field */
-	*(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) = 0;
-	if (config_bpdu->top_change_ack)
-		*(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) |= 0x80;
-	if (config_bpdu->top_change)
-		*(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) |= 0x01;
-
-	config_bpdu_hton(config_bpdu);
-	/* copy the rest */
-	memcpy(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET+1,
-		 (char*)&(config_bpdu->root_id),
-		 BRIDGE_BPDU_8021_CONFIG_SIZE-1-BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
-
- 	dev_queue_xmit(skb);
-  	return(0);
-}
-  
-static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu)
-{
-	struct sk_buff *skb;
-	
-	/*
-	 *	Keep silent when disabled or when STP disabled
-	 */
-	 
-	if(!(br_stats.flags & BR_UP) || (br_stats.flags & BR_STP_DISABLED))
-		return -1;
-	
- 	
-	skb = alloc_bridge_skb(port_no, sizeof(Tcn_bpdu), "tcn");
-	if (skb == NULL)
-  		return(-1);
-  
-  	memcpy(skb->nh.raw, bpdu, sizeof(Tcn_bpdu));
-  
- 	dev_queue_xmit(skb);
-  	return(0);
-}
-
-static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
-{
-	struct net_device *dev = ptr;
-	int i;
-
-	/* check for loopback devices */
-	if (dev->flags & IFF_LOOPBACK)
-		return(NOTIFY_DONE);
-
-	if (dev == &brg_if.dev)
-	  return(NOTIFY_DONE);	/* Don't attach the brg device to a port! */
-	
-	switch (event) 
-	{
-		case NETDEV_DOWN:
-			if (br_stats.flags & BR_DEBUG)
-				printk(KERN_DEBUG "br_device_event: NETDEV_DOWN...\n");
-			/* find our device and mark it down */
-			for (i = One; i <= No_of_ports; i++) 
-			{
-				if (port_info[i].dev == dev) 
-				{
-					disable_port(i);
-					return NOTIFY_DONE;
-					break;
-				}
-			}
-			break;
-		case NETDEV_UP:
-			if (br_stats.flags & BR_DEBUG)
-				printk(KERN_DEBUG "br_device_event: NETDEV_UP...\n");
-			/* Only handle ethernet ports */
-			if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
-				return NOTIFY_DONE;
-			/* look up an unused device and enable it */
-			for (i = One; i <= No_of_ports; i++) 
-			{
-				if (port_info[i].dev == NULL || port_info[i].dev == dev) 
-				{
-					port_info[i].dev = dev;
-					port_info[i].port_id = i;
-					dev->bridge_port_id = i;
-					if( i > max_port_used ) 
-						max_port_used = i;
-					/* set bridge addr from 1st device addr */
-					if (((htonl(bridge_info.bridge_id.BRIDGE_ID[0])&0xffff) == 0) &&
-						(bridge_info.bridge_id.BRIDGE_ID[1] == 0)) 
-					{
-						memcpy(bridge_info.bridge_id.BRIDGE_ID_ULA, dev->dev_addr, 6);
-						if(bridge_info.bridge_id.BRIDGE_PRIORITY == 0)
-							bridge_info.bridge_id.BRIDGE_PRIORITY = htons(32768);
-						set_bridge_priority(&bridge_info.bridge_id);
-					}
-					/* Add local MAC address */
-					br_add_local_mac(dev->dev_addr);
-					/* Save MAC address for latter change address events */
-					memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
-					if((br_stats.flags & BR_UP) &&
-				   		(user_port_state[i] != Disabled)) 
-				   	{
-				   		/* don't start if user said so */
-							enable_port(i);
-						set_path_cost(i, br_port_cost(dev));
-						set_port_priority(i); 
-						if (br_stats.flags & BR_STP_DISABLED)
-							port_info[i].state = Forwarding;
-						else
-							make_forwarding(i);
-					}
-					return NOTIFY_DONE;
-					break;
-				}
-			}
-			break;
-	        case NETDEV_REGISTER:
-		        if (br_stats.flags & BR_DEBUG) 
-				printk(KERN_DEBUG "br_device_event: NETDEV_REGISTER...\n");
-			/* printk(KERN_ERR "br_device_event: NETDEV_REGISTER...\n"); */
-			/* printk(KERN_ERR "br_device_event: dev->type: 0x%X\n", dev->type); */
-			/* Only handle ethernet ports */
-			if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
-				return NOTIFY_DONE;
-			/* printk(KERN_ERR "br_device_event: Looking for port...\n"); */
-			for (i = One; i <= No_of_ports; i++) 
-			{
-				if (port_info[i].dev == NULL || port_info[i].dev == dev) 
-				{
-				        /* printk(KERN_ERR "br_device_event: Found port %d\n", i); */
-					port_info[i].dev = dev;
-					port_info[i].port_id = i;
-					dev->bridge_port_id = i;
-					if( i > max_port_used )
-						max_port_used = i;
-					/* handle local MAC address minuplations */
-					br_add_local_mac(dev->dev_addr);
-					memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
-					return NOTIFY_DONE;
-					break;
-				}
-			}
-			break;
-		case NETDEV_UNREGISTER:
-			if (br_stats.flags & BR_DEBUG)
-				printk(KERN_DEBUG "br_device_event: NETDEV_UNREGISTER...\n");
-                        i = find_port(dev);
-                        if (i > 0) {
-				br_avl_delete_by_port(i);
-				memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
-				port_info[i].dev = NULL;
-			}
-			break;
-		case NETDEV_CHANGEADDR:
-			if (br_stats.flags & BR_DEBUG)
-				printk(KERN_DEBUG "br_device_event: NETDEV_CHANGEADDR...\n");
-                        i = find_port(dev);
-                        if (i <= 0)  
-			  break;
-			if (memcmp(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6) != 0)
-			  break; /* Don't worry about a change of hardware broadcast address! */
-			if (dev->start) {
-			  printk(KERN_CRIT "br_device_event: NETDEV_CHANGEADDR on busy device %s - FIX DRIVER!\n", 
-				 dev->name);
-			/*  return NOTIFY_BAD;  It SHOULD be this, but I want to be friendly... */
-			  return NOTIFY_DONE;
-			}
-			br_avl_delete_by_port(i);
-			memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
-			break;
-	}
-	return NOTIFY_DONE;
-}
-
-/* Routine to loop over device list and register 
- * interfaces to bridge.  Called from last part of net_dev_init just before
- * bootp/rarp interface setup
- */
-void br_spacedevice_register(void) 
-{
-	struct net_device *dev;
-	for( dev = dev_base; dev != NULL; dev = dev->next)
-	{
-		br_device_event(NULL, NETDEV_REGISTER, dev);
-	}
-}	
-
-
-/* This is for SPEED in the kernel in net_bh.c */
-
-int br_call_bridge(struct sk_buff *skb, unsigned short type)
-{
-	int port;
-	struct net_device *dev;
-  
-#if 0  /* Checked first in handle_bridge to save expense of function call */ 
-	if(!(br_stats.flags & BR_UP))
-		return 0;
-#endif
-  
-	dev = skb->dev;
-	port = dev->bridge_port_id;
-
-	if(!port)
-		return 0;
-
-	/* Sanity - make sure we are not leaping off into fairy space! */
-	if ( port < 0 || port > max_port_used || port_info[port].dev != dev) {
-		if (net_ratelimit())
-			printk(KERN_CRIT "br_call_bridge: device %s has invalid port ID %d!\n",
-				dev->name,
-				dev->bridge_port_id);
-		return 0;
-	}
-
-	if(user_port_state[port] == Disabled)
-		return 0;
-  
-	if (!br_protocol_ok(ntohs(type)))
-		return 0;
-
-	return 1;
-
-}
-
-
-/*
- * following routine is called when a frame is received
- * from an interface, it returns 1 when it consumes the
- * frame, 0 when it does not
- */
-
-int br_receive_frame(struct sk_buff *skb)	/* 3.5 */
-{
-	int port;
-	Port_data  *p;
-	struct ethhdr *eth;
-	struct net_device *dev;
-	
-	/* sanity */
-	if (!skb) {
-		printk(KERN_CRIT "br_receive_frame: no skb!\n");
-		return(1);
-	}
-
-	dev = skb->dev;
-
-	skb->pkt_bridged = IS_BRIDGED;
-
-	/* check for loopback */
-	if (dev->flags & IFF_LOOPBACK)
-		return 0 ;
-
-#if 0
-	port = find_port(dev);
-#else
-	port = dev->bridge_port_id;
-#endif
-	
-	if(!port)
-		return 0;
-	
-	/* Hand off to brg_rx BEFORE we screw up the skb */
-	if(brg_rx(skb, port))
-	  return(1);
-
-	skb->nh.raw = skb->mac.raw;
-	eth = skb->mac.ethernet;
-	p = &port_info[port];
- 
- 	if(p->state == Disabled) 
- 	{
- 		/* We are here if BR_UP even if this port is Disabled.
- 		 * Send everything up
- 		 */
- 		skb->pkt_type = PACKET_HOST;
- 		++br_stats_cnt.port_disable_up_stack;
- 		return(0);	/* pass frame up our stack (this will */
- 				/* happen in net_bh() in dev.c) */
- 	}
- 
- 	/* Here only if not disable.
- 	 * Remark: only frames going up will show up in NIT (tcpdump)
- 	 */
-
-	/* JRP: even if port is Blocking we need to process the Spanning Tree
-	 * frames to keep the port in that state
-	 */
-	if (memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) 
-	{
-		++br_stats_cnt.rcv_bpdu;
-		br_bpdu(skb, port); /* br_bpdu consumes skb */
-		return(1);
-	}
-	switch (p->state) 
-	{
-		case Learning:
-			if(br_learn(skb, port)) 
-			{	/* 3.8 */
-				++br_stats_cnt.drop_multicast;
-				return br_drop(skb);
-			}
-			/* fall through */
-		case Listening:
-			/* fall through */
-		case Blocking:
-			++br_stats_cnt.notForwarding;
-			return(br_drop(skb));	
-		/*
-		case Disabled: is now handled before this switch !
-		Keep the break to allow GCC to use a jmp table.
-		 */
-			break;
-		case Forwarding:
-			if(br_learn(skb, port)) {	/* 3.8 */
-				++br_stats_cnt.drop_multicast;
-				return br_drop(skb);
-			}
-			/* Now this frame came from one of bridged
-			   ports this means we should attempt to forward it.
-			   JRP: local addresses are now in the AVL tree,
-			   br_forward will pass frames up if it matches
-			   one of our local MACs or if it is a multicast
-			   group address.
-			   br_forward() will not consume the frame if this
-			   is the case */
-			return(br_forward(skb, port));
-		default:
-			printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n",
-				port, p->state);
-			++br_stats_cnt.unknown_state;
-			return(br_drop(skb));	/* discard frame */
-	}
-}
-
-/*
- * the following routine is called to transmit frames from the host
- * stack.  it returns 1 when it consumes the frame and
- * 0 when it does not.
- */
-
-int br_tx_frame(struct sk_buff *skb)	/* 3.5 */
-{
-	int port;
-	struct ethhdr *eth;
-	
-	/* sanity */
-	if (!skb) 
-	{
-		printk(KERN_CRIT "br_tx_frame: no skb!\n");
-		return(0);
-	}
-	
-	if (!skb->dev)
-	{
-		printk(KERN_CRIT "br_tx_frame: no dev!\n");
-		return(0);
-	}
-	
-	/* check for loopback */
-	if (skb->dev->flags & IFF_LOOPBACK)
-		return(0);
-
-	/* if bridging is not enabled on the port we are going to send
-           to, we have nothing to do with this frame, hands off */
-	if (((port=find_port(skb->dev))==0)||(port_info[port].state==Disabled)) {
-		++br_stats_cnt.port_disable;
-		return(0);
-	}
-	++br_stats_cnt.port_not_disable;
-	skb->mac.raw = skb->nh.raw = skb->data;
-	eth = skb->mac.ethernet;
-	port = 0;	/* an impossible port (locally generated) */	
-	if (br_stats.flags & BR_DEBUG)
-		printk(KERN_DEBUG "br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x"
-	  		" dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
-			port,
-			eth->h_source[0],
-			eth->h_source[1],
-			eth->h_source[2],
-			eth->h_source[3],
-			eth->h_source[4],
-			eth->h_source[5],
-			eth->h_dest[0],
-			eth->h_dest[1],
-			eth->h_dest[2],
-			eth->h_dest[3],
-			eth->h_dest[4],
-			eth->h_dest[5]);
-	return(br_forward(skb, port));
-}
-
-static void br_add_local_mac(unsigned char *mac)
-{
-	struct fdb *f;
-	f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC);
-	if (!f) 
-	{
-		printk(KERN_CRIT "br_add_local_mac: unable to malloc fdb\n");
-		return;
-	}
-	f->port = 0;	/* dest port == 0 =>local */
-	memcpy(f->ula, mac, 6);
-	f->timer = 0;	/* will not aged anyway */
-	f->flags = 0;	/* not valid => br_forward special route */
-	/*
-	 * add entity to AVL tree.  If entity already
-	 * exists in the tree, update the fields with
-	 * what we have here.
-  	 */
-	if (br_avl_insert(f) != NULL) 
-	{
-		/* Already in */
-		kfree(f);
-	}
-}
-
-/* Avoid broadcast loop by limiting the number of broacast frames per
- * period. The idea is to limit this per source
- * returns: 0 if limit is not reached
- *          1 if frame should be dropped
- */
-
-static inline int mcast_quench(struct fdb *f)
-{
-	if(f->mcast_count++ == 0) /* first time */
-		f->mcast_timer = jiffies;
-	else {
-		if(f->mcast_count > max_mcast_per_period) {
-			if(time_after(jiffies, f->mcast_timer + mcast_hold_time))
-				f->mcast_count = 0;
-			else	return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * this routine returns 0 when it learns (or updates) from the
- * frame, and 1 if we must dropped the frame.
- */
-
-static int br_learn(struct sk_buff *skb, int port)	/* 3.8 */
-{
-	struct fdb *f, *oldfdb;
-	Port_data  *p = &port_info[port];
-	struct ethhdr *eth = skb->mac.ethernet;
-
-	/* JRP: no reason to check port state again. We are called by
-	 * br_receive_frame() only when in Learning or Forwarding
-	 * Remark: code not realigned yet to keep diffs smaller
-	 */
-
-	/* don't keep group addresses in the tree */
-	if (eth->h_source[0] & 0x01)
-		return 0;
-
-	if((f= newfdb[port]) == NULL) 
-	{
-		newfdb[port] = f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC);
-		if (!f) 
-		{
-			printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
-			return(-1); /* this drop the frame */
-		}
-	}
-	f->port = port;	/* source port */
-	memcpy(f->ula, eth->h_source, 6);
-	f->timer = CURRENT_TIME;
-	f->flags = FDB_ENT_VALID;
-	/*
-	 * add entity to AVL tree.  If entity already
-	 * exists in the tree, update the fields with
-	 * what we have here.
-	 */
-	if ((oldfdb = br_avl_insert(f))) 
-	{
-		/* update if !NULL */
-		if((eth->h_dest[0] & 0x01) &&  /* multicast */ mcast_quench(oldfdb))
-			return 1;
-		return 0;
-	}
-	newfdb[port] = NULL;	/* force kmalloc next time */
-	f->mcast_count = 0;
-	/* add to head of port chain */
-	f->fdb_next = p->fdb;
-	p->fdb = f;
-	allocated_fdb_cnt++;
-	return 0;
-}
-
-/* JRP: always called under br_receive_frame(). No need for Q protection. */
-
-void requeue_fdb(struct fdb *node, int new_port)
-{
-	Port_data *p = &port_info[node->port];
-
-	/* dequeue */
-	if(p->fdb == node)
-		p->fdb = node->fdb_next;
-	else 
-	{
-		struct fdb *prev;
-
-		for(prev = p->fdb; prev; prev = prev->fdb_next)
-			if (prev->fdb_next == node)
-				break;
-
-		if(prev != NULL)
-			prev->fdb_next = node->fdb_next;
-		else 
-		{
-			/*	Forget about this update. */
-			printk(KERN_ERR "br:requeue_fdb\n");
-			return;
-		}
-	}
-	/* enqueue */
-	node->port = new_port;
-	node->fdb_next = port_info[new_port].fdb;
-	port_info[new_port].fdb = node;
-}
-
-/*
- * this routine always consumes the frame
- */
-
-static int br_drop(struct sk_buff *skb)
-{
-	kfree_skb(skb);
-	return(1);
-}
-
-/*
- * this routine always consumes the frame
- */
-
-static int br_dev_drop(struct sk_buff *skb)
-{
-	dev_kfree_skb(skb);
-	return(1);
-}
-
-/*
- * Forward the frame SKB to proper port[s].  PORT is the port that the
- * frame has come from; we will not send the frame back there.  PORT == 0
- * means we have been called from br_tx_fr(), not from br_receive_frame().
- *
- * this routine returns 1 if it consumes the frame, 0
- * if not...
- */
-
-static int br_forward(struct sk_buff *skb, int port)	/* 3.7 */
-{
-	struct fdb *f;
-	
-	/*
-   	 * flood all ports with frames destined for a group
-	 * address.  If frame came from above, drop it,
-	 * otherwise it will be handled in br_receive_frame()
-	 * Multicast frames will also need to be seen
-	 * by our upper layers.
-	 */	
-	if (skb->mac.ethernet->h_dest[0] & 0x01) 
-	{
-		/* group address */
-		br_flood(skb, port);
-		/*
-		 *	External groups are fed out via the normal source
-		 *	This probably should be dropped since the flood will
-		 *	have sent it anyway.
-		 */
-		if (port == 0) 
-		{
-			/* Locally generated */
-			++br_stats_cnt.local_multicast;
-			return(br_dev_drop(skb));
-		}
-		++br_stats_cnt.forwarded_multicast;
-		return(0);
-	}
-	else 
-	{
-		/* unicast frame, locate port to forward to */
-		f = br_avl_find_addr(skb->mac.ethernet->h_dest);
-		/*
-		 *	Send flood and drop.
-		 */
-		if (!f || !(f->flags & FDB_ENT_VALID)) 
-		{
-	 		if(f && (f->port == 0)) 
-	 		{
-				skb->pkt_type = PACKET_HOST;
-				++br_stats_cnt.forwarded_unicast_up_stack;
-				return(0);
-			}
-			/* not found or too old; flood all ports */
-			++br_stats_cnt.flood_unicast;
-			br_flood(skb, port);
-			return(br_dev_drop(skb));
-		}
-		/*
-		 *	Sending
-		 */
-		if (f->port!=port && port_info[f->port].state == Forwarding) 
-		{
-			/* Has entry expired? */
-			if (f->timer + fdb_aging_time < CURRENT_TIME) 
-			{
-				/* timer expired, invalidate entry */
-				f->flags &= ~FDB_ENT_VALID;
-				if (br_stats.flags & BR_DEBUG)
-					printk(KERN_DEBUG "fdb entry expired...\n");
-				/*
-				 *	Send flood and drop original
-				 */
-				++br_stats_cnt.aged_flood_unicast;
-				br_flood(skb, port);
-				return(br_dev_drop(skb));
-			}
-			++br_stats_cnt.forwarded_unicast;
-			/* mark that's we've been here... */
-			skb->pkt_bridged = IS_BRIDGED;
-			
-			/* reset the skb->ip pointer */	
-			skb->nh.raw = skb->data + ETH_HLEN;
-
-			/*
-			 *	Send the buffer out.
-			 */
-			 
-			skb->dev=port_info[f->port].dev;
-			 
-			/*
-			 *	We send this still locked
-			 */
-			skb->priority = 1;
-			dev_queue_xmit(skb);
-			return(1);	/* skb has been consumed */
-		}
-		else 
-		{
-			/* JRP: Needs to aged entry as well, if topology changes
-			 * the entry would not age. Got this while swapping
-			 * two cables !
-			 *
-			 *	Has entry expired?
-			 */
-			 
-			if (f->timer + fdb_aging_time < CURRENT_TIME) 
-			{
-				/* timer expired, invalidate entry */
-				f->flags &= ~FDB_ENT_VALID;
-				if (br_stats.flags & BR_DEBUG)
-					printk(KERN_DEBUG "fdb entry expired...\n");
-				++br_stats_cnt.drop_same_port_aged;
-			}
-			else ++br_stats_cnt.drop_same_port;
-			/*
-			 *	Arrived on the right port, we discard
-			 */
-			return(br_dev_drop(skb));
-		}
-	}
-}
-
-/*
- * this routine sends a copy of the frame to all forwarding ports
- * with the exception of the port given.  This routine never
- * consumes the original frame.
- */
-	
-static int br_flood(struct sk_buff *skb, int port)
-{
-	int i;
-	struct sk_buff *nskb;
-
-	for (i = One; i <= No_of_ports; i++) 
-	{
-		if (i == port)	/* don't send back where we got it */
-			continue;
-		if (i > max_port_used)
-			/* Don't go scanning empty port entries */
-			break;
-		if (port_info[i].state == Forwarding) 
-		{
-			nskb = skb_clone(skb, GFP_ATOMIC);
-			if(nskb==NULL)
-				continue;
-			/* mark that's we've been here... */
-			nskb->pkt_bridged = IS_BRIDGED;
-			/* Send to each port in turn */
-			nskb->dev= port_info[i].dev;
-			/* To get here we must have done ARP already,
-			   or have a received valid MAC header */
-			
-/*			printk(KERN_DEBUG "Flood to port %d\n",i);*/
-			nskb->nh.raw = nskb->data + ETH_HLEN;
-			nskb->priority = 1;
-			dev_queue_xmit(nskb);
-		}
-	}
-	return(0);
-}
-
-/*
- *	FIXME: This needs to come from the device structs, eg for
- *	10,100,1Gbit ethernet.
- */
- 
-static int br_port_cost(struct net_device *dev)	/* 4.10.2 */
-{
-	if (strncmp(dev->name, "lec", 3) == 0)	/* ATM Lan Emulation (LANE) */
-		return(7);                      /* 155 Mbs */
-	if (strncmp(dev->name, "eth", 3) == 0)	/* ethernet */
-		return(100);
-	if (strncmp(dev->name, "plip",4) == 0) /* plip */
-		return (1600);
-	return(100);	/* default */
-}
-
-/*
- * this routine always consumes the skb 
- */
-
-static void br_bpdu(struct sk_buff *skb, int port) /* consumes skb */
-{
-	char *bufp = skb->data + ETH_HLEN;
-	Tcn_bpdu *bpdu = (Tcn_bpdu *) (bufp + BRIDGE_LLC1_HS);
-	Config_bpdu rcv_bpdu;
-
-	if(!(br_stats.flags & BR_STP_DISABLED) &&
-	        (*bufp++ == BRIDGE_LLC1_DSAP) && (*bufp++ == BRIDGE_LLC1_SSAP) &&
-		(*bufp++ == BRIDGE_LLC1_CTRL) &&
-		(bpdu->protocol_id == BRIDGE_BPDU_8021_PROTOCOL_ID) &&
-		(bpdu->protocol_version_id == BRIDGE_BPDU_8021_PROTOCOL_VERSION_ID)) 
-	{
-  
-  		switch (bpdu->type) 
-  		{
-	  		case BPDU_TYPE_CONFIG:
- 				/* realign for portability to RISC */
- 				memcpy((char*)&rcv_bpdu, bufp,
- 					BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
- 				bufp+= BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET;
- 				rcv_bpdu.top_change_ack =
- 					(*bufp & TOPOLOGY_CHANGE_ACK) != 0;
- 				rcv_bpdu.top_change =
- 					(*bufp & TOPOLOGY_CHANGE) != 0;
- 				bufp++;
- 				memcpy((char*)&rcv_bpdu.root_id, bufp,
- 					BRIDGE_BPDU_8021_CONFIG_SIZE-1
-        	                         -BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
- 				config_bpdu_ntoh(&rcv_bpdu);
- 				received_config_bpdu(port, &rcv_bpdu);
- 				break;
- 			
-			case BPDU_TYPE_TOPO_CHANGE:
-				received_tcn_bpdu(port, bpdu);
-				break;
-			default:
-				printk(KERN_DEBUG "br_bpdu: received unknown bpdu, type = %i\n", bpdu->type);
-			/* break; */
-		}
-	}
-	br_drop(skb);
-}
-
-struct fdb_info *get_fdb_info(int user_buf_size, int *copied,int *notcopied)
-{
-	int fdb_size, i, built = 0;
-	struct fdb_info *fdbi, *fdbis;
-
-	*copied = user_buf_size - sizeof(struct fdb_info_hdr);
-	*copied /= sizeof(struct fdb_info);
-	*copied = min(*copied, allocated_fdb_cnt);
-	*notcopied = allocated_fdb_cnt - *copied;
-	if(*copied == 0)
-		return NULL;
-	fdb_size = *copied * sizeof(struct fdb_info);
-	fdbis = kmalloc(fdb_size, GFP_KERNEL);
-	if(fdbis == NULL)
-		return NULL;
-	fdbi = fdbis;
-
-	for(i=One; i<=No_of_ports;i++)
-	{
-		struct fdb *fdb;
-
-		cli();
-		fdb = port_info[i].fdb;
-		while(fdb) 
-		{
-			memcpy(fdbi->ula, fdb->ula, ETH_ALEN);
-			fdbi->port = fdb->port;
-			fdbi->flags = fdb->flags;
-			fdbi->timer = fdb->timer;
-			fdbi++;
-			if(++built == *copied) 
-			{
-				sti();
-				return fdbis;
-			}
-			fdb = fdb->fdb_next;
-		}
-		sti();
-	}
-	printk(KERN_DEBUG "get_fdb_info: built=%d\n", built);
-	return fdbis;
-}
-
-
-/* Fill in interface names in port_info structure
- */
-static void br_get_ifnames(void) {
-  int i;
-
-  for(i=One;i<=No_of_ports; i++) {
-    /* memset IS needed.  Kernel strncpy does NOT NULL terminate strings when limit
-       reached */
-    memset(port_info[i].ifname, 0, IFNAMSIZ); 
-    if( port_info[i].dev == 0 )
-      continue;
-    strncpy(port_info[i].ifname, port_info[i].dev->name, IFNAMSIZ-1);
-    /* Being paranoid */
-    port_info[i].ifname[IFNAMSIZ-1] = '\0';
-  }
-}
-
-/* Given an interface index, loop over port array to see if configured.  If
-   so, return port number, otherwise error */ 
-static int br_find_port(int ifindex) 
-{
-  int i;
-  
-  for(i=1; i <= No_of_ports; i++) {
-    if (port_info[i].dev == 0)
-      continue;
-    if (port_info[i].dev->ifindex == ifindex)
-      return(i);
-  }
-  
-  return -EUNATCH;  /* Tell me if this is incorrect error code for this case */
-} 
-
-
-int br_ioctl(unsigned int cmd, void *arg)
-{
-	int err, i, ifflags;
-	struct br_cf bcf;
-	bridge_id_t new_id;
-	struct net_device *dev;
-	
-	switch(cmd)
-	{
-		case SIOCGIFBR:	/* get bridging control blocks */
-			memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
-
-			/* Fill in interface names in port_info*/
-			br_get_ifnames();
-			
-			br_stats.num_ports = No_of_ports;
-			memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*All_ports);
-
-			err = copy_to_user(arg, &br_stats, sizeof(struct br_stat));
-			if (err)
-			{
-				err = -EFAULT;
-			}
-			return err;
-		case SIOCSIFBR:
-			err = copy_from_user(&bcf, arg, sizeof(struct br_cf));
-			if (err)
-				return -EFAULT; 
-			if (bcf.cmd != BRCMD_DISPLAY_FDB && !suser())
-				return -EPERM;
-			switch (bcf.cmd) 
-			{
-				case BRCMD_BRIDGE_ENABLE:
-					if (br_stats.flags & BR_UP)
-						return(-EALREADY);	
-					printk(KERN_DEBUG "br: enabling bridging function\n");
-					br_stats.flags |= BR_UP;	/* enable bridge */
-					for(i=One;i<=No_of_ports; i++)
-					{
-						/* don't start if user said so */
-						if((user_port_state[i] != Disabled)
-							&& port_info[i].dev) 
-						{
-							enable_port(i);
-						}
-					}
-					port_state_selection();	  /* (4.8.1.5)	 */
-					if (br_stats.flags & BR_STP_DISABLED)
-						for(i=One;i<=No_of_ports; i++)
-							if((user_port_state[i] != Disabled) && port_info[i].dev)
-								port_info[i].state = Forwarding;
-					config_bpdu_generation();  /* (4.8.1.6)	 */
-					/* initialize system timer */
-					tl.expires = jiffies+HZ;	/* 1 second */
-					tl.function = br_tick;
-					add_timer(&tl);
-					start_hello_timer();
-					break;
-				case BRCMD_BRIDGE_DISABLE:
-					if (!(br_stats.flags & BR_UP))
-						return(-EALREADY);	
-					printk(KERN_DEBUG "br: disabling bridging function\n");
-					br_stats.flags &= ~BR_UP;	/* disable bridge */
-					stop_hello_timer();
-					for (i = One; i <= No_of_ports; i++)
-						if (port_info[i].state != Disabled)
-							disable_port(i);
-					break;
-				case BRCMD_TOGGLE_STP:
-					printk(KERN_DEBUG "br: %s spanning tree protcol\n",
-					       (br_stats.flags & BR_STP_DISABLED) ? "enabling" : "disabling");
-					if (br_stats.flags & BR_STP_DISABLED) { /* enable STP */
-						for(i=One;i<=No_of_ports; i++)
-							if((user_port_state[i] != Disabled) && port_info[i].dev)
-								enable_port(i);
-					} else { /* STP was enabled, now disable it */
-						for (i = One; i <= No_of_ports; i++)
-							if (port_info[i].state != Disabled && port_info[i].dev)
-								port_info[i].state = Forwarding;
-					}
-					br_stats.flags ^= BR_STP_DISABLED;
-					break;
-			        case BRCMD_IF_ENABLE:
-				        bcf.arg1 = br_find_port(bcf.arg1);
-					if (bcf.arg1 < 0)
-						return(bcf.arg1);
-				case BRCMD_PORT_ENABLE:
-					if (port_info[bcf.arg1].dev == 0)
-						return(-EINVAL);
-					if (user_port_state[bcf.arg1] != Disabled)
-						return(-EALREADY);
-					printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
-					dev = port_info[bcf.arg1].dev;
-					ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
-					  |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
-					dev_change_flags(dev, ifflags|IFF_PROMISC);
-					user_port_state[bcf.arg1] = ~Disabled;
-					if(br_stats.flags & BR_UP)
-						enable_port(bcf.arg1);
-					break;
-			        case BRCMD_IF_DISABLE:
-				        bcf.arg1 = br_find_port(bcf.arg1);
-					if (bcf.arg1 < 0)
-						return(bcf.arg1);
-				case BRCMD_PORT_DISABLE:
-					if (port_info[bcf.arg1].dev == 0)
-						return(-EINVAL);
-					if (user_port_state[bcf.arg1] == Disabled)
-						return(-EALREADY);
-					printk(KERN_DEBUG "br: disabling port %i\n",bcf.arg1);
-					user_port_state[bcf.arg1] = Disabled;
-					if(br_stats.flags & BR_UP)
-						disable_port(bcf.arg1);
-					dev = port_info[bcf.arg1].dev;
-					ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
-					  |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
-					dev_change_flags(port_info[bcf.arg1].dev, ifflags & ~IFF_PROMISC);
-					break;
-				case BRCMD_SET_BRIDGE_PRIORITY:
-					new_id = bridge_info.bridge_id;
-					new_id.BRIDGE_PRIORITY = htons(bcf.arg1);
-					set_bridge_priority(&new_id);
-					break;
-			        case BRCMD_SET_IF_PRIORITY:
-				        bcf.arg1 = br_find_port(bcf.arg1);
-					if (bcf.arg1 < 0)
-						return(bcf.arg1);
-				case BRCMD_SET_PORT_PRIORITY:
-					if((port_info[bcf.arg1].dev == 0)
-					    || (bcf.arg2 & ~0xff))
-						return(-EINVAL);
-					port_priority[bcf.arg1] = bcf.arg2;
-					set_port_priority(bcf.arg1);
-					break;
-			        case BRCMD_SET_IF_PATH_COST:
-				        bcf.arg1 = br_find_port(bcf.arg1);
-					if (bcf.arg1 < 0)
-						return(bcf.arg1);
-				case BRCMD_SET_PATH_COST:
-					if (port_info[bcf.arg1].dev == 0)
-						return(-EINVAL);
-					set_path_cost(bcf.arg1, bcf.arg2);
-					break;
-				case BRCMD_ENABLE_DEBUG:
-					br_stats.flags |= BR_DEBUG;
-					break;
-				case BRCMD_DISABLE_DEBUG:
-					br_stats.flags &= ~BR_DEBUG;
-					break;
-				case BRCMD_SET_POLICY:
-					return br_set_policy(bcf.arg1);
-				case BRCMD_EXEMPT_PROTOCOL:
-					return br_add_exempt_protocol(bcf.arg1);
-				case BRCMD_ENABLE_PROT_STATS:
-					br_stats.flags |= BR_PROT_STATS;
-					break;
-				case BRCMD_DISABLE_PROT_STATS:
-					br_stats.flags &= ~BR_PROT_STATS;
-					break;
-				case BRCMD_ZERO_PROT_STATS:
-					memset(&br_stats.prot_id,0,sizeof(br_stats.prot_id));
-					memset(&br_stats.prot_counter,0,sizeof(br_stats.prot_counter));
-					break;
-				case BRCMD_DISPLAY_FDB:
-				{
-					struct fdb_info_hdr *user_buf = (void*) bcf.arg1;
-					struct fdb_info *u_fdbs, *fdbis;
-					int copied, notcopied;
-					u32 j = CURRENT_TIME;
-
-					if(bcf.arg2<sizeof(struct fdb_info_hdr))
-						return -EINVAL;
-					put_user(j, &user_buf->cmd_time);
-					if(allocated_fdb_cnt == 0) 
-					{
-						put_user(0, &user_buf->copied);
-						put_user(0, &user_buf->not_copied);
-						return 0;
-					}
-					fdbis = get_fdb_info(bcf.arg2, &copied, &notcopied);
-					put_user(copied, &user_buf->copied);
-					put_user(notcopied, &user_buf->not_copied);
-					if(!fdbis)
-						return -ENOMEM;
-					u_fdbs = (struct fdb_info *) (user_buf+1);
-					err = copy_to_user(u_fdbs, fdbis, copied*sizeof(struct fdb_info));
-					kfree(fdbis);
-					if (err)
-					{
-						err = -EFAULT;
-					}
-					return err;
-				}
-				default:
-					return -EINVAL;
-			}
-			return(0);
-		default:
-			return -EINVAL;
-	}
-	/*NOTREACHED*/
 	return 0;
 }
 
-static int br_cmp(unsigned int *a, unsigned int *b)
+static void __br_clear_frame_hook(void)
 {
-	int i;	
-	for (i=0; i<2; i++) 
-	{
-		/* JRP: compares prty then MAC address in memory byte order
-		 * OK optimizer does htonl() only once per long !
-		 */
-		if (htonl(a[i]) < htonl(b[i]))
-			return(-1);
-		if (htonl(a[i]) > htonl(b[i]))
-			return(1);
-	}
-	return(0);
+	br_handle_frame_hook = NULL;
 }
 
-
-
-
-/* --------------------------------------------------------------------------------
- *
- *
- *  Bridge network device here for future modularization - device structures
- *  must be 'static' inside bridge instance
- *  Modelled after sch_teql.c
- * 
- */
-
-
-
-/*
- *	Index to functions.
- */
-
-int	    brg_probe(struct net_device *dev);
-static int  brg_open(struct net_device *dev);
-static int  brg_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int  brg_close(struct net_device *dev);
-static struct net_device_stats *brg_get_stats(struct net_device *dev);
-static void brg_set_multicast_list(struct net_device *dev);
-
-/*
- *	Board-specific info in dev->priv.
- */
-
-struct net_local
+static void __br_clear_ioctl_hook(void)
 {
-	__u32		groups;
-	struct net_device_stats stats;
-};
-
-
-
-
-/*
- *	To call this a probe is a bit misleading, however for real
- *	hardware it would have to check what was present.
- */
- 
-int __init brg_probe(struct net_device *dev)
-{
-  unsigned int bogomips;
-  struct timeval utime;
-
-  printk(KERN_INFO "%s: network interface for Ethernet Bridge 006/NET4.0\n", dev->name);
-
-  /*
-   *	Initialize the device structure.
-   */
-  
-  dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-  if (dev->priv == NULL)
-    return -ENOMEM;
-  memset(dev->priv, 0, sizeof(struct net_local));
-
-  /* Set up MAC address based on BogoMIPs figure for first CPU and time
-   */ 
-  bogomips = (loops_per_sec+2500)/500000 ;
-  get_fast_time(&utime);
-
-  /* Ummmm....  YES! */
-  dev->dev_addr[0] = '\xFE';
-  dev->dev_addr[1] = '\xFD';
-  dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4;
-  dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16);
-  dev->dev_addr[3] = bogomips & 0xFF;
-  dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8;
-  dev->dev_addr[5] = (utime.tv_sec & 0x000000FF);
-  
-  printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", 
-	 dev->name,
-	 dev->dev_addr[0],
-	 dev->dev_addr[1],
-	 dev->dev_addr[2],
-	 dev->dev_addr[3],
-	 dev->dev_addr[4],
-	 dev->dev_addr[5]);
-
-  
-  printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr);
-
-  /*
-   *	The brg specific entries in the device structure.
-   */
-
-  dev->open = brg_open;
-  dev->hard_start_xmit = brg_start_xmit;
-  dev->stop = brg_close;
-  dev->get_stats = brg_get_stats;
-  dev->set_multicast_list = brg_set_multicast_list;
-
-  /*
-   *	Setup the generic properties
-   */
-
-  ether_setup(dev);
-
-  dev->tx_queue_len = 0;
-
-  return 0;
+	br_ioctl_hook = NULL;
 }
 
-/*
- *	Open/initialize the board.
- */
-
-static int brg_open(struct net_device *dev)
+static void __exit br_deinit(void)
 {
-        if (br_stats.flags & BR_DEBUG)
-		printk(KERN_DEBUG "%s: Doing brg_open()...", dev->name);
-
-	if (memcmp(dev->dev_addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
-	  return -EFAULT;
-
-	dev->start = 1;
-	dev->tbusy = 0;
-	return 0;
-}
-
-static unsigned brg_mc_hash(__u8 *dest)
-{
-	unsigned idx = 0;
-	idx ^= dest[0];
-	idx ^= dest[1];
-	idx ^= dest[2];
-	idx ^= dest[3];
-	idx ^= dest[4];
-	idx ^= dest[5];
-	return 1U << (idx&0x1F);
-}
-
-static void brg_set_multicast_list(struct net_device *dev)
-{
-	unsigned groups = ~0;
-	struct net_local *lp = (struct net_local *)dev->priv;
-
-	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
-		struct dev_mc_list *dmi;
-
-		groups = brg_mc_hash(dev->broadcast);
-
-		for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
-			if (dmi->dmi_addrlen != 6)
-				continue;
-			groups |= brg_mc_hash(dmi->dmi_addr);
-		}
-	}
-	lp->groups = groups;
-}
-
-/*
- *	We transmit by throwing the packet at the bridge.
- */
- 
-static int brg_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = (struct net_local *)dev->priv;
-	struct ethhdr *eth = (struct ethhdr*)skb->data;
-	int port;
-
-	/* Deal with the bridge being disabled */
-	if(!(br_stats.flags & BR_UP)) {
-		/* Either this */
-		/* lp->stats.tx_errors++; */ /* this condition is NOT an error */
-		/* or this  (implied by RFC 2233) */
-		lp->stats.tx_dropped++;
-		dev_kfree_skb(skb);
-		return 0;
-	}
-
-	lp->stats.tx_bytes+=skb->len;
-	lp->stats.tx_packets++;
-
-#if 0
-	++br_stats_cnt.port_not_disable;
-#endif
-	skb->mac.raw = skb->nh.raw = skb->data;
-	eth = skb->mac.ethernet;
-	port = 0;	/* an impossible port (locally generated) */	
-
-	 if (br_stats.flags & BR_DEBUG)
-		printk(KERN_DEBUG "%s: brg_start_xmit - src %02x:%02x:%02x:%02x:%02x:%02x"
-	  		" dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
-		       dev->name,
-		       eth->h_source[0],
-		       eth->h_source[1],
-		       eth->h_source[2],
-		       eth->h_source[3],
-		       eth->h_source[4],
-		       eth->h_source[5],
-		       eth->h_dest[0],
-		       eth->h_dest[1],
-		       eth->h_dest[2],
-		       eth->h_dest[3],
-		       eth->h_dest[4],
-		       eth->h_dest[5]);
-	
-	/* Forward the packet ! */
-	if(br_forward(skb, port))
-	  return(0);
-    
-	/* Throw packet initially */
-	dev_kfree_skb(skb);
-	return 0;
-}
-
-
-/*
- *	The typical workload of the driver:
- *	Handle the ether interface interrupts.
- *
- *	(In this case handle the packets posted from the bridge)
- */
-
-static int brg_rx(struct sk_buff *skb, int port)
-{
-        struct net_device *dev = &brg_if.dev;
-	struct net_local *lp = (struct net_local *)dev->priv;
-	struct ethhdr *eth = (struct ethhdr*)(skb->data);
-	int len = skb->len;
-	int clone = 0;
-
-	if (br_stats.flags & BR_DEBUG)
-		printk(KERN_DEBUG "%s: brg_rx()\n", dev->name);
-
-	/* Get out of here if the bridge interface is not up
-	 */
-	if(!(dev->flags & IFF_UP))
-	  return(0);
-	
-	/* Check that the port that this thing came off is in the forwarding state 
-	 * We sould only listen to the same address scope we will transmit to.
-	 */
-	if(port_info[port].state != Forwarding)
-	  return(0);
-
-	/* Is this for us? - broadcast/mulitcast/promiscuous packets need cloning,
-         * with uni-cast we eat the packet
-	 */
-	clone = 0;
-	if (dev->flags & IFF_PROMISC) {
-	  clone = 1;
-	}
-	else if (eth->h_dest[0]&1) {
-	  if (!(dev->flags&(IFF_ALLMULTI))
-	      && !(brg_mc_hash(eth->h_dest)&lp->groups))
-	    return(0);
-	  clone = 1;
-	}
-	else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN) != 0) {
-	  return(0);
-	}
-
-	/* Clone things here - we want to be transparent before we check packet data 
-	 * integrity
-	 */
-	if(clone) {
-	  struct sk_buff *skb2 = skb;
-	  skb = skb_clone(skb2, GFP_ATOMIC);
-	  if (skb == NULL) {
-	    return(0);
-	  }
-	  
-	}
-
-	/* Check packet length 
-	 */
-	if (len < 16) {
-		printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len);
-		kfree_skb(skb);
-		return(!clone);
-	}
-
-	if (br_stats.flags & BR_DEBUG)
-	  printk(KERN_DEBUG "%s: brg_rx - src %02x:%02x:%02x:%02x:%02x:%02x"
-		 " dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
-		 dev->name,
-		 eth->h_source[0],
-		 eth->h_source[1],
-		 eth->h_source[2],
-		 eth->h_source[3],
-		 eth->h_source[4],
-		 eth->h_source[5],
-		 eth->h_dest[0],
-		 eth->h_dest[1],
-		 eth->h_dest[2],
-		 eth->h_dest[3],
-		 eth->h_dest[4],
-		 eth->h_dest[5]);
-
-	/* Do it */
-	skb->pkt_type = PACKET_HOST;
-	skb->dev = dev;
-	skb->protocol=eth_type_trans(skb,dev);
-	memset(skb->cb, 0, sizeof(skb->cb));
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes+=len;
-	netif_rx(skb);
-	return(!clone);
-}
-
-static int brg_close(struct net_device *dev)
-{
-	if (br_stats.flags & BR_DEBUG)
-		printk(KERN_DEBUG "%s: Shutting down.\n", dev->name);
-
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	return 0;
-}
-
-static struct net_device_stats *brg_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = (struct net_local *)dev->priv;
-	return &lp->stats;
-}
-
-/* 
- *      
- */
-
-int __init brg_init(void)
-{
-        int err;
-
-	memset(&brg_if, 0, sizeof(brg_if));
-
-        rtnl_lock();
-
-	brg_if.dev.base_addr = bridge_info.instance;
-	sprintf (brg_if.name, "brg%d", bridge_info.instance);
-	brg_if.dev.name = (void*)&brg_if.name;
-        if(dev_get(brg_if.name)) {
-               printk(KERN_INFO "%s already loaded.\n", brg_if.name);
-	       return -EBUSY;
-	}
-        brg_if.dev.init = brg_probe;
-
-        err = register_netdevice(&brg_if.dev);
-        rtnl_unlock();
-        return err;
-}
-
-
-#if 0				/* Its here if we ever need it... */
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-
-  /* 
-   * Unregister the device
-   */
-  rtnl_lock();
-  unregister_netdevice(&the_master.dev);
-  rtnl_unlock();
-
-  /*
-   *	Free up the private structure.
-   */
-  
-  kfree(brg_if.dev.priv);
-  brg_if.dev.priv = NULL;	/* gets re-allocated by brg_probe */
+	unregister_netdevice_notifier(&br_device_notifier);
+	br_call_ioctl_atomic(__br_clear_ioctl_hook);
+	net_call_rx_atomic(__br_clear_frame_hook);
 }
 
-#endif /* MODULE */
+EXPORT_NO_SYMBOLS;
 
-#endif
+module_init(br_init)
+module_exit(br_deinit)
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_device.c linux/net/bridge/br_device.c
--- v2.3.46/linux/net/bridge/br_device.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_device.c	Fri Feb 18 14:51:22 2000
@@ -0,0 +1,141 @@
+/*
+ *	Device handling code
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_device.c,v 1.1 2000/02/18 16:47:11 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_bridge.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+
+static int br_dev_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	unsigned long args[4];
+	unsigned long *data;
+
+	if (cmd != SIOCDEVPRIVATE)
+		return -EOPNOTSUPP;
+
+	data = (unsigned long *)rq->ifr_data;
+	if (copy_from_user(args, data, 4*sizeof(unsigned long)))
+		return -EFAULT;
+
+	return br_ioctl(dev->priv, args[0], args[1], args[2], args[3]);
+}
+
+static struct net_device_stats *br_dev_get_stats(struct net_device *dev)
+{
+	struct net_bridge *br;
+
+	br = dev->priv;
+
+	return &br->statistics;
+}
+
+static int __br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_bridge *br;
+	unsigned char *dest;
+	struct net_bridge_fdb_entry *dst;
+
+	br = dev->priv;
+	br->statistics.tx_packets++;
+	br->statistics.tx_bytes += skb->len;
+
+	dest = skb->data;
+
+	if (dest[0] & 1) {
+		br_flood(br, skb, 0);
+		return 0;
+	}
+
+	if ((dst = br_fdb_get(br, dest)) != NULL) {
+		br_forward(dst->dst, skb);
+		br_fdb_put(dst);
+		return 0;
+	}
+
+	br_flood(br, skb, 0);
+	return 0;
+}
+
+static int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_bridge *br;
+	int ret;
+
+	br = dev->priv;
+	read_lock(&br->lock);
+	ret = __br_dev_xmit(skb, dev);
+	read_unlock(&br->lock);
+
+	return ret;
+}
+
+static int br_dev_open(struct net_device *dev)
+{
+	struct net_bridge *br;
+
+	netif_start_queue(dev);
+
+	br = dev->priv;
+	read_lock(&br->lock);
+	br_stp_enable_bridge(br);
+	read_unlock(&br->lock);
+
+	return 0;
+}
+
+static void br_dev_set_multicast_list(struct net_device *dev)
+{
+}
+
+static int br_dev_stop(struct net_device *dev)
+{
+	struct net_bridge *br;
+
+	br = dev->priv;
+	read_lock(&br->lock);
+	br_stp_disable_bridge(br);
+	read_unlock(&br->lock);
+
+	netif_stop_queue(dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_NET_FASTROUTE
+static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
+{
+	return -1;
+}
+#endif
+
+void br_dev_setup(struct net_device *dev)
+{
+	memset(dev->dev_addr, 0, ETH_ALEN);
+
+	dev->do_ioctl = br_dev_do_ioctl;
+	dev->get_stats = br_dev_get_stats;
+	dev->hard_start_xmit = br_dev_xmit;
+	dev->open = br_dev_open;
+	dev->set_multicast_list = br_dev_set_multicast_list;
+	dev->stop = br_dev_stop;
+#ifdef CONFIG_NET_FASTROUTE
+	dev->accept_fastpath = br_dev_accept_fastpath;
+#endif
+
+	dev->tx_queue_len = 0;
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_fdb.c linux/net/bridge/br_fdb.c
--- v2.3.46/linux/net/bridge/br_fdb.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_fdb.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,318 @@
+/*
+ *	Forwarding database
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_fdb.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include <asm/atomic.h>
+#include <asm/spinlock.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+
+static __inline__ unsigned long __timeout(struct net_bridge *br)
+{
+	unsigned long timeout;
+
+	timeout = jiffies - br->ageing_time;
+	if (br->topology_change)
+		timeout = jiffies - br->forward_delay;
+
+	return timeout;
+}
+
+static __inline__ int has_expired(struct net_bridge *br,
+				  struct net_bridge_fdb_entry *fdb)
+{
+	if (!fdb->is_static &&
+	    time_before_eq(fdb->ageing_timer, __timeout(br)))
+		return 1;
+
+	return 0;
+}
+
+static __inline__ void copy_fdb(struct __fdb_entry *ent, struct net_bridge_fdb_entry *f)
+{
+	memcpy(ent->mac_addr, f->addr.addr, ETH_ALEN);
+	ent->port_no = f->dst?f->dst->port_no:0;
+	ent->is_local = f->is_local;
+	ent->ageing_timer_value = 0;
+	if (!f->is_static)
+		ent->ageing_timer_value = jiffies - f->ageing_timer;
+}
+
+static __inline__ int br_mac_hash(unsigned char *mac)
+{
+	unsigned long x;
+
+	x = mac[0];
+	x = (x << 2) ^ mac[1];
+	x = (x << 2) ^ mac[2];
+	x = (x << 2) ^ mac[3];
+	x = (x << 2) ^ mac[4];
+	x = (x << 2) ^ mac[5];
+
+	x ^= x >> 8;
+
+	return x & (BR_HASH_SIZE - 1);
+}
+
+static __inline__ void __hash_link(struct net_bridge *br,
+				   struct net_bridge_fdb_entry *ent,
+				   int hash)
+{
+	ent->next_hash = br->hash[hash];
+	if (ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = &ent->next_hash;
+	br->hash[hash] = ent;
+	ent->pprev_hash = &br->hash[hash];
+}
+
+static __inline__ void __hash_unlink(struct net_bridge_fdb_entry *ent)
+{
+	*(ent->pprev_hash) = ent->next_hash;
+	if (ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = ent->pprev_hash;
+	ent->next_hash = NULL;
+	ent->pprev_hash = NULL;
+}
+
+
+
+void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr)
+{
+	struct net_bridge *br;
+	int i;
+
+	br = p->br;
+	write_lock_bh(&br->hash_lock);
+	for (i=0;i<BR_HASH_SIZE;i++) {
+		struct net_bridge_fdb_entry *f;
+
+		f = br->hash[i];
+		while (f != NULL) {
+			if (f->dst == p && f->is_local) {
+				__hash_unlink(f);
+				memcpy(f->addr.addr, newaddr, ETH_ALEN);
+				__hash_link(br, f, br_mac_hash(newaddr));
+				write_unlock_bh(&br->hash_lock);
+				return;
+			}
+			f = f->next_hash;
+		}
+	}
+	write_unlock_bh(&br->hash_lock);
+}
+
+void br_fdb_cleanup(struct net_bridge *br)
+{
+	int i;
+	unsigned long timeout;
+
+	timeout = __timeout(br);
+
+	write_lock_bh(&br->hash_lock);
+	for (i=0;i<BR_HASH_SIZE;i++) {
+		struct net_bridge_fdb_entry *f;
+
+		f = br->hash[i];
+		while (f != NULL) {
+			struct net_bridge_fdb_entry *g;
+
+			g = f->next_hash;
+			if (!f->is_static &&
+			    time_before_eq(f->ageing_timer, timeout)) {
+				__hash_unlink(f);
+				br_fdb_put(f);
+			}
+			f = g;
+		}
+	}
+	write_unlock_bh(&br->hash_lock);
+}
+
+void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
+{
+	int i;
+
+	write_lock_bh(&br->hash_lock);
+	for (i=0;i<BR_HASH_SIZE;i++) {
+		struct net_bridge_fdb_entry *f;
+
+		f = br->hash[i];
+		while (f != NULL) {
+			struct net_bridge_fdb_entry *g;
+
+			g = f->next_hash;
+			if (f->dst == p) {
+				__hash_unlink(f);
+				br_fdb_put(f);
+			}
+			f = g;
+		}
+	}
+	write_unlock_bh(&br->hash_lock);
+}
+
+struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, unsigned char *addr)
+{
+	struct net_bridge_fdb_entry *fdb;
+
+	read_lock_bh(&br->hash_lock);
+	fdb = br->hash[br_mac_hash(addr)];
+	while (fdb != NULL) {
+		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
+			if (!has_expired(br, fdb)) {
+				atomic_inc(&fdb->use_count);
+				read_unlock_bh(&br->hash_lock);
+				return fdb;
+			}
+
+			read_unlock_bh(&br->hash_lock);
+			return NULL;
+		}
+
+		fdb = fdb->next_hash;
+	}
+
+	read_unlock_bh(&br->hash_lock);
+	return NULL;
+}
+
+void br_fdb_put(struct net_bridge_fdb_entry *ent)
+{
+	if (atomic_dec_and_test(&ent->use_count))
+		kfree(ent);
+}
+
+int br_fdb_get_entries(struct net_bridge *br,
+		       unsigned char *_buf,
+		       int maxnum,
+		       int offset)
+{
+	int i;
+	int num;
+	struct __fdb_entry *walk;
+
+	num = 0;
+	walk = (struct __fdb_entry *)_buf;
+
+	read_lock_bh(&br->hash_lock);
+	for (i=0;i<BR_HASH_SIZE;i++) {
+		struct net_bridge_fdb_entry *f;
+
+		f = br->hash[i];
+		while (f != NULL && num < maxnum) {
+			struct __fdb_entry ent;
+			int err;
+			struct net_bridge_fdb_entry *g;
+
+			if (has_expired(br, f)) {
+				f = f->next_hash;
+				continue;
+			}
+
+			if (offset) {
+				offset--;
+				f = f->next_hash;
+				continue;
+			}
+
+			copy_fdb(&ent, f);
+
+			atomic_inc(&f->use_count);
+			read_unlock_bh(&br->hash_lock);
+			err = copy_to_user(walk, &ent, sizeof(struct __fdb_entry));
+			read_lock_bh(&br->hash_lock);
+
+			g = f->next_hash;
+			br_fdb_put(f);
+
+			if (err)
+				goto out_fault;
+
+			if (f->next_hash == NULL &&
+			    f->pprev_hash == NULL)
+				goto out_disappeared;
+
+			num++;
+			walk++;
+
+			f = g;
+		}
+	}
+
+ out:
+	read_unlock_bh(&br->hash_lock);
+	return num;
+
+ out_disappeared:
+	num = -EAGAIN;
+	goto out;
+
+ out_fault:
+	num = -EFAULT;
+	goto out;
+}
+
+static __inline__ void __fdb_possibly_replace(struct net_bridge_fdb_entry *fdb,
+					      struct net_bridge_port *source,
+					      int is_local)
+{
+	if (!fdb->is_static || is_local) {
+		fdb->dst = source;
+		fdb->is_local = is_local;
+		fdb->is_static = is_local;
+		fdb->ageing_timer = jiffies;
+	}
+}
+
+void br_fdb_insert(struct net_bridge *br,
+		   struct net_bridge_port *source,
+		   unsigned char *addr,
+		   int is_local)
+{
+	struct net_bridge_fdb_entry *fdb;
+	int hash;
+
+	hash = br_mac_hash(addr);
+
+	write_lock_bh(&br->hash_lock);
+	fdb = br->hash[hash];
+	while (fdb != NULL) {
+		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
+			__fdb_possibly_replace(fdb, source, is_local);
+			write_unlock_bh(&br->hash_lock);
+			return;
+		}
+
+		fdb = fdb->next_hash;
+	}
+
+	fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC);
+	if (fdb == NULL) {
+		write_unlock_bh(&br->hash_lock);
+		return;
+	}
+
+	memcpy(fdb->addr.addr, addr, ETH_ALEN);
+	atomic_set(&fdb->use_count, 1);
+	fdb->dst = source;
+	fdb->is_local = is_local;
+	fdb->is_static = is_local;
+	fdb->ageing_timer = jiffies;
+
+	__hash_link(br, fdb, hash);
+
+	write_unlock_bh(&br->hash_lock);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_forward.c linux/net/bridge/br_forward.c
--- v2.3.46/linux/net/bridge/br_forward.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_forward.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,95 @@
+/*
+ *	Forwarding decision
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_forward.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_bridge.h>
+#include "br_private.h"
+
+static inline int should_forward(struct net_bridge_port *p, struct sk_buff *skb)
+{
+	if (skb->dev == p->dev ||
+	    p->state != BR_STATE_FORWARDING)
+		return 0;
+
+	return 1;
+}
+
+static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb)
+{
+	skb->dev = to->dev;
+	dev_queue_xmit(skb);
+}
+
+/* called under bridge lock */
+void br_forward(struct net_bridge_port *to, struct sk_buff *skb)
+{
+	if (should_forward(to, skb)) {
+		__br_forward(to, skb);
+		return;
+	}
+
+	kfree_skb(skb);
+}
+
+/* called under bridge lock */
+void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone)
+{
+	struct net_bridge_port *p;
+	struct net_bridge_port *prev;
+
+	if (clone) {
+		struct sk_buff *skb2;
+
+		if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+			br->statistics.tx_dropped++;
+			return;
+		}
+
+		skb = skb2;
+	}
+
+	prev = NULL;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (should_forward(p, skb)) {
+			if (prev != NULL) {
+				struct sk_buff *skb2;
+
+				if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+					br->statistics.tx_dropped++;
+					kfree_skb(skb);
+					return;
+				}
+
+				__br_forward(prev, skb2);
+			}
+
+			prev = p;
+		}
+
+		p = p->next;
+	}
+
+	if (prev != NULL) {
+		__br_forward(prev, skb);
+		return;
+	}
+
+	kfree_skb(skb);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_if.c linux/net/bridge/br_if.c
--- v2.3.46/linux/net/bridge/br_if.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_if.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,293 @@
+/*
+ *	Userspace interface
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_if.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+
+static struct net_bridge *bridge_list;
+
+static int br_initial_port_cost(struct net_device *dev)
+{
+	if (!strncmp(dev->name, "lec", 3))
+		return 7;
+
+	if (!strncmp(dev->name, "eth", 3))
+		return 100;			/* FIXME handle 100Mbps */
+
+	if (!strncmp(dev->name, "plip", 4))
+		return 2500;
+
+	return 100;
+}
+
+/* called under bridge lock */
+static int __br_del_if(struct net_bridge *br, struct net_device *dev)
+{
+	struct net_bridge_port *p;
+	struct net_bridge_port **pptr;
+
+	if ((p = dev->br_port) == NULL)
+		return -EINVAL;
+
+	br_stp_disable_port(p);
+
+	dev_set_promiscuity(dev, -1);
+	dev->br_port = NULL;
+
+	pptr = &br->port_list;
+	while (*pptr != NULL) {
+		if (*pptr == p) {
+			*pptr = p->next;
+			break;
+		}
+
+		pptr = &((*pptr)->next);
+	}
+
+	br_fdb_delete_by_port(br, p);
+	kfree(p);
+	dev_put(dev);
+
+	return 0;
+}
+
+static struct net_bridge **__find_br(char *name)
+{
+	struct net_bridge **b;
+	struct net_bridge *br;
+
+	b = &bridge_list;
+	while ((br = *b) != NULL) {
+		if (!strncmp(br->name, name, IFNAMSIZ))
+			return b;
+
+		b = &(br->next);
+	}
+
+	return NULL;
+}
+
+static void del_ifs(struct net_bridge *br)
+{
+	write_lock_bh(&br->lock);
+	while (br->port_list != NULL)
+		__br_del_if(br, br->port_list->dev);
+	write_unlock_bh(&br->lock);
+}
+
+static struct net_bridge *new_nb(char *name)
+{
+	struct net_bridge *br;
+	struct net_device *dev;
+
+	if ((br = kmalloc(sizeof(*br), GFP_KERNEL)) == NULL)
+		return NULL;
+
+	memset(br, 0, sizeof(*br));
+	dev = &br->dev;
+
+	strncpy(br->name, name, IFNAMSIZ);
+	dev->priv = br;
+	dev->name = br->name;
+	ether_setup(dev);
+	br_dev_setup(dev);
+
+	br->lock = RW_LOCK_UNLOCKED;
+	br->hash_lock = RW_LOCK_UNLOCKED;
+
+	br->bridge_id.prio[0] = 0x80;
+	br->bridge_id.prio[1] = 0x00;
+	memset(br->bridge_id.addr, 0, ETH_ALEN);
+
+	br->stp_enabled = 1;
+	br->designated_root = br->bridge_id;
+	br->root_path_cost = 0;
+	br->root_port = 0;
+	br->bridge_max_age = br->max_age = 20 * HZ;
+	br->bridge_hello_time = br->hello_time = 2 * HZ;
+	br->bridge_forward_delay = br->forward_delay = 15 * HZ;
+	br->topology_change = 0;
+	br->topology_change_detected = 0;
+	br_timer_clear(&br->hello_timer);
+	br_timer_clear(&br->tcn_timer);
+	br_timer_clear(&br->topology_change_timer);
+
+	br->ageing_time = 300 * HZ;
+	br->gc_interval = 4 * HZ;
+
+	return br;
+}
+
+/* called under bridge lock */
+static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device *dev)
+{
+	int i;
+	struct net_bridge_port *p;
+
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (p == NULL)
+		return p;
+
+	memset(p, 0, sizeof(*p));
+	p->br = br;
+	p->dev = dev;
+	p->path_cost = br_initial_port_cost(dev);
+	p->priority = 0x80;
+
+	dev->br_port = p;
+
+	for (i=1;i<255;i++)
+		if (br_get_port(br, i) == NULL)
+			break;
+
+	if (i == 255) {
+		kfree(p);
+		return NULL;
+	}
+
+	p->port_no = i;
+	br_init_port(p);
+	p->state = BR_STATE_DISABLED;
+
+	p->next = br->port_list;
+	br->port_list = p;
+
+	return p;
+}
+
+int br_add_bridge(char *name)
+{
+	struct net_bridge *br;
+
+	if ((br = new_nb(name)) == NULL)
+		return -ENOMEM;
+
+	if (__dev_get_by_name(name) != NULL) {
+		kfree(br);
+		return -EEXIST;
+	}
+
+	br->next = bridge_list;
+	bridge_list = br;
+
+	br_inc_use_count();
+	register_netdev(&br->dev);
+
+	return 0;
+}
+
+int br_del_bridge(char *name)
+{
+	struct net_bridge **b;
+	struct net_bridge *br;
+
+	if ((b = __find_br(name)) == NULL)
+		return -ENXIO;
+
+	br = *b;
+
+	if (br->dev.flags & IFF_UP)
+		return -EBUSY;
+
+	del_ifs(br);
+
+	*b = br->next;
+
+	unregister_netdev(&br->dev);
+	kfree(br);
+	br_dec_use_count();
+
+	return 0;
+}
+
+int br_add_if(struct net_bridge *br, struct net_device *dev)
+{
+	struct net_bridge_port *p;
+
+	if (dev->br_port != NULL)
+		return -EBUSY;
+
+	if (dev->flags & IFF_LOOPBACK)
+		return -EINVAL;
+
+	dev_hold(dev);
+	write_lock_bh(&br->lock);
+	if ((p = new_nbp(br, dev)) == NULL) {
+		write_unlock_bh(&br->lock);
+		dev_put(dev);
+		return -EXFULL;
+	}
+
+	dev_set_promiscuity(dev, 1);
+
+	br_stp_recalculate_bridge_id(br);
+	br_fdb_insert(br, p, dev->dev_addr, 1);
+	if ((br->dev.flags & IFF_UP) && (dev->flags & IFF_UP))
+		br_stp_enable_port(p);
+	write_unlock_bh(&br->lock);
+
+	return 0;
+}
+
+int br_del_if(struct net_bridge *br, struct net_device *dev)
+{
+	int retval;
+
+	write_lock_bh(&br->lock);
+	retval = __br_del_if(br, dev);
+	br_stp_recalculate_bridge_id(br);
+	write_unlock_bh(&br->lock);
+
+	return retval;
+}
+
+int br_get_bridge_ifindices(int *indices, int num)
+{
+	struct net_bridge *br;
+	int i;
+
+	i = 0;
+
+	br = bridge_list;
+	for (i=0;i<num;i++) {
+		if (br == NULL)
+			break;
+
+		indices[i] = br->dev.ifindex;
+		br = br->next;
+	}
+
+	return i;
+}
+
+/* called under ioctl_lock */
+void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
+{
+	int i;
+	struct net_bridge_port *p;
+
+	for (i=0;i<256;i++)
+		ifindices[i] = 0;
+
+	p = br->port_list;
+	while (p != NULL) {
+		ifindices[p->port_no] = p->dev->ifindex;
+		p = p->next;
+	}
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_input.c linux/net/bridge/br_input.c
--- v2.3.46/linux/net/bridge/br_input.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_input.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,113 @@
+/*
+ *	Handle incoming frames
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_input.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
+#include "br_private.h"
+
+unsigned char bridge_ula[5] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
+
+static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
+{
+	if (br->dev.flags & IFF_UP) {
+		br->statistics.rx_packets++;
+		br->statistics.rx_bytes += skb->len;
+
+		skb->dev = &br->dev;
+		skb->pkt_type = PACKET_HOST;
+		skb->mac.raw = skb->data;
+		skb_pull(skb, skb->nh.raw - skb->data);
+		skb->protocol = eth_type_trans(skb, &br->dev);
+		netif_rx(skb);
+
+		return;
+	}
+
+	kfree_skb(skb);
+}
+
+static void __br_handle_frame(struct sk_buff *skb)
+{
+	struct net_bridge *br;
+	unsigned char *dest;
+	struct net_bridge_fdb_entry *dst;
+	struct net_bridge_port *p;
+
+	skb->nh.raw = skb->mac.raw;
+	dest = skb->mac.ethernet->h_dest;
+
+	p = skb->dev->br_port;
+	br = p->br;
+
+	if (p->state == BR_STATE_DISABLED ||
+	    skb->mac.ethernet->h_source[0] & 1)
+		goto freeandout;
+
+	if (!memcmp(dest, bridge_ula, 5) && !(dest[5] & 0xF0))
+		goto handle_special_frame;
+
+	skb_push(skb, skb->data - skb->mac.raw);
+
+	if (p->state == BR_STATE_LEARNING ||
+	    p->state == BR_STATE_FORWARDING)
+		br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
+
+	if (p->state != BR_STATE_FORWARDING)
+		goto freeandout;
+
+	if (dest[0] & 1) {
+		br_flood(br, skb, 1);
+		br_pass_frame_up(br, skb);
+		return;
+	}
+
+	dst = br_fdb_get(br, dest);
+
+	if (dst != NULL && dst->is_local) {
+		br_pass_frame_up(br, skb);
+		br_fdb_put(dst);
+		return;
+	}
+
+	if (dst != NULL) {
+		br_forward(dst->dst, skb);
+		br_fdb_put(dst);
+		return;
+	}
+
+	br_flood(br, skb, 0);
+	return;
+
+ handle_special_frame:
+	if (!dest[5]) {
+		br_stp_handle_bpdu(skb);
+		return;
+	}
+
+ freeandout:
+	kfree_skb(skb);
+}
+
+void br_handle_frame(struct sk_buff *skb)
+{
+	struct net_bridge *br;
+
+	br = skb->dev->br_port->br;
+	read_lock(&br->lock);
+	__br_handle_frame(skb);
+	read_unlock(&br->lock);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_ioctl.c linux/net/bridge/br_ioctl.c
--- v2.3.46/linux/net/bridge/br_ioctl.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_ioctl.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,264 @@
+/*
+ *	Ioctl handler
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_ioctl.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include <linux/inetdevice.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+
+static int br_ioctl_device(struct net_bridge *br,
+			   unsigned int cmd,
+			   unsigned long arg0,
+			   unsigned long arg1,
+			   unsigned long arg2)
+{
+	if (br == NULL)
+		return -EINVAL;
+
+	switch (cmd)
+	{
+	case BRCTL_ADD_IF:
+	case BRCTL_DEL_IF:
+	{
+		struct net_device *dev;
+		int ret;
+
+		dev = dev_get_by_index(arg0);
+		if (dev == NULL)
+			return -EINVAL;
+
+		if (cmd == BRCTL_ADD_IF)
+			ret = br_add_if(br, dev);
+		else
+			ret = br_del_if(br, dev);
+
+		dev_put(dev);
+		return ret;
+	}
+
+	case BRCTL_GET_BRIDGE_INFO:
+	{
+		struct __bridge_info b;
+
+		memcpy(&b.designated_root, &br->designated_root, 8);
+		memcpy(&b.bridge_id, &br->bridge_id, 8);
+		b.root_path_cost = br->root_path_cost;
+		b.max_age = br->max_age;
+		b.hello_time = br->hello_time;
+		b.forward_delay = br->forward_delay;
+		b.bridge_max_age = br->bridge_max_age;
+		b.bridge_hello_time = br->bridge_hello_time;
+		b.bridge_forward_delay = br->bridge_forward_delay;
+		b.topology_change = br->topology_change;
+		b.topology_change_detected = br->topology_change_detected;
+		b.root_port = br->root_port;
+		b.stp_enabled = br->stp_enabled;
+		b.ageing_time = br->ageing_time;
+		b.gc_interval = br->gc_interval;
+		b.hello_timer_value = br_timer_get_residue(&br->hello_timer);
+		b.tcn_timer_value = br_timer_get_residue(&br->tcn_timer);
+		b.topology_change_timer_value = br_timer_get_residue(&br->topology_change_timer);
+		b.gc_timer_value = br_timer_get_residue(&br->gc_timer);
+
+		if (copy_to_user((void *)arg0, &b, sizeof(b)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	case BRCTL_GET_PORT_LIST:
+	{
+		int indices[256];
+
+		br_get_port_ifindices(br, indices);
+		if (copy_to_user((void *)arg0, indices, 256*sizeof(int)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	case BRCTL_SET_BRIDGE_FORWARD_DELAY:
+		br->bridge_forward_delay = arg0;
+		if (br_is_root_bridge(br))
+			br->forward_delay = arg0;
+		return 0;
+
+	case BRCTL_SET_BRIDGE_HELLO_TIME:
+		br->bridge_hello_time = arg0;
+		if (br_is_root_bridge(br))
+			br->hello_time = arg0;
+		return 0;
+
+	case BRCTL_SET_BRIDGE_MAX_AGE:
+		br->bridge_max_age = arg0;
+		if (br_is_root_bridge(br))
+			br->max_age = arg0;
+		return 0;
+
+	case BRCTL_SET_AGEING_TIME:
+		br->ageing_time = arg0;
+		return 0;
+
+	case BRCTL_SET_GC_INTERVAL:
+		br->gc_interval = arg0;
+		return 0;
+
+	case BRCTL_GET_PORT_INFO:
+	{
+		struct __port_info p;
+		struct net_bridge_port *pt;
+
+		if ((pt = br_get_port(br, arg1)) == NULL)
+			return -EINVAL;
+
+		memcpy(&p.designated_root, &pt->designated_root, 8);
+		memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
+		p.port_id = pt->port_id;
+		p.designated_port = pt->designated_port;
+		p.path_cost = pt->path_cost;
+		p.designated_cost = pt->designated_cost;
+		p.state = pt->state;
+		p.top_change_ack = pt->topology_change_ack;
+		p.config_pending = pt->config_pending;
+		p.message_age_timer_value = br_timer_get_residue(&pt->message_age_timer);
+		p.forward_delay_timer_value = br_timer_get_residue(&pt->forward_delay_timer);
+		p.hold_timer_value = br_timer_get_residue(&pt->hold_timer);
+
+		if (copy_to_user((void *)arg0, &p, sizeof(p)))
+			return -EINVAL;
+
+		return 0;
+	}
+
+	case BRCTL_SET_BRIDGE_STP_STATE:
+		br->stp_enabled = arg0?1:0;
+		return 0;
+
+	case BRCTL_SET_BRIDGE_PRIORITY:
+		br_stp_set_bridge_priority(br, arg0);
+		return 0;
+
+	case BRCTL_SET_PORT_PRIORITY:
+	{
+		struct net_bridge_port *p;
+
+		if ((p = br_get_port(br, arg0)) == NULL)
+			return -EINVAL;
+		br_stp_set_port_priority(p, arg1);
+		return 0;
+	}
+
+	case BRCTL_SET_PATH_COST:
+	{
+		struct net_bridge_port *p;
+
+		if ((p = br_get_port(br, arg0)) == NULL)
+			return -EINVAL;
+		br_stp_set_path_cost(p, arg1);
+		return 0;
+	}
+
+	case BRCTL_GET_FDB_ENTRIES:
+		return br_fdb_get_entries(br, (void *)arg0, arg1, arg2);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int br_ioctl_deviceless(unsigned int cmd,
+			       unsigned long arg0,
+			       unsigned long arg1)
+{
+	switch (cmd)
+	{
+	case BRCTL_GET_VERSION:
+		return BRCTL_VERSION;
+
+	case BRCTL_GET_BRIDGES:
+	{
+		int indices[64];
+
+		if (arg1 > 64)
+			arg1 = 64;
+		arg1 = br_get_bridge_ifindices(indices, arg1);
+		if (copy_to_user((void *)arg0, indices, arg1*sizeof(int)))
+			return -EFAULT;
+
+		return arg1;
+	}
+
+	case BRCTL_ADD_BRIDGE:
+	case BRCTL_DEL_BRIDGE:
+	{
+		char buf[IFNAMSIZ];
+
+		if (copy_from_user(buf, (void *)arg0, IFNAMSIZ))
+			return -EFAULT;
+
+		buf[IFNAMSIZ-1] = 0;
+
+		if (cmd == BRCTL_ADD_BRIDGE)
+			return br_add_bridge(buf);
+
+		return br_del_bridge(buf);
+	}
+	}
+
+	return -EOPNOTSUPP;
+}
+
+DECLARE_MUTEX(ioctl_mutex);
+
+int br_ioctl_deviceless_stub(unsigned long arg)
+{
+	int err;
+	unsigned long i[3];
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(i, (void *)arg, 3*sizeof(unsigned long)))
+		return -EFAULT;
+
+	down(&ioctl_mutex);
+	err = br_ioctl_deviceless(i[0], i[1], i[2]);
+	up(&ioctl_mutex);
+
+	return err;
+}
+
+int br_ioctl(struct net_bridge *br, unsigned int cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2)
+{
+	int err;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	down(&ioctl_mutex);
+	err = br_ioctl_deviceless(cmd, arg0, arg1);
+	if (err == -EOPNOTSUPP)
+		err = br_ioctl_device(br, cmd, arg0, arg1, arg2);
+	up(&ioctl_mutex);
+
+	return err;
+}
+
+void br_call_ioctl_atomic(void (*fn)(void))
+{
+	down(&ioctl_mutex);
+	fn();
+	up(&ioctl_mutex);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_notify.c linux/net/bridge/br_notify.c
--- v2.3.46/linux/net/bridge/br_notify.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_notify.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,75 @@
+/*
+ *	Device event handling
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_notify.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include "br_private.h"
+
+static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr);
+
+struct notifier_block br_device_notifier =
+{
+	br_device_event,
+	NULL,
+	0
+};
+
+static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+	struct net_device *dev;
+	struct net_bridge_port *p;
+
+	dev = ptr;
+	p = dev->br_port;
+
+	if (p == NULL)
+		return NOTIFY_DONE;
+
+	switch (event)
+	{
+	case NETDEV_CHANGEADDR:
+		read_lock(&p->br->lock);
+		br_fdb_changeaddr(p, dev->dev_addr);
+		br_stp_recalculate_bridge_id(p->br);
+		read_unlock(&p->br->lock);
+		break;
+
+	case NETDEV_GOING_DOWN:
+		/* extend the protocol to send some kind of notification? */
+		break;
+
+	case NETDEV_DOWN:
+		if (p->br->dev.flags & IFF_UP) {
+			read_lock(&p->br->lock);
+			br_stp_disable_port(dev->br_port);
+			read_unlock(&p->br->lock);
+		}
+		break;
+
+	case NETDEV_UP:
+		if (p->br->dev.flags & IFF_UP) {
+			read_lock(&p->br->lock);
+			br_stp_enable_port(dev->br_port);
+			read_unlock(&p->br->lock);
+		}
+		break;
+
+	case NETDEV_UNREGISTER:
+		br_del_if(dev->br_port->br, dev);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_private.h linux/net/bridge/br_private.h
--- v2.3.46/linux/net/bridge/br_private.h	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_private.h	Fri Feb 18 14:51:22 2000
@@ -0,0 +1,199 @@
+/*
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_private.h,v 1.1 2000/02/18 16:47:12 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _BR_PRIVATE_H
+#define _BR_PRIVATE_H
+
+#include <linux/netdevice.h>
+#include <linux/miscdevice.h>
+#include <linux/if_bridge.h>
+#include "br_private_timer.h"
+
+#define BR_HASH_BITS 8
+#define BR_HASH_SIZE (1 << BR_HASH_BITS)
+
+#define BR_HOLD_TIME (1*HZ)
+
+typedef struct bridge_id bridge_id;
+typedef struct mac_addr mac_addr;
+typedef __u16 port_id;
+
+struct bridge_id
+{
+	unsigned char	prio[2];
+	unsigned char	addr[6];
+};
+
+struct mac_addr
+{
+	unsigned char	addr[6];
+	unsigned char	pad[2];
+};
+
+struct net_bridge_fdb_entry
+{
+	struct net_bridge_fdb_entry	*next_hash;
+	struct net_bridge_fdb_entry	**pprev_hash;
+	atomic_t			use_count;
+	mac_addr			addr;
+	struct net_bridge_port		*dst;
+	unsigned long			ageing_timer;
+	unsigned			is_local:1;
+	unsigned			is_static:1;
+};
+
+struct net_bridge_port
+{
+	struct net_bridge_port		*next;
+	struct net_bridge		*br;
+	struct net_device		*dev;
+	int				port_no;
+
+	/* STP */
+	port_id				port_id;
+	int				state;
+	int				path_cost;
+	bridge_id			designated_root;
+	int				designated_cost;
+	bridge_id			designated_bridge;
+	port_id				designated_port;
+	unsigned			topology_change_ack:1;
+	unsigned			config_pending:1;
+	int				priority;
+
+	struct br_timer			forward_delay_timer;
+	struct br_timer			hold_timer;
+	struct br_timer			message_age_timer;
+};
+
+struct net_bridge
+{
+	struct net_bridge		*next;
+	rwlock_t			lock;
+	struct net_bridge_port		*port_list;
+	char				name[IFNAMSIZ];
+	struct net_device		dev;
+	struct net_device_stats		statistics;
+	rwlock_t			hash_lock;
+	struct net_bridge_fdb_entry	*hash[BR_HASH_SIZE];
+	struct timer_list		tick;
+
+	/* STP */
+	bridge_id			designated_root;
+	int				root_path_cost;
+	int				root_port;
+	int				max_age;
+	int				hello_time;
+	int				forward_delay;
+	bridge_id			bridge_id;
+	int				bridge_max_age;
+	int				bridge_hello_time;
+	int				bridge_forward_delay;
+	unsigned			stp_enabled:1;
+	unsigned			topology_change:1;
+	unsigned			topology_change_detected:1;
+
+	struct br_timer			hello_timer;
+	struct br_timer			tcn_timer;
+	struct br_timer			topology_change_timer;
+	struct br_timer			gc_timer;
+
+	int				ageing_time;
+	int				gc_interval;
+};
+
+struct notifier_block br_device_notifier;
+unsigned char bridge_ula[5];
+
+/* br.c */
+void br_dec_use_count(void);
+void br_inc_use_count(void);
+
+/* br_device.c */
+void br_dev_setup(struct net_device *dev);
+
+/* br_fdb.c */
+void br_fdb_changeaddr(struct net_bridge_port *p,
+		       unsigned char *newaddr);
+void br_fdb_cleanup(struct net_bridge *br);
+void br_fdb_delete_by_port(struct net_bridge *br,
+			   struct net_bridge_port *p);
+struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
+					unsigned char *addr);
+void br_fdb_put(struct net_bridge_fdb_entry *ent);
+int  br_fdb_get_entries(struct net_bridge *br,
+			unsigned char *_buf,
+			int maxnum,
+			int offset);
+void br_fdb_insert(struct net_bridge *br,
+		   struct net_bridge_port *source,
+		   unsigned char *addr,
+		   int is_local);
+
+/* br_forward.c */
+void br_forward(struct net_bridge_port *to,
+		struct sk_buff *skb);
+void br_flood(struct net_bridge *br,
+	      struct sk_buff *skb,
+	      int clone);
+
+/* br_if.c */
+int br_add_bridge(char *name);
+int br_del_bridge(char *name);
+int br_add_if(struct net_bridge *br,
+	      struct net_device *dev);
+int br_del_if(struct net_bridge *br,
+	      struct net_device *dev);
+int br_get_bridge_ifindices(int *indices,
+			    int num);
+void br_get_port_ifindices(struct net_bridge *br,
+			   int *ifindices);
+
+/* br_input.c */
+void br_handle_frame(struct sk_buff *skb);
+
+/* br_ioctl.c */
+void br_call_ioctl_atomic(void (*fn)(void));
+int br_ioctl(struct net_bridge *br,
+	     unsigned int cmd,
+	     unsigned long arg0,
+	     unsigned long arg1,
+	     unsigned long arg2);
+int br_ioctl_deviceless_stub(unsigned long arg);
+
+/* br_stp.c */
+int br_is_root_bridge(struct net_bridge *br);
+struct net_bridge_port *br_get_port(struct net_bridge *br,
+				    int port_no);
+void br_init_port(struct net_bridge_port *p);
+port_id br_make_port_id(struct net_bridge_port *p);
+void br_become_designated_port(struct net_bridge_port *p);
+
+/* br_stp_if.c */
+void br_stp_enable_bridge(struct net_bridge *br);
+void br_stp_disable_bridge(struct net_bridge *br);
+void br_stp_enable_port(struct net_bridge_port *p);
+void br_stp_disable_port(struct net_bridge_port *p);
+void br_stp_recalculate_bridge_id(struct net_bridge *br);
+void br_stp_set_bridge_priority(struct net_bridge *br,
+				int newprio);
+void br_stp_set_port_priority(struct net_bridge_port *p,
+			      int newprio);
+void br_stp_set_path_cost(struct net_bridge_port *p,
+			  int path_cost);
+
+/* br_stp_bpdu.c */
+void br_stp_handle_bpdu(struct sk_buff *skb);
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_private_stp.h linux/net/bridge/br_private_stp.h
--- v2.3.46/linux/net/bridge/br_private_stp.h	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_private_stp.h	Fri Feb 18 14:51:22 2000
@@ -0,0 +1,53 @@
+/*
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_private_stp.h,v 1.1 2000/02/18 16:47:13 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _BR_PRIVATE_STP_H
+#define _BR_PRIVATE_STP_H
+
+#define BPDU_TYPE_CONFIG 0
+#define BPDU_TYPE_TCN 1
+
+struct br_config_bpdu
+{
+	unsigned	topology_change:1;
+	unsigned	topology_change_ack:1;
+	bridge_id	root;
+	int		root_path_cost;
+	bridge_id	bridge_id;
+	port_id		port_id;
+	int		message_age;
+	int		max_age;
+	int		hello_time;
+	int		forward_delay;
+};
+
+/* br_stp.c */
+void br_become_root_bridge(struct net_bridge *br);
+void br_config_bpdu_generation(struct net_bridge *);
+void br_configuration_update(struct net_bridge *);
+int  br_is_designated_port(struct net_bridge_port *p);
+int  br_is_root_bridge(struct net_bridge *br);
+void br_port_state_selection(struct net_bridge *);
+void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu);
+void br_received_tcn_bpdu(struct net_bridge_port *p);
+void br_tick(unsigned long __data);
+void br_transmit_config(struct net_bridge_port *p);
+void br_transmit_tcn(struct net_bridge *br);
+void br_topology_change_detection(struct net_bridge *br);
+
+/* br_stp_bpdu.c */
+void br_send_config_bpdu(struct net_bridge_port *, struct br_config_bpdu *);
+void br_send_tcn_bpdu(struct net_bridge_port *);
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_private_timer.h linux/net/bridge/br_private_timer.h
--- v2.3.46/linux/net/bridge/br_private_timer.h	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_private_timer.h	Fri Feb 18 14:51:22 2000
@@ -0,0 +1,54 @@
+/*
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_private_timer.h,v 1.1 2000/02/18 16:47:13 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _BR_PRIVATE_TIMER_H
+#define _BR_PRIVATE_TIMER_H
+
+struct br_timer
+{
+	int running;
+	unsigned long expires;
+};
+
+extern __inline__ void br_timer_clear(struct br_timer *t)
+{
+	t->running = 0;
+}
+
+extern __inline__ unsigned long br_timer_get_residue(struct br_timer *t)
+{
+	if (t->running)
+		return jiffies - t->expires;
+
+	return 0;
+}
+
+extern __inline__ void br_timer_set(struct br_timer *t, unsigned long x)
+{
+	t->expires = x;
+	t->running = 1;
+}
+
+extern __inline__ int br_timer_is_running(struct br_timer *t)
+{
+	return t->running;
+}
+
+extern __inline__ int br_timer_has_expired(struct br_timer *t, unsigned long to)
+{
+	return t->running && time_after_eq(jiffies, t->expires + to);
+}
+
+
+#endif
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp.c linux/net/bridge/br_stp.c
--- v2.3.46/linux/net/bridge/br_stp.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_stp.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,465 @@
+/*
+ *	Spanning tree protocol; generic parts
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_stp.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+#include "br_private_stp.h"
+
+
+
+/* called under ioctl_lock or bridge lock */
+int br_is_root_bridge(struct net_bridge *br)
+{
+	return !memcmp(&br->bridge_id, &br->designated_root, 8);
+}
+
+/* called under bridge lock */
+int br_is_designated_port(struct net_bridge_port *p)
+{
+	return !memcmp(&p->designated_bridge, &p->br->bridge_id, 8) &&
+		(p->designated_port == p->port_id);
+}
+
+/* called under ioctl_lock or bridge lock */
+struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no)
+{
+	struct net_bridge_port *p;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->port_no == port_no)
+			return p;
+
+		p = p->next;
+	}
+
+	return NULL;
+}
+
+/* called under bridge lock */
+static int br_should_become_root_port(struct net_bridge_port *p, int root_port)
+{
+	struct net_bridge *br;
+	struct net_bridge_port *rp;
+	int t;
+
+	br = p->br;
+	if (p->state == BR_STATE_DISABLED ||
+	    br_is_designated_port(p))
+		return 0;
+
+	if (memcmp(&br->bridge_id, &p->designated_root, 8) <= 0)
+		return 0;
+
+	if (!root_port)
+		return 1;
+
+	rp = br_get_port(br, root_port);
+
+	t = memcmp(&p->designated_root, &rp->designated_root, 8);
+	if (t < 0)
+		return 1;
+	else if (t > 0)
+		return 0;
+
+	if (p->designated_cost + p->path_cost <
+	    rp->designated_cost + rp->path_cost)
+		return 1;
+	else if (p->designated_cost + p->path_cost >
+		 rp->designated_cost + rp->path_cost)
+		return 0;
+
+	t = memcmp(&p->designated_bridge, &rp->designated_bridge, 8);
+	if (t < 0)
+		return 1;
+	else if (t > 0)
+		return 0;
+
+	if (p->designated_port < rp->designated_port)
+		return 1;
+	else if (p->designated_port > rp->designated_port)
+		return 0;
+
+	if (p->port_id < rp->port_id)
+		return 1;
+
+	return 0;
+}
+
+/* called under bridge lock */
+static void br_root_selection(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+	int root_port;
+
+	root_port = 0;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (br_should_become_root_port(p, root_port))
+			root_port = p->port_no;
+
+		p = p->next;
+	}
+
+	br->root_port = root_port;
+
+	if (!root_port) {
+		br->designated_root = br->bridge_id;
+		br->root_path_cost = 0;
+	} else {
+		p = br_get_port(br, root_port);
+		br->designated_root = p->designated_root;
+		br->root_path_cost = p->designated_cost + p->path_cost;
+	}
+}
+
+/* called under bridge lock */
+void br_become_root_bridge(struct net_bridge *br)
+{
+	br->max_age = br->bridge_max_age;
+	br->hello_time = br->bridge_hello_time;
+	br->forward_delay = br->bridge_forward_delay;
+	br_topology_change_detection(br);
+	br_timer_clear(&br->tcn_timer);
+	br_config_bpdu_generation(br);
+	br_timer_set(&br->hello_timer, jiffies);
+}
+
+/* called under bridge lock */
+void br_transmit_config(struct net_bridge_port *p)
+{
+	struct br_config_bpdu bpdu;
+	struct net_bridge *br;
+
+	if (br_timer_is_running(&p->hold_timer)) {
+		p->config_pending = 1;
+		return;
+	}
+
+	br = p->br;
+
+	bpdu.topology_change = br->topology_change;
+	bpdu.topology_change_ack = p->topology_change_ack;
+	bpdu.root = br->designated_root;
+	bpdu.root_path_cost = br->root_path_cost;
+	bpdu.bridge_id = br->bridge_id;
+	bpdu.port_id = p->port_id;
+	bpdu.message_age = 0;
+	if (!br_is_root_bridge(br)) {
+		struct net_bridge_port *root;
+		unsigned long age;
+
+		root = br_get_port(br, br->root_port);
+		age = br_timer_get_residue(&root->message_age_timer) + 1;
+		bpdu.message_age = age;
+	}
+	bpdu.max_age = br->max_age;
+	bpdu.hello_time = br->hello_time;
+	bpdu.forward_delay = br->forward_delay;
+
+	br_send_config_bpdu(p, &bpdu);
+
+	p->topology_change_ack = 0;
+	p->config_pending = 0;
+	br_timer_set(&p->hold_timer, jiffies);
+}
+
+/* called under bridge lock */
+static void br_record_config_information(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
+{
+	p->designated_root = bpdu->root;
+	p->designated_cost = bpdu->root_path_cost;
+	p->designated_bridge = bpdu->bridge_id;
+	p->designated_port = bpdu->port_id;
+
+	br_timer_set(&p->message_age_timer, jiffies - bpdu->message_age);
+}
+
+/* called under bridge lock */
+static void br_record_config_timeout_values(struct net_bridge *br, struct br_config_bpdu *bpdu)
+{
+	br->max_age = bpdu->max_age;
+	br->hello_time = bpdu->hello_time;
+	br->forward_delay = bpdu->forward_delay;
+	br->topology_change = bpdu->topology_change;
+}
+
+/* called under bridge lock */
+void br_transmit_tcn(struct net_bridge *br)
+{
+	br_send_tcn_bpdu(br_get_port(br, br->root_port));
+}
+
+/* called under bridge lock */
+static int br_should_become_designated_port(struct net_bridge_port *p)
+{
+	struct net_bridge *br;
+	int t;
+
+	br = p->br;
+	if (br_is_designated_port(p))
+		return 1;
+
+	if (memcmp(&p->designated_root, &br->designated_root, 8))
+		return 1;
+
+	if (br->root_path_cost < p->designated_cost)
+		return 1;
+	else if (br->root_path_cost > p->designated_cost)
+		return 0;
+
+	t = memcmp(&br->bridge_id, &p->designated_bridge, 8);
+	if (t < 0)
+		return 1;
+	else if (t > 0)
+		return 0;
+
+	if (p->port_id < p->designated_port)
+		return 1;
+
+	return 0;
+}
+
+/* called under bridge lock */
+static void br_designated_port_selection(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->state != BR_STATE_DISABLED &&
+		    br_should_become_designated_port(p))
+			br_become_designated_port(p);
+
+		p = p->next;
+	}
+}
+
+/* called under bridge lock */
+static int br_supersedes_port_info(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
+{
+	int t;
+
+	t = memcmp(&bpdu->root, &p->designated_root, 8);
+	if (t < 0)
+		return 1;
+	else if (t > 0)
+		return 0;
+
+	if (bpdu->root_path_cost < p->designated_cost)
+		return 1;
+	else if (bpdu->root_path_cost > p->designated_cost)
+		return 0;
+
+	t = memcmp(&bpdu->bridge_id, &p->designated_bridge, 8);
+	if (t < 0)
+		return 1;
+	else if (t > 0)
+		return 0;
+
+	if (memcmp(&bpdu->bridge_id, &p->br->bridge_id, 8))
+		return 1;
+
+	if (bpdu->port_id <= p->designated_port)
+		return 1;
+
+	return 0;
+}
+
+/* called under bridge lock */
+static void br_topology_change_acknowledged(struct net_bridge *br)
+{
+	br->topology_change_detected = 0;
+	br_timer_clear(&br->tcn_timer);
+}
+
+/* called under bridge lock */
+void br_topology_change_detection(struct net_bridge *br)
+{
+	printk(KERN_INFO "%s: topology change detected, ", br->name);
+
+	if (br_is_root_bridge(br)) {
+		printk("propagating\n");
+		br->topology_change = 1;
+		br_timer_set(&br->topology_change_timer, jiffies);
+	} else if (!br->topology_change_detected) {
+		printk("sending tcn bpdu\n");
+		br_transmit_tcn(br);
+		br_timer_set(&br->tcn_timer, jiffies);
+	}
+
+	br->topology_change_detected = 1;
+}
+
+/* called under bridge lock */
+void br_config_bpdu_generation(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->state != BR_STATE_DISABLED &&
+		    br_is_designated_port(p))
+			br_transmit_config(p);
+
+		p = p->next;
+	}
+}
+
+/* called under bridge lock */
+static void br_reply(struct net_bridge_port *p)
+{
+	br_transmit_config(p);
+}
+
+/* called under bridge lock */
+void br_configuration_update(struct net_bridge *br)
+{
+	br_root_selection(br);
+	br_designated_port_selection(br);
+}
+
+/* called under bridge lock */
+void br_become_designated_port(struct net_bridge_port *p)
+{
+	struct net_bridge *br;
+
+	br = p->br;
+	p->designated_root = br->designated_root;
+	p->designated_cost = br->root_path_cost;
+	p->designated_bridge = br->bridge_id;
+	p->designated_port = p->port_id;
+}
+
+/* called under bridge lock */
+static void br_make_blocking(struct net_bridge_port *p)
+{
+	if (p->state != BR_STATE_DISABLED &&
+	    p->state != BR_STATE_BLOCKING) {
+		if (p->state == BR_STATE_FORWARDING ||
+		    p->state == BR_STATE_LEARNING)
+			br_topology_change_detection(p->br);
+
+		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
+		       p->br->name, p->port_no, p->dev->name, "blocking");
+
+		p->state = BR_STATE_BLOCKING;
+		br_timer_clear(&p->forward_delay_timer);
+	}
+}
+
+/* called under bridge lock */
+static void br_make_forwarding(struct net_bridge_port *p)
+{
+	if (p->state == BR_STATE_BLOCKING) {
+		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
+		       p->br->name, p->port_no, p->dev->name, "listening");
+
+		p->state = BR_STATE_LISTENING;
+		br_timer_set(&p->forward_delay_timer, jiffies);
+	}
+}
+
+/* called under bridge lock */
+void br_port_state_selection(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->state != BR_STATE_DISABLED) {
+			if (p->port_no == br->root_port) {
+				p->config_pending = 0;
+				p->topology_change_ack = 0;
+				br_make_forwarding(p);
+			} else if (br_is_designated_port(p)) {
+				br_timer_clear(&p->message_age_timer);
+				br_make_forwarding(p);
+			} else {
+				p->config_pending = 0;
+				p->topology_change_ack = 0;
+				br_make_blocking(p);
+			}
+		}
+
+		p = p->next;
+	}
+}
+
+/* called under bridge lock */
+static void br_topology_change_acknowledge(struct net_bridge_port *p)
+{
+	p->topology_change_ack = 1;
+	br_transmit_config(p);
+}
+
+/* lock-safe */
+void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
+{
+	struct net_bridge *br;
+	int was_root;
+
+	if (p->state == BR_STATE_DISABLED)
+		return;
+
+	br = p->br;
+	read_lock(&br->lock);
+
+	was_root = br_is_root_bridge(br);
+	if (br_supersedes_port_info(p, bpdu)) {
+		br_record_config_information(p, bpdu);
+		br_configuration_update(br);
+		br_port_state_selection(br);
+
+		if (!br_is_root_bridge(br) && was_root) {
+			br_timer_clear(&br->hello_timer);
+			if (br->topology_change_detected) {
+				br_timer_clear(&br->topology_change_timer);
+				br_transmit_tcn(br);
+				br_timer_set(&br->tcn_timer, jiffies);
+			}
+		}
+
+		if (p->port_no == br->root_port) {
+			br_record_config_timeout_values(br, bpdu);
+			br_config_bpdu_generation(br);
+			if (bpdu->topology_change_ack)
+				br_topology_change_acknowledged(br);
+		}
+	} else if (br_is_designated_port(p)) {		
+		br_reply(p);		
+	}
+
+	read_unlock(&br->lock);
+}
+
+/* lock-safe */
+void br_received_tcn_bpdu(struct net_bridge_port *p)
+{
+	read_lock(&p->br->lock);
+	if (p->state != BR_STATE_DISABLED &&
+	    br_is_designated_port(p)) {
+		printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n",
+		       p->br->name, p->port_no, p->dev->name);
+
+		br_topology_change_detection(p->br);
+		br_topology_change_acknowledge(p);
+	}
+	read_unlock(&p->br->lock);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp_bpdu.c linux/net/bridge/br_stp_bpdu.c
--- v2.3.46/linux/net/bridge/br_stp_bpdu.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_stp_bpdu.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,191 @@
+/*
+ *	Spanning tree protocol; BPDU handling
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_stp_bpdu.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include "br_private.h"
+#include "br_private_stp.h"
+
+#define JIFFIES_TO_TICKS(j) (((j) << 8) / HZ)
+#define TICKS_TO_JIFFIES(j) (((j) * HZ) >> 8)
+
+static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int length)
+{
+	struct net_device *dev;
+	struct sk_buff *skb;
+	int size;
+
+	if (!p->br->stp_enabled)
+		return;
+
+	size = length + 2*ETH_ALEN + 2;
+	if (size < 60)
+		size = 60;
+
+	dev = p->dev;
+
+	if ((skb = dev_alloc_skb(size)) == NULL) {
+		printk(KERN_INFO "br: memory squeeze!\n");
+		return;
+	}
+
+	skb->dev = dev;
+	skb->mac.raw = skb_put(skb, size);
+	memcpy(skb->mac.raw, bridge_ula, ETH_ALEN);
+	memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN);
+	skb->mac.raw[2*ETH_ALEN] = 0;
+	skb->mac.raw[2*ETH_ALEN+1] = length;
+	skb->nh.raw = skb->mac.raw + 2*ETH_ALEN + 2;
+	memcpy(skb->nh.raw, data, length);
+	memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2);
+
+	dev_queue_xmit(skb);
+}
+
+static __inline__ void br_set_ticks(unsigned char *dest, int jiff)
+{
+	__u16 ticks;
+
+	ticks = JIFFIES_TO_TICKS(jiff);
+	dest[0] = (ticks >> 8) & 0xFF;
+	dest[1] = ticks & 0xFF;
+}
+
+static __inline__ int br_get_ticks(unsigned char *dest)
+{
+	return TICKS_TO_JIFFIES((dest[0] << 8) | dest[1]);
+}
+
+/* called under bridge lock */
+void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
+{
+	unsigned char buf[38];
+
+	buf[0] = 0x42;
+	buf[1] = 0x42;
+	buf[2] = 0x03;
+	buf[3] = 0;
+	buf[4] = 0;
+	buf[5] = 0;
+	buf[6] = BPDU_TYPE_CONFIG;
+	buf[7] = (bpdu->topology_change ? 0x01 : 0) |
+		(bpdu->topology_change_ack ? 0x80 : 0);
+	buf[8] = bpdu->root.prio[0];
+	buf[9] = bpdu->root.prio[1];
+	buf[10] = bpdu->root.addr[0];
+	buf[11] = bpdu->root.addr[1];
+	buf[12] = bpdu->root.addr[2];
+	buf[13] = bpdu->root.addr[3];
+	buf[14] = bpdu->root.addr[4];
+	buf[15] = bpdu->root.addr[5];
+	buf[16] = (bpdu->root_path_cost >> 24) & 0xFF;
+	buf[17] = (bpdu->root_path_cost >> 16) & 0xFF;
+	buf[18] = (bpdu->root_path_cost >> 8) & 0xFF;
+	buf[19] = bpdu->root_path_cost & 0xFF;
+	buf[20] = bpdu->bridge_id.prio[0];
+	buf[21] = bpdu->bridge_id.prio[1];
+	buf[22] = bpdu->bridge_id.addr[0];
+	buf[23] = bpdu->bridge_id.addr[1];
+	buf[24] = bpdu->bridge_id.addr[2];
+	buf[25] = bpdu->bridge_id.addr[3];
+	buf[26] = bpdu->bridge_id.addr[4];
+	buf[27] = bpdu->bridge_id.addr[5];
+	buf[28] = (bpdu->port_id >> 8) & 0xFF;
+	buf[29] = bpdu->port_id & 0xFF;
+
+	br_set_ticks(buf+30, bpdu->message_age);
+	br_set_ticks(buf+32, bpdu->max_age);
+	br_set_ticks(buf+34, bpdu->hello_time);
+	br_set_ticks(buf+36, bpdu->forward_delay);
+
+	br_send_bpdu(p, buf, 38);
+}
+
+/* called under bridge lock */
+void br_send_tcn_bpdu(struct net_bridge_port *p)
+{
+	unsigned char buf[7];
+
+	buf[0] = 0x42;
+	buf[1] = 0x42;
+	buf[2] = 0x03;
+	buf[3] = 0;
+	buf[4] = 0;
+	buf[5] = 0;
+	buf[6] = BPDU_TYPE_TCN;
+	br_send_bpdu(p, buf, 7);
+}
+
+static unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
+
+/* called under bridge lock */
+void br_stp_handle_bpdu(struct sk_buff *skb)
+{
+	unsigned char *buf;
+	struct net_bridge_port *p;
+
+	buf = skb->mac.raw + 14;
+	p = skb->dev->br_port;
+	if (!p->br->stp_enabled || memcmp(buf, header, 6)) {
+		kfree_skb(skb);
+		return;
+	}
+
+	if (buf[6] == BPDU_TYPE_CONFIG) {
+		struct br_config_bpdu bpdu;
+
+		bpdu.topology_change = (buf[7] & 0x01) ? 1 : 0;
+		bpdu.topology_change_ack = (buf[7] & 0x80) ? 1 : 0;
+		bpdu.root.prio[0] = buf[8];
+		bpdu.root.prio[1] = buf[9];
+		bpdu.root.addr[0] = buf[10];
+		bpdu.root.addr[1] = buf[11];
+		bpdu.root.addr[2] = buf[12];
+		bpdu.root.addr[3] = buf[13];
+		bpdu.root.addr[4] = buf[14];
+		bpdu.root.addr[5] = buf[15];
+		bpdu.root_path_cost =
+			(buf[16] << 24) |
+			(buf[17] << 16) |
+			(buf[18] << 8) |
+			buf[19];
+		bpdu.bridge_id.prio[0] = buf[20];
+		bpdu.bridge_id.prio[1] = buf[21];
+		bpdu.bridge_id.addr[0] = buf[22];
+		bpdu.bridge_id.addr[1] = buf[23];
+		bpdu.bridge_id.addr[2] = buf[24];
+		bpdu.bridge_id.addr[3] = buf[25];
+		bpdu.bridge_id.addr[4] = buf[26];
+		bpdu.bridge_id.addr[5] = buf[27];
+		bpdu.port_id = (buf[28] << 8) | buf[29];
+
+		bpdu.message_age = br_get_ticks(buf+30);
+		bpdu.max_age = br_get_ticks(buf+32);
+		bpdu.hello_time = br_get_ticks(buf+34);
+		bpdu.forward_delay = br_get_ticks(buf+36);
+
+		kfree_skb(skb);
+		br_received_config_bpdu(p, &bpdu);
+		return;
+	}
+
+	if (buf[6] == BPDU_TYPE_TCN) {
+		br_received_tcn_bpdu(p);
+		kfree_skb(skb);
+		return;
+	}
+
+	kfree_skb(skb);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp_if.c linux/net/bridge/br_stp_if.c
--- v2.3.46/linux/net/bridge/br_stp_if.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_stp_if.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,225 @@
+/*
+ *	Spanning tree protocol; interface code
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_stp_if.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+#include "br_private_stp.h"
+
+__u16 br_make_port_id(struct net_bridge_port *p)
+{
+	return (p->priority << 8) | p->port_no;
+}
+
+/* called under bridge lock */
+void br_init_port(struct net_bridge_port *p)
+{
+	p->port_id = br_make_port_id(p);
+	br_become_designated_port(p);
+	p->state = BR_STATE_BLOCKING;
+	p->topology_change_ack = 0;
+	p->config_pending = 0;
+	br_timer_clear(&p->message_age_timer);
+	br_timer_clear(&p->forward_delay_timer);
+	br_timer_clear(&p->hold_timer);
+}
+
+/* called under bridge lock */
+void br_stp_enable_bridge(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+	struct timer_list *timer = &br->tick;
+
+	init_timer(timer);
+	timer->data = (unsigned long) br;
+	timer->function = br_tick;
+	timer->expires = jiffies + 1;
+	add_timer(timer);
+
+	br_timer_set(&br->hello_timer, jiffies);
+	br_config_bpdu_generation(br);
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->dev->flags & IFF_UP)
+			br_stp_enable_port(p);
+
+		p = p->next;
+	}
+
+	br_timer_set(&br->gc_timer, jiffies);
+}
+
+/* called under bridge lock */
+void br_stp_disable_bridge(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+
+	br->topology_change = 0;
+	br->topology_change_detected = 0;
+	br_timer_clear(&br->hello_timer);
+	br_timer_clear(&br->topology_change_timer);
+	br_timer_clear(&br->tcn_timer);
+	br_timer_clear(&br->gc_timer);
+	br_fdb_cleanup(br);
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->state != BR_STATE_DISABLED)
+			br_stp_disable_port(p);
+
+		p = p->next;
+	}
+
+	del_timer(&br->tick);
+}
+
+/* called under bridge lock */
+void br_stp_enable_port(struct net_bridge_port *p)
+{
+	br_init_port(p);
+	br_port_state_selection(p->br);
+}
+
+/* called under bridge lock */
+void br_stp_disable_port(struct net_bridge_port *p)
+{
+	struct net_bridge *br;
+	int wasroot;
+
+	br = p->br;
+	printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
+	       br->name, p->port_no, p->dev->name, "disabled");
+
+	wasroot = br_is_root_bridge(br);
+	br_become_designated_port(p);
+	p->state = BR_STATE_DISABLED;
+	p->topology_change_ack = 0;
+	p->config_pending = 0;
+	br_timer_clear(&p->message_age_timer);
+	br_timer_clear(&p->forward_delay_timer);
+	br_timer_clear(&p->hold_timer);
+	br_configuration_update(br);
+	br_port_state_selection(br);
+
+	if (br_is_root_bridge(br) && !wasroot)
+		br_become_root_bridge(br);
+}
+
+/* called under bridge lock */
+static void br_stp_change_bridge_id(struct net_bridge *br, unsigned char *addr)
+{
+	unsigned char oldaddr[6];
+	struct net_bridge_port *p;
+	int wasroot;
+
+	wasroot = br_is_root_bridge(br);
+
+	memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN);
+	memcpy(br->bridge_id.addr, addr, ETH_ALEN);
+	memcpy(br->dev.dev_addr, addr, ETH_ALEN);
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (!memcmp(p->designated_bridge.addr, oldaddr, ETH_ALEN))
+			memcpy(p->designated_bridge.addr, addr, ETH_ALEN);
+
+		if (!memcmp(p->designated_root.addr, oldaddr, ETH_ALEN))
+			memcpy(p->designated_root.addr, addr, ETH_ALEN);
+
+		p = p->next;
+	}
+
+	br_configuration_update(br);
+	br_port_state_selection(br);
+	if (br_is_root_bridge(br) && !wasroot)
+		br_become_root_bridge(br);
+}
+
+static unsigned char br_mac_zero[6] = {0,0,0,0,0,0};
+
+/* called under bridge lock */
+void br_stp_recalculate_bridge_id(struct net_bridge *br)
+{
+	unsigned char *addr;
+	struct net_bridge_port *p;
+
+	addr = br_mac_zero;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (addr == br_mac_zero ||
+		    memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0)
+			addr = p->dev->dev_addr;
+
+		p = p->next;
+	}
+
+	if (memcmp(br->bridge_id.addr, addr, ETH_ALEN))
+		br_stp_change_bridge_id(br, addr);
+}
+
+/* called under bridge lock */
+void br_stp_set_bridge_priority(struct net_bridge *br, int newprio)
+{
+	struct net_bridge_port *p;
+	int wasroot;
+
+	wasroot = br_is_root_bridge(br);
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->state != BR_STATE_DISABLED &&
+		    br_is_designated_port(p)) {
+			p->designated_bridge.prio[0] = (newprio >> 8) & 0xFF;
+			p->designated_bridge.prio[1] = newprio & 0xFF;
+		}
+
+		p = p->next;
+	}
+
+	br->bridge_id.prio[0] = (newprio >> 8) & 0xFF;
+	br->bridge_id.prio[1] = newprio & 0xFF;
+	br_configuration_update(br);
+	br_port_state_selection(br);
+	if (br_is_root_bridge(br) && !wasroot)
+		br_become_root_bridge(br);
+}
+
+/* called under bridge lock */
+void br_stp_set_port_priority(struct net_bridge_port *p, int newprio)
+{
+	int new_port_id = ((newprio & 0xFF) << 8) | p->port_no;
+
+	if (br_is_designated_port(p))
+		p->designated_port = new_port_id;
+
+	p->port_id = new_port_id;
+	if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) &&
+	    p->port_id < p->designated_port) {
+		br_become_designated_port(p);
+		br_port_state_selection(p->br);
+	}
+}
+
+/* called under bridge lock */
+void br_stp_set_path_cost(struct net_bridge_port *p, int path_cost)
+{
+	p->path_cost = path_cost;
+	br_configuration_update(p->br);
+	br_port_state_selection(p->br);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp_timer.c linux/net/bridge/br_stp_timer.c
--- v2.3.46/linux/net/bridge/br_stp_timer.c	Wed Dec 31 16:00:00 1969
+++ linux/net/bridge/br_stp_timer.c	Sun Feb 20 10:41:18 2000
@@ -0,0 +1,184 @@
+/*
+ *	Spanning tree protocol; timer-related code
+ *	Linux ethernet bridge
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *
+ *	$Id: br_stp_timer.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_bridge.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+#include "br_private_stp.h"
+
+static void dump_bridge_id(bridge_id *id)
+{
+	printk("%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", id->prio[0],
+	       id->prio[1], id->addr[0], id->addr[1], id->addr[2], id->addr[3],
+	       id->addr[4], id->addr[5]);
+}
+
+/* called under bridge lock */
+static int br_is_designated_for_some_port(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->state != BR_STATE_DISABLED &&
+		    !memcmp(&p->designated_bridge, &br->bridge_id, 8))
+			return 1;
+
+		p = p->next;
+	}
+
+	return 0;
+}
+
+/* called under bridge lock */
+static void br_hello_timer_expired(struct net_bridge *br)
+{
+	br_config_bpdu_generation(br);
+	br_timer_set(&br->hello_timer, jiffies);
+}
+
+/* called under bridge lock */
+static void br_message_age_timer_expired(struct net_bridge_port *p)
+{
+	struct net_bridge *br;
+	int was_root;
+
+	br = p->br;
+	printk(KERN_INFO "%s: ", br->name);
+	printk("neighbour ");
+	dump_bridge_id(&p->designated_bridge);
+	printk(" lost on port %i(%s)\n", p->port_no, p->dev->name);
+
+	/*
+	 * According to the spec, the message age timer cannot be
+	 * running when we are the root bridge. So..  this was_root
+	 * check is redundant. I'm leaving it in for now, though.
+	 */
+	was_root = br_is_root_bridge(br);
+
+	br_become_designated_port(p);
+	br_configuration_update(br);
+	br_port_state_selection(br);
+	if (br_is_root_bridge(br) && !was_root)
+		br_become_root_bridge(br);
+}
+
+/* called under bridge lock */
+static void br_forward_delay_timer_expired(struct net_bridge_port *p)
+{
+	if (p->state == BR_STATE_LISTENING) {
+		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
+		       p->br->name, p->port_no, p->dev->name, "learning");
+
+		p->state = BR_STATE_LEARNING;
+		br_timer_set(&p->forward_delay_timer, jiffies);
+	} else if (p->state == BR_STATE_LEARNING) {
+		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
+		       p->br->name, p->port_no, p->dev->name, "forwarding");
+
+		p->state = BR_STATE_FORWARDING;
+		if (br_is_designated_for_some_port(p->br))
+			br_topology_change_detection(p->br);
+	}
+}
+
+/* called under bridge lock */
+static void br_tcn_timer_expired(struct net_bridge *br)
+{
+	printk(KERN_INFO "%s: retransmitting tcn bpdu\n", br->name);
+	br_transmit_tcn(br);
+	br_timer_set(&br->tcn_timer, jiffies);
+}
+
+/* called under bridge lock */
+static void br_topology_change_timer_expired(struct net_bridge *br)
+{
+	br->topology_change_detected = 0;
+	br->topology_change = 0;
+}
+
+/* called under bridge lock */
+static void br_hold_timer_expired(struct net_bridge_port *p)
+{
+	if (p->config_pending)
+		br_transmit_config(p);
+}
+
+/* called under bridge lock */
+static void br_check_port_timers(struct net_bridge_port *p)
+{
+	if (br_timer_has_expired(&p->message_age_timer, p->br->max_age)) {
+		br_timer_clear(&p->message_age_timer);
+		br_message_age_timer_expired(p);
+	}
+
+	if (br_timer_has_expired(&p->forward_delay_timer, p->br->forward_delay)) {
+		br_timer_clear(&p->forward_delay_timer);
+		br_forward_delay_timer_expired(p);
+	}
+
+	if (br_timer_has_expired(&p->hold_timer, BR_HOLD_TIME)) {
+		br_timer_clear(&p->hold_timer);
+		br_hold_timer_expired(p);
+	}
+}
+
+/* called under bridge lock */
+static void br_check_timers(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+
+	if (br_timer_has_expired(&br->gc_timer, br->gc_interval)) {
+		br_timer_set(&br->gc_timer, jiffies);
+		br_fdb_cleanup(br);
+	}
+
+	if (br_timer_has_expired(&br->hello_timer, br->hello_time)) {
+		br_timer_clear(&br->hello_timer);
+		br_hello_timer_expired(br);
+	}
+
+	if (br_timer_has_expired(&br->tcn_timer, br->bridge_hello_time)) {
+		br_timer_clear(&br->tcn_timer);
+		br_tcn_timer_expired(br);
+	}
+
+	if (br_timer_has_expired(&br->topology_change_timer, br->bridge_forward_delay + br->bridge_max_age)) {
+		br_timer_clear(&br->topology_change_timer);
+		br_topology_change_timer_expired(br);
+	}
+
+	p = br->port_list;
+	while (p != NULL) {
+		if (p->state != BR_STATE_DISABLED)
+			br_check_port_timers(p);
+
+		p = p->next;
+	}
+}
+
+void br_tick(unsigned long __data)
+{
+	struct net_bridge *br = (struct net_bridge *)__data;
+
+	read_lock(&br->lock);
+	br_check_timers(br);
+	read_unlock(&br->lock);
+
+	br->tick.expires = jiffies + 1;
+	add_timer(&br->tick);
+}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_tree.c linux/net/bridge/br_tree.c
--- v2.3.46/linux/net/bridge/br_tree.c	Wed Dec 29 13:13:21 1999
+++ linux/net/bridge/br_tree.c	Wed Dec 31 16:00:00 1969
@@ -1,501 +0,0 @@
-/*
- *	This code is derived from the avl functions in mmap.c
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/malloc.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-#include <net/br.h>
-#define _DEBUG_AVL
-
-/*
- * Use an AVL (Adelson-Velskii and Landis) tree to speed up this search
- * from O(n) to O(log n), where n is the number of ULAs.
- * Written by Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>.
- * Taken from mmap.c, extensively modified by John Hayes 
- * <hayes@netplumbing.com>
- * 98-02 Modified by Jean-Rene Peulve jr.peulve@aix.pacwan.net
- *		update port number when topology change
- *		return oldfdb when updating, for broadcast storm checking
- *		call addr_cmp once per node
- */
-
-static struct fdb fdb_head;
-static struct fdb *fhp = &fdb_head;
-static struct fdb **fhpp = &fhp;
-static int fdb_inited = 0;
-
-#ifdef DEBUG_AVL
-static void printk_avl (struct fdb * tree);
-#endif
-
-static int addr_cmp(unsigned char *a1, unsigned char *a2);
-
-/*
- * fdb_head is the AVL tree corresponding to fdb
- * or, more exactly, its root.
- * A fdb has the following fields:
- *   fdb_avl_left     left son of a tree node
- *   fdb_avl_right    right son of a tree node
- *   fdb_avl_height   1+max(heightof(left),heightof(right))
- * The empty tree is represented as NULL.
- */
- 
-#ifndef avl_br_empty
-#define avl_br_empty	(struct fdb *) NULL
-#endif
-
-/* Since the trees are balanced, their height will never be large. */
-#define avl_maxheight	127
-#define heightof(tree)	((tree) == avl_br_empty ? 0 : (tree)->fdb_avl_height)
-/*
- * Consistency and balancing rules:
- * 1. tree->fdb_avl_height == 1+max(heightof(tree->fdb_avl_left),heightof(tree->fdb_avl_right))
- * 2. abs( heightof(tree->fdb_avl_left) - heightof(tree->fdb_avl_right) ) <= 1
- * 3. foreach node in tree->fdb_avl_left: node->fdb_avl_key <= tree->fdb_avl_key,
- *    foreach node in tree->fdb_avl_right: node->fdb_avl_key >= tree->fdb_avl_key.
- */
-
-static int fdb_init(void)
-{
-	fdb_head.fdb_avl_height = 0;
-	fdb_head.fdb_avl_left = (struct fdb *)0;
-	fdb_head.fdb_avl_right = (struct fdb *)0;
-	fdb_inited = 1;
-	return(0);
-}
-
-struct fdb *br_avl_find_addr(unsigned char addr[6])
-{
-	struct fdb * result = NULL;
-	struct fdb * tree;
-
-	if (!fdb_inited)
-		fdb_init();
-#if (DEBUG_AVL)
-	printk("searching for ula %02x:%02x:%02x:%02x:%02x:%02x\n",
-		addr[0],
-		addr[1],
-		addr[2],
-		addr[3],
-		addr[4],
-		addr[5]);
-#endif /* DEBUG_AVL */
-	for (tree = fhp ; ; ) {
-		if (tree == avl_br_empty) {
-#if (DEBUG_AVL)
-			printk("search failed, returning node 0x%x\n", (unsigned int)result);
-#endif /* DEBUG_AVL */
-			return result;
-		}
-
-#if (DEBUG_AVL)
-		printk("node 0x%x: checking ula %02x:%02x:%02x:%02x:%02x:%02x\n",
-			(unsigned int)tree,
-			tree->ula[0],
-			tree->ula[1],
-			tree->ula[2],
-			tree->ula[3],
-			tree->ula[4],
-			tree->ula[5]);
-#endif /* DEBUG_AVL */
-		if (addr_cmp(addr, tree->ula) == 0) {
-#if (DEBUG_AVL)
-			printk("found node 0x%x\n", (unsigned int)tree);
-#endif /* DEBUG_AVL */
-			return tree;
-		}
-		if (addr_cmp(addr, tree->ula) < 0) {
-			tree = tree->fdb_avl_left;
-		} else {
-			tree = tree->fdb_avl_right;
-		}
-	}
-}
-
-
-/*
- * Rebalance a tree.
- * After inserting or deleting a node of a tree we have a sequence of subtrees
- * nodes[0]..nodes[k-1] such that
- * nodes[0] is the root and nodes[i+1] = nodes[i]->{fdb_avl_left|fdb_avl_right}.
- */
-static void br_avl_rebalance (struct fdb *** nodeplaces_ptr, int count)
-{
-	if (!fdb_inited)
-		fdb_init();
-	for ( ; count > 0 ; count--) {
-		struct fdb ** nodeplace = *--nodeplaces_ptr;
-		struct fdb * node = *nodeplace;
-		struct fdb * nodeleft = node->fdb_avl_left;
-		struct fdb * noderight = node->fdb_avl_right;
-		int heightleft = heightof(nodeleft);
-		int heightright = heightof(noderight);
-		if (heightright + 1 < heightleft) {
-			/*                                                      */
-			/*                            *                         */
-			/*                          /   \                       */
-			/*                       n+2      n                     */
-			/*                                                      */
-			struct fdb * nodeleftleft = nodeleft->fdb_avl_left;
-			struct fdb * nodeleftright = nodeleft->fdb_avl_right;
-			int heightleftright = heightof(nodeleftright);
-			if (heightof(nodeleftleft) >= heightleftright) {
-				/*                                                        */
-				/*                *                    n+2|n+3            */
-				/*              /   \                  /    \             */
-				/*           n+2      n      -->      /   n+1|n+2         */
-				/*           / \                      |    /    \         */
-				/*         n+1 n|n+1                 n+1  n|n+1  n        */
-				/*                                                        */
-				node->fdb_avl_left = nodeleftright; 
-				nodeleft->fdb_avl_right = node;
-				nodeleft->fdb_avl_height = 1 + (node->fdb_avl_height = 1 + heightleftright);
-				*nodeplace = nodeleft;
-			} else {
-				/*                                                        */
-				/*                *                     n+2               */
-				/*              /   \                 /     \             */
-				/*           n+2      n      -->    n+1     n+1           */
-				/*           / \                    / \     / \           */
-				/*          n  n+1                 n   L   R   n          */
-				/*             / \                                        */
-				/*            L   R                                       */
-				/*                                                        */
-				nodeleft->fdb_avl_right = nodeleftright->fdb_avl_left;
-				node->fdb_avl_left = nodeleftright->fdb_avl_right;
-				nodeleftright->fdb_avl_left = nodeleft;
-				nodeleftright->fdb_avl_right = node;
-				nodeleft->fdb_avl_height = node->fdb_avl_height = heightleftright;
-				nodeleftright->fdb_avl_height = heightleft;
-				*nodeplace = nodeleftright;
-			}
-		} else if (heightleft + 1 < heightright) {
-			/* similar to the above, just interchange 'left' <--> 'right' */
-			struct fdb * noderightright = noderight->fdb_avl_right;
-			struct fdb * noderightleft = noderight->fdb_avl_left;
-			int heightrightleft = heightof(noderightleft);
-			if (heightof(noderightright) >= heightrightleft) {
-				node->fdb_avl_right = noderightleft; 
-				noderight->fdb_avl_left = node;
-				noderight->fdb_avl_height = 1 + (node->fdb_avl_height = 1 + heightrightleft);
-				*nodeplace = noderight;
-			} else {
-				noderight->fdb_avl_left = noderightleft->fdb_avl_right;
-				node->fdb_avl_right = noderightleft->fdb_avl_left;
-				noderightleft->fdb_avl_right = noderight;
-				noderightleft->fdb_avl_left = node;
-				noderight->fdb_avl_height = node->fdb_avl_height = heightrightleft;
-				noderightleft->fdb_avl_height = heightright;
-				*nodeplace = noderightleft;
-			}
-		} else {
-			int height = (heightleft<heightright ? heightright : heightleft) + 1;
-			if (height == node->fdb_avl_height)
-				break;
-			node->fdb_avl_height = height;
-		}
-	}
-#ifdef DEBUG_AVL
-	printk_avl(&fdb_head);
-#endif /* DEBUG_AVL */
-}
-
-/* Insert a node into a tree.
- * Performance improvement:
- *	 call addr_cmp() only once per node and use result in a switch.
- * Return old node address if we knew that MAC address already
- * Return NULL if we insert the new node
- */
-struct fdb *br_avl_insert (struct fdb * new_node)
-{
-	struct fdb ** nodeplace = fhpp;
-	struct fdb ** stack[avl_maxheight];
-	int stack_count = 0;
-	struct fdb *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
-	if (!fdb_inited)
-		fdb_init();
-	for (;;) {
-		struct fdb *node;
-		
-		node = *nodeplace;
-		if (node == avl_br_empty)
-			break;
-		*stack_ptr++ = nodeplace; stack_count++;
-		switch(addr_cmp(new_node->ula, node->ula)) {
-		case 0: /* update */
-                   if (node->port == new_node->port) {
-			node->flags = new_node->flags;
-			node->timer = new_node->timer;	
-		   } else if (!(node->flags & FDB_ENT_VALID) &&
-				node->port) {
-			/* update fdb but never for local interfaces */
-#if (DEBUG_AVL)
-			printk("node 0x%x:port changed old=%d new=%d\n",
-				(unsigned int)node, node->port,new_node->port);
-#endif
-			/* JRP: update port as well if the topology change !
-			 * Don't do this while entry is still valid otherwise
-			 * a broadcast that we flooded and is reentered by another
-			 * port would mess up the good port number.
-			 * The fdb list per port needs to be updated as well.
-			 */
-			requeue_fdb(node, new_node->port);
-			node->flags = new_node->flags;
-			node->timer = new_node->timer;	
-#if (DEBUG_AVL)
-			printk_avl(&fdb_head);
-#endif /* DEBUG_AVL */
-		   }
-		   return node;		/* pass old fdb to caller */
-
-		case 1: /* new_node->ula > node->ula */
-		   nodeplace = &node->fdb_avl_right;
-		   break;
-		default: /* -1 => new_node->ula < node->ula */
-		   nodeplace = &node->fdb_avl_left;
-		}
-	}
-#if (DEBUG_AVL)
-	printk("node 0x%x: adding ula %02x:%02x:%02x:%02x:%02x:%02x\n",
-		(unsigned int)new_node,
-		new_node->ula[0],
-		new_node->ula[1],
-		new_node->ula[2],
-		new_node->ula[3],
-		new_node->ula[4],
-		new_node->ula[5]);
-#endif /* (DEBUG_AVL) */
-	new_node->fdb_avl_left = avl_br_empty;
-	new_node->fdb_avl_right = avl_br_empty;
-	new_node->fdb_avl_height = 1;
-	*nodeplace = new_node;
-	br_avl_rebalance(stack_ptr,stack_count);
-#ifdef DEBUG_AVL
-	printk_avl(&fdb_head);
-#endif /* DEBUG_AVL */
-	return NULL;		/* this is a new node */
-}
-
-
-/* Removes a node out of a tree. */
-static int br_avl_remove (struct fdb * node_to_delete)
-{
-	struct fdb ** nodeplace = fhpp;
-	struct fdb ** stack[avl_maxheight];
-	int stack_count = 0;
-	struct fdb *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
-	struct fdb ** nodeplace_to_delete;
-	if (!fdb_inited)
-		fdb_init();
-	for (;;) {
-		struct fdb * node = *nodeplace;
-		if (node == avl_br_empty) {
-			/* what? node_to_delete not found in tree? */
-			printk(KERN_ERR "br: avl_remove: node to delete not found in tree\n");
-			return(-1);
-		}
-		*stack_ptr++ = nodeplace; stack_count++;
-		if (addr_cmp(node_to_delete->ula, node->ula) == 0)
-				break;
-		if (addr_cmp(node_to_delete->ula, node->ula) < 0)
-			nodeplace = &node->fdb_avl_left;
-		else
-			nodeplace = &node->fdb_avl_right;
-	}
-	nodeplace_to_delete = nodeplace;
-	/* Have to remove node_to_delete = *nodeplace_to_delete. */
-	if (node_to_delete->fdb_avl_left == avl_br_empty) {
-		*nodeplace_to_delete = node_to_delete->fdb_avl_right;
-		stack_ptr--; stack_count--;
-	} else {
-		struct fdb *** stack_ptr_to_delete = stack_ptr;
-		struct fdb ** nodeplace = &node_to_delete->fdb_avl_left;
-		struct fdb * node;
-		for (;;) {
-			node = *nodeplace;
-			if (node->fdb_avl_right == avl_br_empty)
-				break;
-			*stack_ptr++ = nodeplace; stack_count++;
-			nodeplace = &node->fdb_avl_right;
-		}
-		*nodeplace = node->fdb_avl_left;
-		/* node replaces node_to_delete */
-		node->fdb_avl_left = node_to_delete->fdb_avl_left;
-		node->fdb_avl_right = node_to_delete->fdb_avl_right;
-		node->fdb_avl_height = node_to_delete->fdb_avl_height;
-		*nodeplace_to_delete = node; /* replace node_to_delete */
-		*stack_ptr_to_delete = &node->fdb_avl_left; /* replace &node_to_delete->fdb_avl_left */
-	}
-	br_avl_rebalance(stack_ptr,stack_count);
-	return(0);
-}
-
-#ifdef DEBUG_AVL
-
-/* print a tree */
-static void printk_avl (struct fdb * tree)
-{
-	if (tree != avl_br_empty) {
-		printk("(");
-		printk("%02x:%02x:%02x:%02x:%02x:%02x(%d)",
-			tree->ula[0],
-			tree->ula[1],
-			tree->ula[2],
-			tree->ula[3],
-			tree->ula[4],
-			tree->ula[5],
-			tree->port);
-		if (tree->fdb_avl_left != avl_br_empty) {
-			printk_avl(tree->fdb_avl_left);
-			printk("<");
-		}
-		if (tree->fdb_avl_right != avl_br_empty) {
-			printk(">");
-			printk_avl(tree->fdb_avl_right);
-		}
-		printk(")\n");
-	}
-}
-
-static char *avl_check_point = "somewhere";
-
-/* check a tree's consistency and balancing */
-static void avl_checkheights (struct fdb * tree)
-{
-	int h, hl, hr;
-
-	if (tree == avl_br_empty)
-		return;
-	avl_checkheights(tree->fdb_avl_left);
-	avl_checkheights(tree->fdb_avl_right);
-	h = tree->fdb_avl_height;
-	hl = heightof(tree->fdb_avl_left);
-	hr = heightof(tree->fdb_avl_right);
-	if ((h == hl+1) && (hr <= hl) && (hl <= hr+1))
-		return;
-	if ((h == hr+1) && (hl <= hr) && (hr <= hl+1))
-		return;
-	printk("%s: avl_checkheights: heights inconsistent\n",avl_check_point);
-}
-
-/* check that all values stored in a tree are < key */
-static void avl_checkleft (struct fdb * tree, fdb_avl_key_t key)
-{
-	if (tree == avl_br_empty)
-		return;
-	avl_checkleft(tree->fdb_avl_left,key);
-	avl_checkleft(tree->fdb_avl_right,key);
-	if (tree->fdb_avl_key < key)
-		return;
-	printk("%s: avl_checkleft: left key %lu >= top key %lu\n",avl_check_point,tree->fdb_avl_key,key);
-}
-
-/* check that all values stored in a tree are > key */
-static void avl_checkright (struct fdb * tree, fdb_avl_key_t key)
-{
-	if (tree == avl_br_empty)
-		return;
-	avl_checkright(tree->fdb_avl_left,key);
-	avl_checkright(tree->fdb_avl_right,key);
-	if (tree->fdb_avl_key > key)
-		return;
-	printk("%s: avl_checkright: right key %lu <= top key %lu\n",avl_check_point,tree->fdb_avl_key,key);
-}
-
-/* check that all values are properly increasing */
-static void avl_checkorder (struct fdb * tree)
-{
-	if (tree == avl_br_empty)
-		return;
-	avl_checkorder(tree->fdb_avl_left);
-	avl_checkorder(tree->fdb_avl_right);
-	avl_checkleft(tree->fdb_avl_left,tree->fdb_avl_key);
-	avl_checkright(tree->fdb_avl_right,tree->fdb_avl_key);
-}
-
-#endif /* DEBUG_AVL */
-
-static int addr_cmp(unsigned char a1[], unsigned char a2[])
-{
-	int i;
-
-	for (i=0; i<6; i++) {
-		if (a1[i] > a2[i]) return(1);
-		if (a1[i] < a2[i]) return(-1);
-	}
-	return(0);
-}
-
-/* Vova Oksman: function for copy tree to the buffer */
-void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,
-					int* len, off_t offset, int length)
-{
-	int size;
-
-	if( 0 == *pos){
-		if(avl_br_empty == tree)
-		/* begin from the root */
-			tree = fhp;
-		*pos = *len;
-	}
-
-	if (*pos >= offset+length)
-		return;
-
-	if (tree != avl_br_empty) {
-		/* don't write the local device */
-		if(tree->port != 0){
-			size = sprintf(*pbuffer,
-				   "%02x:%02x:%02x:%02x:%02x:%02x     %s       %d         %ld\n",
-				   tree->ula[0],tree->ula[1],tree->ula[2],
-				   tree->ula[3],tree->ula[4],tree->ula[5], 
-				   port_info[tree->port].dev->name, tree->flags,CURRENT_TIME-tree->timer);
-
-			(*pos)+=size;
-			(*len)+=size;
-			(*pbuffer)+=size;
-		}
-		if (*pos <= offset)
-			*len=0;
-
-		if (tree->fdb_avl_left != avl_br_empty) {
-			sprintf_avl (pbuffer,tree->fdb_avl_left,pos,len,offset,length);
-		}
-		if (tree->fdb_avl_right != avl_br_empty) {
-			sprintf_avl (pbuffer,tree->fdb_avl_right,pos,len,offset,length);
-		}
-
-	}
-
-	return;
-}
-
-/*
- * Delete all nodes learnt by the port
- */
-void br_avl_delete_by_port(int port)
-{
-        struct fdb *fdb, *next;
-
-	if (!fdb_inited)
-		fdb_init();
-
-        for(fdb = port_info[port].fdb; fdb != NULL; fdb = next) {
-                next = fdb->fdb_next;
-                br_avl_remove(fdb);
-        }
-        port_info[port].fdb = NULL;
-
-        /* remove the local mac too */
-/*        next = br_avl_find_addr(port_info[port].dev->dev_addr); */
-        next = br_avl_find_addr(port_info[port].ifmac.BRIDGE_ID_ULA);
-        if (next != NULL)
-                br_avl_remove(next);
-
-        return;
-}
diff -u --recursive --new-file v2.3.46/linux/net/bridge/sysctl_net_bridge.c linux/net/bridge/sysctl_net_bridge.c
--- v2.3.46/linux/net/bridge/sysctl_net_bridge.c	Mon Jun  3 02:42:41 1996
+++ linux/net/bridge/sysctl_net_bridge.c	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/* -*- linux-c -*-
- * sysctl_net_bridge.c: sysctl interface to net bridge subsystem.
- *
- * Begun June 1, 1996, Mike Shaver.
- * Added /proc/sys/net/bridge directory entry (empty =) ). [MS]
- */
-
-#include <linux/mm.h>
-#include <linux/sysctl.h>
-
-ctl_table bridge_table[] = {
-	{0}
-};
diff -u --recursive --new-file v2.3.46/linux/net/core/dev.c linux/net/core/dev.c
--- v2.3.46/linux/net/core/dev.c	Sun Feb 13 19:29:04 2000
+++ linux/net/core/dev.c	Sun Feb 20 20:14:55 2000
@@ -81,7 +81,7 @@
 #include <net/slhc.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
-#include <net/br.h>
+#include <linux/if_bridge.h>
 #include <net/dst.h>
 #include <net/pkt_sched.h>
 #include <net/profile.h>
@@ -190,14 +190,11 @@
 		dev_clear_fastroute(pt->dev);
 	}
 #endif
-	if(pt->type==htons(ETH_P_ALL))
-	{
+	if (pt->type == htons(ETH_P_ALL)) {
 		netdev_nit++;
 		pt->next=ptype_all;
 		ptype_all=pt;
-	}
-	else
-	{	
+	} else {
 		hash=ntohs(pt->type)&15;
 		pt->next = ptype_base[hash];
 		ptype_base[hash] = pt;
@@ -216,19 +213,16 @@
 
 	write_lock_bh(&ptype_lock);
 
-	if(pt->type==htons(ETH_P_ALL))
-	{
+	if (pt->type == htons(ETH_P_ALL)) {
 		netdev_nit--;
 		pt1=&ptype_all;
-	}
-	else
+	} else {
 		pt1=&ptype_base[ntohs(pt->type)&15];
+	}
 
-	for(; (*pt1)!=NULL; pt1=&((*pt1)->next))
-	{
-		if(pt==(*pt1))
-		{
-			*pt1=pt->next;
+	for (; (*pt1) != NULL; pt1 = &((*pt1)->next)) {
+		if (pt == (*pt1)) {
+			*pt1 = pt->next;
 #ifdef CONFIG_NET_FASTROUTE
 			if (pt->data)
 				netdev_fastroute_obstacles--;
@@ -357,14 +351,13 @@
 {
 	int i;
 	char buf[32];
+
 	/*
 	 *	If you need over 100 please also fix the algorithm...
 	 */
-	for(i=0;i<100;i++)
-	{
+	for (i = 0; i < 100; i++) {
 		sprintf(buf,name,i);
-		if(__dev_get_by_name(buf)==NULL)
-		{
+		if (__dev_get_by_name(buf) == NULL) {
 			strcpy(dev->name, buf);
 			return i;
 		}
@@ -375,16 +368,14 @@
 struct net_device *dev_alloc(const char *name, int *err)
 {
 	struct net_device *dev=kmalloc(sizeof(struct net_device)+16, GFP_KERNEL);
-	if(dev==NULL)
-	{
-		*err=-ENOBUFS;
+	if (dev == NULL) {
+		*err = -ENOBUFS;
 		return NULL;
 	}
 	memset(dev, 0, sizeof(struct net_device));
-	dev->name=(char *)(dev+1);	/* Name string space */
-	*err=dev_alloc_name(dev,name);
-	if(*err<0)
-	{
+	dev->name = (char *)(dev + 1);	/* Name string space */
+	*err = dev_alloc_name(dev, name);
+	if (*err < 0) {
 		kfree(dev);
 		return NULL;
 	}
@@ -408,7 +399,7 @@
 
 void dev_load(const char *name)
 {
-	if(!__dev_get_by_name(name) && capable(CAP_SYS_MODULE))
+	if (!__dev_get_by_name(name) && capable(CAP_SYS_MODULE))
 		request_module(name);
 }
 
@@ -441,6 +432,12 @@
 		return 0;
 
 	/*
+	 *	Is it even present?
+	 */
+	if (!netif_device_present(dev))
+		return -ENODEV;
+
+	/*
 	 *	Call device private open method
 	 */
 	 
@@ -458,7 +455,7 @@
 		 */
 		dev->flags |= IFF_UP;
 
-		set_bit(LINK_STATE_START, &dev->state);
+		set_bit(__LINK_STATE_START, &dev->state);
 
 		/*
 		 *	Initialize multicasting status 
@@ -528,11 +525,14 @@
 
 	dev_deactivate(dev);
 
-	clear_bit(LINK_STATE_START, &dev->state);
+	clear_bit(__LINK_STATE_START, &dev->state);
 
 	/*
 	 *	Call the device specific close. This cannot fail.
 	 *	Only if device is UP
+	 *
+	 *	We allow it to be called even after a DETACH hot-plug
+	 *	event.
 	 */
 	 
 	if (dev->stop)
@@ -673,7 +673,7 @@
 			spin_lock(&dev->xmit_lock);
 			dev->xmit_lock_owner = cpu;
 
-			if (!test_bit(LINK_STATE_XOFF, &dev->state)) {
+			if (!netif_queue_stopped(dev)) {
 				if (netdev_nit)
 					dev_queue_xmit_nit(skb,dev);
 
@@ -781,7 +781,7 @@
 	struct softnet_data *queue;
 	unsigned long flags;
 
-	if(skb->stamp.tv_sec==0)
+	if (skb->stamp.tv_sec == 0)
 		get_fast_time(&skb->stamp);
 
 	/* The code is rearranged so that the path is the most
@@ -833,37 +833,6 @@
 	kfree_skb(skb);
 }
 
-#ifdef CONFIG_BRIDGE
-static inline void handle_bridge(struct sk_buff *skb, unsigned short type)
-{
-	/* 
-	 * The br_stats.flags is checked here to save the expense of a 
-	 * function call.
-	 */
-	if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type))
-	{
-		/*
-		 *	We pass the bridge a complete frame. This means
-		 *	recovering the MAC header first.
-		 */
-		
-		int offset;
-
-		skb=skb_clone(skb, GFP_ATOMIC);
-		if(skb==NULL)		
-			return;
-			
-		offset=skb->data-skb->mac.raw;
-		skb_push(skb,offset);	/* Put header back on for bridge */
-
-		if(br_receive_frame(skb))
-			return;
-		kfree_skb(skb);
-	}
-	return;
-}
-#endif
-
 /* Deliver skb to an old protocol, which is not threaded well
    or which do not understand shared skbs.
  */
@@ -941,7 +910,7 @@
 			struct net_device *dev = head;
 			head = head->next_sched;
 
-			clear_bit(LINK_STATE_SCHED, &dev->state);
+			clear_bit(__LINK_STATE_SCHED, &dev->state);
 
 			if (spin_trylock(&dev->queue_lock)) {
 				qdisc_run(dev);
@@ -953,6 +922,32 @@
 	}
 }
 
+void net_call_rx_atomic(void (*fn)(void))
+{
+	write_lock_bh(&ptype_lock);
+	fn();
+	write_unlock_bh(&ptype_lock);
+}
+
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
+#endif
+
+#define HANDLE_BRIDGE(SKB, PT_PREV)					\
+do {									\
+	if ((SKB)->dev->br_port != NULL &&				\
+	    br_handle_frame_hook != NULL) {				\
+		if (PT_PREV)						\
+			if (!(PT_PREV->data))				\
+				deliver_to_old_ones(PT_PREV, SKB, 1);	\
+			else						\
+				pt_prev->func(SKB, SKB->dev, PT_PREV);	\
+									\
+		br_handle_frame_hook(SKB);				\
+		continue;						\
+	}								\
+} while(0)
+
 static void net_rx_action(struct softirq_action *h)
 {
 	int this_cpu = smp_processor_id();
@@ -985,9 +980,7 @@
 		{
 			struct packet_type *ptype, *pt_prev;
 			unsigned short type = skb->protocol;
-#ifdef CONFIG_BRIDGE
-			handle_bridge(skb, type);
-#endif
+
 			pt_prev = NULL;
 			for (ptype = ptype_all; ptype; ptype = ptype->next) {
 				if (!ptype->dev || ptype->dev == skb->dev) {
@@ -1004,6 +997,11 @@
 					pt_prev = ptype;
 				}
 			}
+
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+			HANDLE_BRIDGE(skb, pt_prev);
+#endif
+
 			for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
 				if (ptype->type == type &&
 				    (!ptype->dev || ptype->dev == skb->dev)) {
@@ -1020,6 +1018,7 @@
 					pt_prev = ptype;
 				}
 			}
+
 			if (pt_prev) {
 				if (!pt_prev->data)
 					deliver_to_old_ones(pt_prev, skb, 1);
@@ -1212,11 +1211,10 @@
  
 static int dev_get_info(char *buffer, char **start, off_t offset, int length)
 {
-	int len=0;
-	off_t begin=0;
-	off_t pos=0;
+	int len = 0;
+	off_t begin = 0;
+	off_t pos = 0;
 	int size;
-	
 	struct net_device *dev;
 
 
@@ -1224,31 +1222,31 @@
 		"Inter-|   Receive                                                |  Transmit\n"
 		" face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n");
 	
-	pos+=size;
-	len+=size;
+	pos += size;
+	len += size;
 	
 
 	read_lock(&dev_base_lock);
 	for (dev = dev_base; dev != NULL; dev = dev->next) {
 		size = sprintf_stats(buffer+len, dev);
-		len+=size;
-		pos=begin+len;
+		len += size;
+		pos = begin + len;
 				
-		if(pos<offset) {
-			len=0;
-			begin=pos;
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
 		}
-		if(pos>offset+length)
+		if (pos > offset + length)
 			break;
 	}
 	read_unlock(&dev_base_lock);
 
-	*start=buffer+(offset-begin);	/* Start of wanted data */
-	len-=(offset-begin);		/* Start slop */
-	if(len>length)
-		len=length;		/* Ending slop */
-	if (len<0)
-		len=0;
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);		/* Start slop */
+	if (len > length)
+		len = length;			/* Ending slop */
+	if (len < 0)
+		len = 0;
 	return len;
 }
 
@@ -1280,7 +1278,7 @@
 
 	if (len > length)
 		len = length;
-	if(len < 0)
+	if (len < 0)
 		len = 0;
 
 	*start = buffer + offset;
@@ -1307,8 +1305,7 @@
 				       (struct iw_statistics *) NULL);
 	int size;
 
-	if(stats != (struct iw_statistics *) NULL)
-	{
+	if (stats != (struct iw_statistics *) NULL) {
 		size = sprintf(buffer,
 			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d\n",
 			       dev->name,
@@ -1349,30 +1346,30 @@
 		       " face | tus | link level noise |  nwid  crypt   misc\n"
 			);
 	
-	pos+=size;
-	len+=size;
+	pos += size;
+	len += size;
 
 	read_lock(&dev_base_lock);
-	for(dev = dev_base; dev != NULL; dev = dev->next) {
-		size = sprintf_wireless_stats(buffer+len, dev);
-		len+=size;
-		pos=begin+len;
-
-		if(pos < offset) {
-			len=0;
-			begin=pos;
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		size = sprintf_wireless_stats(buffer + len, dev);
+		len += size;
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
 		}
-		if(pos > offset + length)
+		if (pos > offset + length)
 			break;
 	}
 	read_unlock(&dev_base_lock);
 
 	*start = buffer + (offset - begin);	/* Start of wanted data */
 	len -= (offset - begin);		/* Start slop */
-	if(len > length)
-		len = length;		/* Ending slop */
-	if (len<0)
-		len=0;
+	if (len > length)
+		len = length;			/* Ending slop */
+	if (len < 0)
+		len = 0;
 
 	return len;
 }
@@ -1516,7 +1513,7 @@
 		case SIOCGIFFLAGS:	/* Get interface flags */
 			ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI|IFF_RUNNING))
 				|(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));
-			if (!test_bit(LINK_STATE_DOWN, &dev->state))
+			if (netif_running(dev))
 				ifr->ifr_flags |= IFF_RUNNING;
 			return 0;
 
@@ -1545,6 +1542,9 @@
 			if (ifr->ifr_mtu<0)
 				return -EINVAL;
 
+			if (!netif_device_present(dev))
+				return -ENODEV;
+
 			if (dev->change_mtu)
 				err = dev->change_mtu(dev, ifr->ifr_mtu);
 			else {
@@ -1561,17 +1561,19 @@
 			return 0;
 				
 		case SIOCSIFHWADDR:
-			if(dev->set_mac_address==NULL)
+			if (dev->set_mac_address == NULL)
 				return -EOPNOTSUPP;
-			if(ifr->ifr_hwaddr.sa_family!=dev->type)
+			if (ifr->ifr_hwaddr.sa_family!=dev->type)
 				return -EINVAL;
-			err=dev->set_mac_address(dev,&ifr->ifr_hwaddr);
+			if (!netif_device_present(dev))
+				return -ENODEV;
+			err = dev->set_mac_address(dev, &ifr->ifr_hwaddr);
 			if (!err)
 				notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
 			return err;
 			
 		case SIOCSIFHWBROADCAST:
-			if(ifr->ifr_hwaddr.sa_family!=dev->type)
+			if (ifr->ifr_hwaddr.sa_family!=dev->type)
 				return -EINVAL;
 			memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN);
 			notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
@@ -1587,21 +1589,28 @@
 			return 0;
 			
 		case SIOCSIFMAP:
-			if (dev->set_config)
+			if (dev->set_config) {
+				if (!netif_device_present(dev))
+					return -ENODEV;
 				return dev->set_config(dev,&ifr->ifr_map);
+			}
 			return -EOPNOTSUPP;
 			
 		case SIOCADDMULTI:
-			if(dev->set_multicast_list==NULL ||
-			   ifr->ifr_hwaddr.sa_family!=AF_UNSPEC)
+			if (dev->set_multicast_list == NULL ||
+			    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
 				return -EINVAL;
+			if (!netif_device_present(dev))
+				return -ENODEV;
 			dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1);
 			return 0;
 
 		case SIOCDELMULTI:
-			if(dev->set_multicast_list==NULL ||
-			   ifr->ifr_hwaddr.sa_family!=AF_UNSPEC)
+			if (dev->set_multicast_list == NULL ||
+			    ifr->ifr_hwaddr.sa_family!=AF_UNSPEC)
 				return -EINVAL;
+			if (!netif_device_present(dev))
+				return -ENODEV;
 			dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1);
 			return 0;
 
@@ -1614,7 +1623,7 @@
 			return 0;
 
 		case SIOCSIFTXQLEN:
-			if(ifr->ifr_qlen<0)
+			if (ifr->ifr_qlen<0)
 				return -EINVAL;
 			dev->tx_queue_len = ifr->ifr_qlen;
 			return 0;
@@ -1634,17 +1643,23 @@
 		 */
 
 		default:
-			if(cmd >= SIOCDEVPRIVATE &&
-			   cmd <= SIOCDEVPRIVATE + 15) {
-				if (dev->do_ioctl)
+			if (cmd >= SIOCDEVPRIVATE &&
+			    cmd <= SIOCDEVPRIVATE + 15) {
+				if (dev->do_ioctl) {
+					if (!netif_device_present(dev))
+						return -ENODEV;
 					return dev->do_ioctl(dev, ifr, cmd);
+				}
 				return -EOPNOTSUPP;
 			}
 
 #ifdef WIRELESS_EXT
-			if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				if (dev->do_ioctl)
+			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
+				if (dev->do_ioctl) {
+					if (!netif_device_present(dev))
+						return -ENODEV;
 					return dev->do_ioctl(dev, ifr, cmd);
+				}
 				return -EOPNOTSUPP;
 			}
 #endif	/* WIRELESS_EXT */
@@ -1868,6 +1883,13 @@
 	if (dev->rebuild_header == NULL)
 		dev->rebuild_header = default_rebuild_header;
 
+	/*
+	 *	Default initial state at registry is that the
+	 *	device is present.
+	 */
+
+	set_bit(__LINK_STATE_PRESENT, &dev->state);
+
 	dev->next = NULL;
 	dev_init_scheduler(dev);
 	write_lock_bh(&dev_base_lock);
@@ -2048,15 +2070,6 @@
 		queue->completion_queue = NULL;
 	}
 	
-	/*
-	 *	The bridge has to be up before the devices
-	 */
-
-#ifdef CONFIG_BRIDGE	 
-	br_init();
-#endif	
-	
-
 #ifdef CONFIG_NET_PROFILE
 	net_profile_init();
 	NET_PROFILE_REGISTER(dev_queue_xmit);
@@ -2124,22 +2137,11 @@
 	dst_init();
 	dev_mcast_init();
 
-#ifdef CONFIG_BRIDGE
-	/*
-	 * Register any statically linked ethernet devices with the bridge
-	 */
-	br_spacedevice_register();
-#endif
-
 	/*
 	 *	Initialise network devices
 	 */
 	 
 	net_device_init();
-
-#ifdef CONFIG_IP_PNP
-	ip_auto_config();
-#endif
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.46/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c
--- v2.3.46/linux/net/core/dev_mcast.c	Mon Nov  1 13:56:27 1999
+++ linux/net/core/dev_mcast.c	Thu Feb 17 09:18:47 2000
@@ -71,17 +71,20 @@
 void dev_mc_upload(struct net_device *dev)
 {
 	/* Don't do anything till we up the interface
-	   [dev_open will call this function so the list will
-	    stay sane] */
+	 * [dev_open will call this function so the list will
+	 * stay sane]
+	 */
 
-	if(!(dev->flags&IFF_UP))
+	if (!(dev->flags&IFF_UP))
 		return;
 
 	/*
-	 *	Devices with no set multicast don't get set 
+	 *	Devices with no set multicast or which have been
+	 *	detached don't get set.
 	 */
 
-	if(dev->set_multicast_list==NULL)
+	if (dev->set_multicast_list == NULL ||
+	    !netif_device_present(dev))
 		return;
 
 	read_lock_bh(&dev_mc_lock);
@@ -103,19 +106,20 @@
 	struct dev_mc_list *dmi, **dmip;
 
 	write_lock_bh(&dev_mc_lock);
-	for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
+	for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
 		/*
 		 *	Find the entry we want to delete. The device could
 		 *	have variable length entries so check these too.
 		 */
-		if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && alen==dmi->dmi_addrlen) {
+		if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
+		    alen == dmi->dmi_addrlen) {
 			if (glbl) {
 				int old_glbl = dmi->dmi_gusers;
 				dmi->dmi_gusers = 0;
 				if (old_glbl == 0)
 					break;
 			}
-			if(--dmi->dmi_users)
+			if (--dmi->dmi_users)
 				goto done;
 
 			/*
@@ -125,7 +129,7 @@
 			dev->mc_count--;
 			write_unlock_bh(&dev_mc_lock);
 
-			kfree_s(dmi,sizeof(*dmi));
+			kfree_s(dmi, sizeof(*dmi));
 
 			/*
 			 *	We have altered the list, so the card
@@ -153,8 +157,9 @@
 	dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC);
 
 	write_lock_bh(&dev_mc_lock);
-	for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) {
-		if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) {
+	for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+		if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
+		    dmi->dmi_addrlen == alen) {
 			if (glbl) {
 				int old_glbl = dmi->dmi_gusers;
 				dmi->dmi_gusers = 1;
@@ -166,16 +171,16 @@
 		}
 	}
 
-	if ((dmi=dmi1)==NULL) {
+	if ((dmi = dmi1) == NULL) {
 		write_unlock_bh(&dev_mc_lock);
 		return -ENOMEM;
 	}
 	memcpy(dmi->dmi_addr, addr, alen);
-	dmi->dmi_addrlen=alen;
-	dmi->next=dev->mc_list;
-	dmi->dmi_users=1;
-	dmi->dmi_gusers=glbl ? 1 : 0;
-	dev->mc_list=dmi;
+	dmi->dmi_addrlen = alen;
+	dmi->next = dev->mc_list;
+	dmi->dmi_users = 1;
+	dmi->dmi_gusers = glbl ? 1 : 0;
+	dev->mc_list = dmi;
 	dev->mc_count++;
 	write_unlock_bh(&dev_mc_lock);
 	dev_mc_upload(dev);
@@ -195,14 +200,14 @@
 void dev_mc_discard(struct net_device *dev)
 {
 	write_lock_bh(&dev_mc_lock);
-	while (dev->mc_list!=NULL) {
-		struct dev_mc_list *tmp=dev->mc_list;
-		dev->mc_list=tmp->next;
+	while (dev->mc_list != NULL) {
+		struct dev_mc_list *tmp = dev->mc_list;
+		dev->mc_list = tmp->next;
 		if (tmp->dmi_users > tmp->dmi_gusers)
 			printk("dev_mc_discard: multicast leakage! dmi_users=%d\n", tmp->dmi_users);
-		kfree_s(tmp,sizeof(*tmp));
+		kfree_s(tmp, sizeof(*tmp));
 	}
-	dev->mc_count=0;
+	dev->mc_count = 0;
 	write_unlock_bh(&dev_mc_lock);
 }
 
@@ -210,9 +215,9 @@
 static int dev_mc_read_proc(char *buffer, char **start, off_t offset,
 			    int length, int *eof, void *data)
 {
-	off_t pos=0, begin=0;
+	off_t pos = 0, begin = 0;
 	struct dev_mc_list *m;
-	int len=0;
+	int len = 0;
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
@@ -221,20 +226,20 @@
 		for (m = dev->mc_list; m; m = m->next) {
 			int i;
 
-			len += sprintf(buffer+len,"%-4d %-15s %-5d %-5d ", dev->ifindex, dev->name,
-				       m->dmi_users, m->dmi_gusers);
+			len += sprintf(buffer+len,"%-4d %-15s %-5d %-5d ", dev->ifindex,
+				       dev->name, m->dmi_users, m->dmi_gusers);
 
-			for (i=0; i<m->dmi_addrlen; i++)
+			for (i = 0; i < m->dmi_addrlen; i++)
 				len += sprintf(buffer+len, "%02x", m->dmi_addr[i]);
 
-			len+=sprintf(buffer+len, "\n");
+			len += sprintf(buffer+len, "\n");
 
-			pos=begin+len;
+			pos = begin + len;
 			if (pos < offset) {
-				len=0;
-				begin=pos;
+				len = 0;
+				begin = pos;
 			}
-			if (pos > offset+length) {
+			if (pos > offset + length) {
 				read_unlock_bh(&dev_mc_lock);
 				goto done;
 			}
@@ -245,12 +250,12 @@
 
 done:
 	read_unlock(&dev_base_lock);
-	*start=buffer+(offset-begin);
-	len-=(offset-begin);
-	if(len>length)
-		len=length;
-	if(len<0)
-		len=0;
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+	if (len > length)
+		len = length;
+	if (len < 0)
+		len = 0;
 	return len;
 }
 #endif
diff -u --recursive --new-file v2.3.46/linux/net/core/profile.c linux/net/core/profile.c
--- v2.3.46/linux/net/core/profile.c	Mon Nov  1 13:56:27 1999
+++ linux/net/core/profile.c	Sun Feb 20 20:21:25 2000
@@ -271,12 +271,6 @@
 	register_netdevice(&whitehole_dev);
 
 	printk("Evaluating net profiler cost ...");
-#if CPU == 586 || CPU == 686
-	if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC)) {
-		printk(KERN_ERR "Sorry, your CPU does not support TSC. Net profiler disabled.\n");
-		return -1;
-	}
-#endif
 #ifdef __alpha__
 	alpha_tick(0);
 #endif
diff -u --recursive --new-file v2.3.46/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- v2.3.46/linux/net/core/rtnetlink.c	Thu Feb 10 17:11:24 2000
+++ linux/net/core/rtnetlink.c	Thu Feb 17 09:18:47 2000
@@ -171,7 +171,7 @@
 	r->ifi_flags = dev->flags;
 	r->ifi_change = change;
 
-	if (test_bit(LINK_STATE_DOWN, &dev->state))
+	if (! netif_running(dev))
 		r->ifi_flags &= ~IFF_RUNNING;
 	else
 		r->ifi_flags |= IFF_RUNNING;
diff -u --recursive --new-file v2.3.46/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.3.46/linux/net/core/skbuff.c	Sat Feb 12 11:22:11 2000
+++ linux/net/core/skbuff.c	Fri Feb 18 14:51:22 2000
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.67 2000/02/11 22:27:23 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.68 2000/02/18 16:47:18 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -194,7 +194,6 @@
 
 	skb->destructor = NULL;
 	skb->pkt_type = PACKET_HOST;	/* Default type */
-	skb->pkt_bridged = 0;		/* Not bridged */
 	skb->prev = skb->next = NULL;
 	skb->list = NULL;
 	skb->sk = NULL;
diff -u --recursive --new-file v2.3.46/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.46/linux/net/ipv4/af_inet.c	Thu Feb 10 17:11:24 2000
+++ linux/net/ipv4/af_inet.c	Fri Feb 18 14:51:22 2000
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.106 2000/02/04 21:04:06 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.107 2000/02/18 16:47:20 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -103,9 +103,7 @@
 #ifdef CONFIG_IP_MROUTE
 #include <linux/mroute.h>
 #endif
-#ifdef CONFIG_BRIDGE
-#include <net/br.h>
-#endif
+#include <linux/if_bridge.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
@@ -137,6 +135,8 @@
 int (*dlci_ioctl_hook)(unsigned int, void *) = NULL;
 #endif
 
+int (*br_ioctl_hook)(unsigned long) = NULL;
+
 /* New destruction routine */
 
 void inet_sock_destruct(struct sock *sk)
@@ -837,14 +837,14 @@
 			return(devinet_ioctl(cmd,(void *) arg));
 		case SIOCGIFBR:
 		case SIOCSIFBR:
-#ifdef CONFIG_BRIDGE
-			lock_kernel();
-			err = br_ioctl(cmd,(void *) arg);
-			unlock_kernel();
-			return err;
-#else
+#ifdef CONFIG_KMOD
+			if (br_ioctl_hook == NULL)
+				request_module("bridge");
+#endif
+			if (br_ioctl_hook != NULL)
+				return br_ioctl_hook(arg);
+
 			return -ENOPKG;
-#endif						
 			
 		case SIOCADDDLCI:
 		case SIOCDELDLCI:
diff -u --recursive --new-file v2.3.46/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.3.46/linux/net/ipv4/ipconfig.c	Tue Feb  1 01:35:44 2000
+++ linux/net/ipv4/ipconfig.c	Sun Feb 20 20:14:55 2000
@@ -821,7 +821,7 @@
  *	IP Autoconfig dispatcher.
  */
 
-int __init ip_auto_config(void)
+static int __init ip_auto_config(void)
 {
 	if (!ic_enable)
 		return 0;
@@ -878,6 +878,9 @@
 	    system_utsname.domainname, root_server_path));
 	return 0;
 }
+
+module_init(ip_auto_config);
+
 
 /*
  *  Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
diff -u --recursive --new-file v2.3.46/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.3.46/linux/net/ipv4/tcp_output.c	Thu Feb 10 17:11:24 2000
+++ linux/net/ipv4/tcp_output.c	Sun Feb 20 20:23:20 2000
@@ -857,11 +857,15 @@
 		}
 	} else {
 		/* Socket is locked, keep trying until memory is available. */
-		do {
+		for (;;) {
 			skb = sock_wmalloc(sk,
 					   MAX_TCP_HEADER + 15,
 					   1, GFP_KERNEL);
-		} while (skb == NULL);
+			if (skb)
+				break;
+			current->policy |= SCHED_YIELD;
+			schedule();
+		}
 
 		/* Reserve space for headers and prepare control bits. */
 		skb_reserve(skb, MAX_TCP_HEADER);
diff -u --recursive --new-file v2.3.46/linux/net/irda/irlan/irlan_client.c linux/net/irda/irlan/irlan_client.c
--- v2.3.46/linux/net/irda/irlan/irlan_client.c	Sun Feb 13 19:29:04 2000
+++ linux/net/irda/irlan/irlan_client.c	Thu Feb 17 09:18:47 2000
@@ -126,7 +126,7 @@
 	 * is up, that means that the "user" really wants to connect. If not
 	 * we notify the user about the possibility of an IrLAN connection
 	 */
-	if (test_bit(LINK_STATE_START, &self->dev.state)) {
+	if (netif_running(&self->dev)) {
 		/* Open TSAPs */
 		irlan_client_open_ctrl_tsap(self);
  		irlan_open_data_tsap(self);
diff -u --recursive --new-file v2.3.46/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.3.46/linux/net/irda/irlan/irlan_common.c	Sun Feb 13 19:29:04 2000
+++ linux/net/irda/irlan/irlan_common.c	Thu Feb 17 09:18:47 2000
@@ -120,7 +120,7 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if device still configured */
-	if (test_bit(LINK_STATE_START, &self->dev.state)) {
+	if (netif_running(&self->dev)) {
 		IRDA_DEBUG(0, __FUNCTION__ 
 		      "(), notifying irmanager to stop irlan!\n");
 		mgr_event.event = EVENT_IRLAN_STOP;
@@ -363,7 +363,7 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if device is still configured */
-	if (test_bit(LINK_STATE_START, &self->dev.state)) {
+	if (netif_running(&self->dev)) {
 		IRDA_DEBUG(0, __FUNCTION__ 
 		       "(), Device still configured, closing later!\n");
 
@@ -1195,7 +1195,7 @@
 						  buf+len);
 			
 			len += sprintf(buf+len, "tx busy: %s\n", 
-				       test_bit(LINK_STATE_XOFF, &self->dev.state) ? "TRUE" : "FALSE");
+				       netif_queue_stopped(&self->dev) ? "TRUE" : "FALSE");
 			
 			len += sprintf(buf+len, "\n");
 		}
diff -u --recursive --new-file v2.3.46/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.3.46/linux/net/netrom/nr_dev.c	Sun Feb 13 19:29:04 2000
+++ linux/net/netrom/nr_dev.c	Thu Feb 17 09:18:47 2000
@@ -62,7 +62,7 @@
 {
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
-	if (!test_bit(LINK_STATE_START, &dev->state)) {
+	if (!netif_running(dev)) {
 		stats->rx_errors++;
 		return 0;
 	}
diff -u --recursive --new-file v2.3.46/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.46/linux/net/netsyms.c	Sun Feb 13 19:29:04 2000
+++ linux/net/netsyms.c	Fri Feb 18 14:51:22 2000
@@ -28,12 +28,9 @@
 #endif
 #include <net/pkt_sched.h>
 #include <net/scm.h>
+#include <linux/if_bridge.h>
 #include <linux/random.h>
 
-#ifdef CONFIG_BRIDGE
-#include <net/br.h>
-#endif
-
 #ifdef CONFIG_NET
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
@@ -217,10 +214,9 @@
 
 EXPORT_SYMBOL(scm_detach_fds);
 
-#ifdef CONFIG_BRIDGE 
-EXPORT_SYMBOL(br_ioctl);
-EXPORT_SYMBOL(port_info);
-EXPORT_SYMBOL(br_avl_find_addr);
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+EXPORT_SYMBOL(br_handle_frame_hook);
+EXPORT_SYMBOL(br_ioctl_hook);
 #endif
 
 #ifdef CONFIG_INET
@@ -597,6 +593,7 @@
 
 EXPORT_SYMBOL(register_gifconf);
 
+EXPORT_SYMBOL(net_call_rx_atomic);
 EXPORT_SYMBOL(softirq_state);
 EXPORT_SYMBOL(softnet_data);
 
diff -u --recursive --new-file v2.3.46/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.3.46/linux/net/packet/af_packet.c	Thu Feb 10 17:11:25 2000
+++ linux/net/packet/af_packet.c	Fri Feb 18 14:51:22 2000
@@ -5,7 +5,7 @@
  *
  *		PACKET - implements raw packet sockets.
  *
- * Version:	$Id: af_packet.c,v 1.30 2000/02/01 12:38:30 freitag Exp $
+ * Version:	$Id: af_packet.c,v 1.31 2000/02/18 16:47:23 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -65,16 +65,12 @@
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/if_bridge.h>
 
 #ifdef CONFIG_INET
 #include <net/inet_common.h>
 #endif
 
-#ifdef CONFIG_BRIDGE
-#include <linux/smp_lock.h>
-#include <net/br.h>
-#endif
-
 #ifdef CONFIG_DLCI
 extern int dlci_ioctl(unsigned int, void*);
 #endif
@@ -1442,14 +1438,14 @@
 
 		case SIOCGIFBR:
 		case SIOCSIFBR:
-#ifdef CONFIG_BRIDGE
-			lock_kernel();
-			err = br_ioctl(cmd,(void *) arg);
-			unlock_kernel();
-			return err;
-#else
+#ifdef CONFIG_KMOD
+			if (br_ioctl_hook == NULL)
+				request_module("bridge");
+#endif
+			if (br_ioctl_hook != NULL)
+				return br_ioctl_hook(arg);
+
 			return -ENOPKG;
-#endif						
 			
 #ifdef CONFIG_INET
 		case SIOCADDRT:
diff -u --recursive --new-file v2.3.46/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.3.46/linux/net/rose/rose_dev.c	Sun Feb 13 19:29:04 2000
+++ linux/net/rose/rose_dev.c	Thu Feb 17 09:18:47 2000
@@ -57,7 +57,7 @@
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
 #ifdef CONFIG_INET
-	if (!test_bit(LINK_STATE_START, &dev->state)) {
+	if (!netif_running(dev)) {
 		stats->rx_errors++;
 		return 0;
 	}
@@ -163,7 +163,7 @@
 {
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
-	if (!test_bit(LINK_STATE_START, &dev->state)) {
+	if (!netif_running(dev)) {
 		printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n");
 		return 1;
 	}
diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_api.c linux/net/sched/sch_api.c
--- v2.3.46/linux/net/sched/sch_api.c	Fri Jan  7 19:13:23 2000
+++ linux/net/sched/sch_api.c	Sun Feb 20 20:21:25 2000
@@ -1139,11 +1139,6 @@
 	long rdelay;
 	unsigned long stop;
 
-#if CPU == 586 || CPU == 686
-	if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC))
-		return -1;
-#endif
-
 #ifdef PSCHED_WATCHER
 	psched_tick(0);
 #endif
diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- v2.3.46/linux/net/sched/sch_cbq.c	Thu Feb 10 17:11:25 2000
+++ linux/net/sched/sch_cbq.c	Thu Feb 17 09:18:47 2000
@@ -1053,7 +1053,7 @@
 
 	if (sch->q.qlen) {
 		sch->stats.overlimits++;
-		if (q->wd_expires && !test_bit(LINK_STATE_XOFF, &sch->dev->state)) {
+		if (q->wd_expires && !netif_queue_stopped(sch->dev)) {
 			long delay = PSCHED_US2JIFFIE(q->wd_expires);
 			del_timer(&q->wd_timer);
 			if (delay <= 0)
diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c
--- v2.3.46/linux/net/sched/sch_generic.c	Thu Feb 10 17:11:25 2000
+++ linux/net/sched/sch_generic.c	Fri Feb 18 14:51:22 2000
@@ -88,7 +88,7 @@
 			/* And release queue */
 			spin_unlock(&dev->queue_lock);
 
-			if (!test_bit(LINK_STATE_XOFF, &dev->state)) {
+			if (!netif_queue_stopped(dev)) {
 				if (netdev_nit)
 					dev_queue_xmit_nit(skb, dev);
 
@@ -146,7 +146,7 @@
 
 	spin_lock(&dev->xmit_lock);
 	if (dev->qdisc != &noop_qdisc) {
-		if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+		if (netif_queue_stopped(dev) &&
 		    (jiffies - dev->trans_start) > dev->watchdog_timeo) {
 			printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name);
 			dev->tx_timeout(dev);
@@ -476,7 +476,7 @@
 
 	dev_watchdog_down(dev);
 
-	if (test_bit(LINK_STATE_SCHED, &dev->state)) {
+	while (test_bit(__LINK_STATE_SCHED, &dev->state)) {
 		current->policy |= SCHED_YIELD;
 		schedule();
 	}
diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c
--- v2.3.46/linux/net/sched/sch_tbf.c	Thu Feb 10 17:11:25 2000
+++ linux/net/sched/sch_tbf.c	Thu Feb 17 09:18:47 2000
@@ -226,7 +226,7 @@
 			return skb;
 		}
 
-		if (!test_bit(LINK_STATE_XOFF, &sch->dev->state)) {
+		if (!netif_queue_stopped(sch->dev)) {
 			long delay = PSCHED_US2JIFFIE(max(-toks, -ptoks));
 
 			if (delay == 0)
diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c
--- v2.3.46/linux/net/sched/sch_teql.c	Thu Feb 10 17:11:25 2000
+++ linux/net/sched/sch_teql.c	Thu Feb 17 09:18:47 2000
@@ -296,8 +296,7 @@
 		
 		if (slave->qdisc_sleeping != q)
 			continue;
-		if (test_bit(LINK_STATE_XOFF, &slave->state) ||
-		    test_bit(LINK_STATE_DOWN, &slave->state)) {
+		if (netif_queue_stopped(slave) || ! netif_running(slave)) {
 			busy = 1;
 			continue;
 		}
@@ -306,7 +305,7 @@
 		case 0:
 			if (spin_trylock(&slave->xmit_lock)) {
 				slave->xmit_lock_owner = smp_processor_id();
-				if (!test_bit(LINK_STATE_XOFF, &slave->state) &&
+				if (!netif_queue_stopped(slave) &&
 				    slave->hard_start_xmit(skb, slave) == 0) {
 					slave->xmit_lock_owner = -1;
 					spin_unlock(&slave->xmit_lock);
@@ -319,7 +318,7 @@
 				slave->xmit_lock_owner = -1;
 				spin_unlock(&slave->xmit_lock);
 			}
-			if (test_bit(LINK_STATE_XOFF, &dev->state))
+			if (netif_queue_stopped(dev))
 				busy = 1;
 			break;
 		case 1:
diff -u --recursive --new-file v2.3.46/linux/net/sysctl_net.c linux/net/sysctl_net.c
--- v2.3.46/linux/net/sysctl_net.c	Sun Nov 30 14:00:40 1997
+++ linux/net/sysctl_net.c	Fri Feb 18 14:51:22 2000
@@ -34,10 +34,6 @@
 extern ctl_table ether_table[], e802_table[];
 #endif
 
-#ifdef CONFIG_BRIDGE
-extern ctl_table bridge_table[];
-#endif
-
 #ifdef CONFIG_IPV6
 extern ctl_table ipv6_table[];
 #endif
@@ -60,9 +56,6 @@
 #endif
 #ifdef CONFIG_IPX
         {NET_IPX,    "ipx",       NULL, 0, 0555, ipx_table},
-#endif
-#ifdef CONFIG_BRIDGE
-        {NET_BRIDGE, "bridge",    NULL, 0, 0555, bridge_table},
 #endif
 #ifdef CONFIG_IPV6
 	{NET_IPV6, "ipv6", NULL, 0, 0555, ipv6_table},
diff -u --recursive --new-file v2.3.46/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.3.46/linux/net/wanrouter/wanmain.c	Sun Feb 13 19:29:04 2000
+++ linux/net/wanrouter/wanmain.c	Thu Feb 17 09:18:47 2000
@@ -701,7 +701,7 @@
 	if (dev == NULL)
 		return -ENODEV;	/* interface not found */
 
-	if (test_bit(LINK_STATE_START, &dev->state)) {
+	if (netif_running(dev)) {
 		if (force) {
 			printk(KERN_WARNING
 				"%s: deleting opened interface %s!\n",
diff -u --recursive --new-file v2.3.46/linux/scripts/Configure linux/scripts/Configure
--- v2.3.46/linux/scripts/Configure	Mon Nov  1 13:56:27 1999
+++ linux/scripts/Configure	Sun Feb 20 20:13:10 2000
@@ -311,6 +311,26 @@
 	bool "$ques" "$var"
 }
 
+function dep_mbool () {
+	ques=$1
+	var=$2
+	shift 2
+	while [ $# -gt 0 ]; do
+	  case "$1" in
+	    n)
+	      define_bool "$var" "n"
+	      return
+	      ;;
+	    m)
+	      eval "$var=y"
+	      ;;
+	  esac
+	  shift
+	done
+
+	bool "$ques" "$var"
+}
+
 #
 # define_int sets the value of a integer argument
 #
diff -u --recursive --new-file v2.3.46/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.3.46/linux/scripts/Menuconfig	Tue Dec  7 09:32:52 1999
+++ linux/scripts/Menuconfig	Sun Feb 20 20:13:10 2000
@@ -258,6 +258,26 @@
 	fi
 }
 
+function dep_mbool () {
+	ques="$1"
+	var="$2"
+	dep=y
+	shift 2
+	while [ $# -gt 0 ]; do
+		if [ "$1" = y -o "$1" = m ]; then
+			shift
+		else
+			dep=n
+			shift $#
+		fi
+	done
+	if [ "$dep" = y ]; then
+	    bool "$ques" "$var"
+	else 
+	    define_bool "$var" n
+	fi
+}
+
 #
 # Add a menu item which will call our local int function.
 # 
@@ -1075,6 +1095,20 @@
 		shift 2
 		while [ $# -gt 0 ]; do
 			if   [ "$1" = y ]; then
+				shift
+			else 
+				x=n; shift $#
+			fi
+		done
+		define_bool "$var" "$x"
+	}
+
+	function dep_mbool () {
+		set_x_info "$2" "n"
+		var="$2"
+		shift 2
+		while [ $# -gt 0 ]; do
+			if   [ "$1" = y -o "$1" = m ]; then
 				shift
 			else 
 				x=n; shift $#
diff -u --recursive --new-file v2.3.46/linux/scripts/header.tk linux/scripts/header.tk
--- v2.3.46/linux/scripts/header.tk	Mon Oct  4 15:49:30 1999
+++ linux/scripts/header.tk	Sun Feb 20 20:13:10 2000
@@ -249,17 +249,19 @@
 	return $var
 }
 
-proc sync_bool { var dep } {
+proc sync_bool { var dep modset } {
 	set var [sync_tristate $var $dep]
-	if {$dep == 2} then {
-		set var 0
+	if {$dep == 2 && $var == 2} then {
+		set var $modset
 	}
 	return $var
 }
 
-proc write_tristate { file1 file2 varname variable deplist } {
+proc write_tristate { file1 file2 varname variable deplist modset } {
 	set variable [sync_tristate $variable [effective_dep $deplist]]
-	if { $variable == 1 }\
+	if { $variable == 2 } \
+		then { set variable $modset }
+	if { $variable == 1 } \
 		then { puts $file1 "$varname=y"; \
 		       puts $file2 "#define $varname 1" } \
 	elseif { $variable == 2 } \
diff -u --recursive --new-file v2.3.46/linux/scripts/tkcond.c linux/scripts/tkcond.c
--- v2.3.46/linux/scripts/tkcond.c	Sun Feb 13 19:29:04 2000
+++ linux/scripts/tkcond.c	Sun Feb 20 20:13:10 2000
@@ -53,6 +53,7 @@
 	||   cfg->token == token_define_string
 	||   cfg->token == token_define_tristate
 	||   cfg->token == token_dep_bool
+	||   cfg->token == token_dep_mbool
 	||   cfg->token == token_dep_tristate
 	||   cfg->token == token_hex
 	||   cfg->token == token_int
@@ -517,6 +518,7 @@
 		break;
 
 	    case token_dep_bool:
+	    case token_dep_mbool:
 	    case token_dep_tristate:
 		/*
 		 * Same as the other simple statements, plus an additional
diff -u --recursive --new-file v2.3.46/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v2.3.46/linux/scripts/tkgen.c	Mon Oct  4 15:49:30 1999
+++ linux/scripts/tkgen.c	Sun Feb 20 20:13:10 2000
@@ -343,12 +343,16 @@
      */
     if ( line_num >= -1 )
     {
+	int modtoyes = 0;
+
 	switch ( cfg->token )
 	{
 	default:
 	    printf( " }\n" );
 	    break;
 
+	case token_dep_mbool:
+	    modtoyes = 1;
 	case token_dep_bool:
 	    printf( "\n" );
 	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
@@ -359,10 +363,13 @@
 	    printf( "\tset tmpvar_dep [effective_dep [list" );
 	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 		printf( " $%s", tmp->name );
-	    printf( "]];set %s [sync_bool $%s $tmpvar_dep];",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	    printf( "if {$tmpvar_dep != 1} then {" );
-	    printf( "configure_entry .menu%d.config.f.x%d disabled {y};",
+	    printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
+		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
+		modtoyes );
+	    printf( "if {$tmpvar_dep != 1" );
+	    if (modtoyes)
+		printf( " && $tmpvar_dep != 2" );
+	    printf( "} then {configure_entry .menu%d.config.f.x%d disabled {y};",
 		menu_num, line_num );
 	    printf( "} else {" );
 	    printf( "configure_entry .menu%d.config.f.x%d normal {y};",
@@ -474,12 +481,16 @@
     }
     else
     {
+	int modtoyes = 0;
+
 	switch ( cfg->token )
 	{
 	default:
 	    printf( " }\n" );
 	    break;
 
+	case token_dep_mbool:
+	    modtoyes = 1;
 	case token_dep_bool:
 	    printf( "\n" );
 	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
@@ -490,8 +501,9 @@
 	    printf( "\tset tmpvar_dep [effective_dep [list" );
 	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 		printf( " $%s", tmp->name );
-	    printf( "]];set %s [sync_bool $%s $tmpvar_dep];",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
+	    printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
+		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
+		modtoyes );
 	case token_bool:
 	    if ( cfg->token == token_bool )
 		printf( "\n\t" );
@@ -604,6 +616,7 @@
 {
     struct condition * cond;
     struct dependency * tmp;
+    int depmod = 2;
     
     /*
      * Generate global declaration for this symbol.
@@ -705,7 +718,7 @@
 
     case token_bool:
     case token_tristate:
-	printf( "write_tristate $cfg $autocfg %s $%s [list $notmod]", 
+	printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2", 
 	    vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 	if ( cfg->cond != NULL )
 	    printf( " }" );
@@ -724,7 +737,7 @@
 		  cfg1 != NULL && cfg1->token == token_choice_item;
 		  cfg1  = cfg1->next )
 	    {
-		printf("\n\tif { $tmpvar_%d == \"%s\" } then { write_tristate $cfg $autocfg %s 1 [list $notmod] } else { write_tristate $cfg $autocfg %s 0 [list $notmod] }",
+		printf("\n\tif { $tmpvar_%d == \"%s\" } then { write_tristate $cfg $autocfg %s 1 [list $notmod] 2 } else { write_tristate $cfg $autocfg %s 0 [list $notmod] 2 }",
 		    -(cfg->nameindex), cfg1->label,
 		    vartable[cfg1->nameindex].name,
 		    vartable[cfg1->nameindex].name );
@@ -751,23 +764,25 @@
     case token_define_tristate:
 	if ( cfg->cond == NULL )
 	{
-	    printf( "write_tristate $cfg $autocfg %s $%s [list $notmod]\n",
+	    printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2\n",
 		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 	}
 	else
 	{
-	    printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] }\n",
+	    printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2 }\n",
 		vartable[cfg->nameindex].name, cfg->value );
 	}
 	break;
 
+    case token_dep_mbool:
+	depmod = 1;
     case token_dep_bool:
     case token_dep_tristate:
 	printf( "write_tristate $cfg $autocfg %s $%s [list",
 	    vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 	for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 	    printf( " $%s", tmp->name );
-	printf( "]" );
+	printf( "] %d", depmod );
 	if ( cfg->cond != NULL )
 	    printf( " }" );
 	printf( "\n" );
@@ -887,6 +902,7 @@
 	    case token_define_string:
 	    case token_dep_bool:
 	    case token_dep_tristate:
+	    case token_dep_mbool:
 	    case token_int:
 	    case token_hex:
 	    case token_mainmenu_option:
@@ -1121,6 +1137,7 @@
 	case token_choice_item:
 	case token_dep_bool:
 	case token_dep_tristate:
+	case token_dep_mbool:
 	case token_hex:
 	case token_int:
 	case token_string:
@@ -1222,6 +1239,7 @@
 		break;
 
 	    case token_dep_bool:
+	    case token_dep_mbool:
 		cfg->menu_line = menu_line++;
 		printf( "\tdep_bool $w.config.f %d %d \"%s\" %s\n",
 		    cfg->menu_number, cfg->menu_line, cfg->label,
@@ -1300,6 +1318,7 @@
 	case token_choice_item:
 	case token_dep_bool:
 	case token_dep_tristate:
+	case token_dep_mbool:
 	case token_tristate:
 	    if ( ! vartable[cfg->nameindex].global_written )
 	    {
@@ -1376,6 +1395,7 @@
 	case token_define_tristate:
 	case token_dep_bool:
 	case token_dep_tristate:
+	case token_dep_mbool:
 	case token_hex:
 	case token_int:
 	case token_string:
diff -u --recursive --new-file v2.3.46/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v2.3.46/linux/scripts/tkparse.c	Mon Oct  4 15:49:30 1999
+++ linux/scripts/tkparse.c	Sun Feb 20 20:13:10 2000
@@ -386,6 +386,7 @@
 	match_token( token_define_string, "define_string" );
 	match_token( token_define_tristate, "define_tristate" );
 	match_token( token_dep_bool, "dep_bool" );
+	match_token( token_dep_mbool, "dep_mbool" );
 	match_token( token_dep_tristate, "dep_tristate" );
 	break;
 
@@ -549,6 +550,7 @@
 	break;
 
     case token_dep_bool:
+    case token_dep_mbool:
     case token_dep_tristate:
 	pnt = get_qstring ( pnt, &cfg->label );
 	pnt = get_string  ( pnt, &buffer );
@@ -585,7 +587,7 @@
 	    }
 	    else
 	    {
-		syntax_error( "can't handle dep_bool/dep_tristate condition" );
+		syntax_error( "can't handle dep_bool/dep_mbool/dep_tristate condition" );
 	    }
 	    dep_ptr = &(*dep_ptr)->next;
 	    while ( *pnt == ' ' || *pnt == '\t' )
@@ -623,12 +625,12 @@
 		*cond_ptr = malloc( sizeof(struct condition) );
 		memset( *cond_ptr, 0, sizeof(struct condition) );
 		(*cond_ptr)->op = op_lparen;
-		if ( token == token_dep_tristate )
-		    sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then",
-			dep->name, dep->name, dep->name );
-		else
+		if ( token == token_dep_bool )
 		    sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"\" ]; then",
 			dep->name, dep->name );
+		else
+		    sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then",
+			dep->name, dep->name, dep->name );
 		(*cond_ptr)->next = tokenize_if( fake_if );
 		while ( *cond_ptr )
 		    cond_ptr = &(*cond_ptr)->next;
diff -u --recursive --new-file v2.3.46/linux/scripts/tkparse.h linux/scripts/tkparse.h
--- v2.3.46/linux/scripts/tkparse.h	Mon Oct  4 15:49:30 1999
+++ linux/scripts/tkparse.h	Sun Feb 20 20:13:10 2000
@@ -19,6 +19,7 @@
     token_define_string,
     token_define_tristate,
     token_dep_bool,
+    token_dep_mbool,
     token_dep_tristate,
     token_else, 
     token_endmenu,
@@ -77,7 +78,7 @@
 };
 
 /*
- * Dependency list for dep_bool, dep_tristate
+ * Dependency list for dep_bool, dep_mbool, dep_tristate
  */
 
 struct dependency
