]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.47pre5 2.3.47pre5
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:31:51 +0000 (15:31 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:31:51 +0000 (15:31 -0500)
140 files changed:
CREDITS
Documentation/Configure.help
Documentation/DMA-mapping.txt
Documentation/networking/bridge.txt [new file with mode: 0644]
Documentation/networking/skfp.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_sx164.c
arch/sparc/defconfig
arch/sparc/kernel/ioport.c
arch/sparc64/defconfig
arch/sparc64/kernel/pci_iommu.c
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/sbus.c
drivers/block/ide-dma.c
drivers/fc4/fc.c
drivers/net/3c59x.c
drivers/net/8139too.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/acenic.c
drivers/net/de4x5.c
drivers/net/eepro100.c
drivers/net/myri_sbus.c
drivers/net/rtl8129.c
drivers/net/sk98lin/skge.c
drivers/net/skfp/Makefile [new file with mode: 0644]
drivers/net/skfp/can.c [new file with mode: 0644]
drivers/net/skfp/cfm.c [new file with mode: 0644]
drivers/net/skfp/drvfbi.c [new file with mode: 0644]
drivers/net/skfp/ecm.c [new file with mode: 0644]
drivers/net/skfp/ess.c [new file with mode: 0644]
drivers/net/skfp/fplustm.c [new file with mode: 0644]
drivers/net/skfp/h/cmtdef.h [new file with mode: 0644]
drivers/net/skfp/h/fddi.h [new file with mode: 0644]
drivers/net/skfp/h/fddimib.h [new file with mode: 0644]
drivers/net/skfp/h/fplustm.h [new file with mode: 0644]
drivers/net/skfp/h/hwmtm.h [new file with mode: 0644]
drivers/net/skfp/h/lnkstat.h [new file with mode: 0644]
drivers/net/skfp/h/mbuf.h [new file with mode: 0644]
drivers/net/skfp/h/osdef1st.h [new file with mode: 0644]
drivers/net/skfp/h/sba.h [new file with mode: 0644]
drivers/net/skfp/h/sba_def.h [new file with mode: 0644]
drivers/net/skfp/h/skfbi.h [new file with mode: 0644]
drivers/net/skfp/h/skfbiinc.h [new file with mode: 0644]
drivers/net/skfp/h/smc.h [new file with mode: 0644]
drivers/net/skfp/h/smt.h [new file with mode: 0644]
drivers/net/skfp/h/smt_p.h [new file with mode: 0644]
drivers/net/skfp/h/smtstate.h [new file with mode: 0644]
drivers/net/skfp/h/supern_2.h [new file with mode: 0644]
drivers/net/skfp/h/targethw.h [new file with mode: 0644]
drivers/net/skfp/h/targetos.h [new file with mode: 0644]
drivers/net/skfp/h/types.h [new file with mode: 0644]
drivers/net/skfp/hwmtm.c [new file with mode: 0644]
drivers/net/skfp/hwt.c [new file with mode: 0644]
drivers/net/skfp/lnkstat.c [new file with mode: 0644]
drivers/net/skfp/pcmplc.c [new file with mode: 0644]
drivers/net/skfp/pmf.c [new file with mode: 0644]
drivers/net/skfp/queue.c [new file with mode: 0644]
drivers/net/skfp/rmt.c [new file with mode: 0644]
drivers/net/skfp/skfddi.c [new file with mode: 0644]
drivers/net/skfp/smt.c [new file with mode: 0644]
drivers/net/skfp/smtdef.c [new file with mode: 0644]
drivers/net/skfp/smtinit.c [new file with mode: 0644]
drivers/net/skfp/smtparse.c [new file with mode: 0644]
drivers/net/skfp/smttimer.c [new file with mode: 0644]
drivers/net/skfp/srf.c [new file with mode: 0644]
drivers/net/starfire.c
drivers/net/sunbmac.c
drivers/net/sunhme.c
drivers/net/sunhme.h
drivers/parport/parport_pc.c
drivers/sbus/audio/cs4231.c
drivers/sbus/audio/dbri.c
drivers/scsi/aic7xxx.c
drivers/scsi/eata_dma_proc.c
drivers/scsi/esp.c
drivers/scsi/pci2000.c
drivers/scsi/pci2000.h
drivers/scsi/pci2220i.c
drivers/scsi/pci2220i.h
drivers/scsi/psi_dale.h
drivers/scsi/qlogicisp.c
drivers/scsi/qlogicpti.c
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_obsolete.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
fs/Config.in
include/asm-alpha/pci.h
include/asm-arm/pci.h
include/asm-i386/pci.h
include/asm-ia64/pci.h
include/asm-ppc/pci.h
include/asm-sparc/pci.h
include/asm-sparc/sbus.h
include/asm-sparc64/floppy.h
include/asm-sparc64/pbm.h
include/asm-sparc64/pci.h
include/asm-sparc64/sbus.h
include/linux/ide.h
include/linux/if_bridge.h [new file with mode: 0644]
include/linux/netdevice.h
include/linux/pci.h
include/linux/skbuff.h
include/net/br.h [deleted file]
net/Changes
net/Config.in
net/Makefile
net/README
net/bridge/Makefile
net/bridge/br.c
net/bridge/br_device.c [new file with mode: 0644]
net/bridge/br_fdb.c [new file with mode: 0644]
net/bridge/br_forward.c [new file with mode: 0644]
net/bridge/br_if.c [new file with mode: 0644]
net/bridge/br_input.c [new file with mode: 0644]
net/bridge/br_ioctl.c [new file with mode: 0644]
net/bridge/br_notify.c [new file with mode: 0644]
net/bridge/br_private.h [new file with mode: 0644]
net/bridge/br_private_stp.h [new file with mode: 0644]
net/bridge/br_private_timer.h [new file with mode: 0644]
net/bridge/br_stp.c [new file with mode: 0644]
net/bridge/br_stp_bpdu.c [new file with mode: 0644]
net/bridge/br_stp_if.c [new file with mode: 0644]
net/bridge/br_stp_timer.c [new file with mode: 0644]
net/bridge/br_tree.c [deleted file]
net/bridge/sysctl_net_bridge.c [deleted file]
net/core/dev.c
net/core/skbuff.c
net/ipv4/af_inet.c
net/netsyms.c
net/packet/af_packet.c
net/sched/sch_generic.c
net/sysctl_net.c

diff --git a/CREDITS b/CREDITS
index f7247ea8810d57c62cc5df2638a093ffd4796f0d..f97a63889a02e64c307a87669854b9ec379e86ee 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -367,6 +367,13 @@ D: Original author of Amiga FFS filesystem
 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
index fe94f09920c24f984ada3e9505501c1bf9234e8d..4931d2680fc61bea3ceefbbb32ea090dd7201251 100644 (file)
@@ -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 @@ CONFIG_MAC_FLOPPY
 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 @@ CONFIG_BLK_DEV_LOOP
   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 @@ CONFIG_BLK_DEV_LOOP
   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 @@ Network Block Device support
 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 @@ CONFIG_BLK_DEV_IDE
   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 @@ CONFIG_BLK_DEV_IDEDISK
   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 @@ CONFIG_BLK_DEV_IDECD
   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 @@ CONFIG_IDEDMA_PCI_AUTO
   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 @@ CONFIG_PARIDE_PCD
   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
@@ -1519,7 +1519,7 @@ CONFIG_NETFILTER
   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
@@ -1529,7 +1529,7 @@ CONFIG_NETFILTER
 
   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
@@ -1538,7 +1538,7 @@ CONFIG_NETFILTER
   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
@@ -1565,12 +1565,12 @@ CONFIG_SYN_COOKIES
   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.
 
@@ -1878,7 +1878,7 @@ CONFIG_I2O_SCSI
 
 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.
 
@@ -1898,7 +1898,7 @@ CONFIG_PNP
   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).
@@ -1987,7 +1987,7 @@ CONFIG_SYSCTL
   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.
@@ -1998,7 +1998,7 @@ CONFIG_SYSCTL
 
 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
@@ -2092,7 +2092,7 @@ CONFIG_BINFMT_MISC
   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
@@ -2404,7 +2404,7 @@ CONFIG_FONT_8x8
   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
@@ -2702,7 +2702,7 @@ CONFIG_PARPORT_AX
 
 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.
 
@@ -2742,7 +2742,7 @@ CONFIG_MODVERSIONS
 
 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
@@ -2794,7 +2794,7 @@ CONFIG_INET
   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
@@ -2827,12 +2827,12 @@ CONFIG_IP_ADVANCED_ROUTER
 
   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
@@ -2926,12 +2926,12 @@ CONFIG_IP_ROUTER
 
   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.
@@ -2948,7 +2948,7 @@ CONFIG_IP_PNP
 
 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
@@ -2961,7 +2961,7 @@ CONFIG_IP_PNP_BOOTP
 
 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
@@ -3189,7 +3189,7 @@ CONFIG_IPX
   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,
@@ -3248,7 +3248,7 @@ CONFIG_SPX
 
   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
@@ -3273,7 +3273,7 @@ CONFIG_DECNET
   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.
 
@@ -3820,25 +3820,25 @@ CONFIG_LLC
   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
@@ -3919,13 +3919,13 @@ CONFIG_ATM_CLIP
   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
@@ -4164,7 +4164,7 @@ CONFIG_SCSI
   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
@@ -4180,7 +4180,7 @@ CONFIG_BLK_DEV_SD
   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.
 
@@ -4227,7 +4227,7 @@ CONFIG_BLK_DEV_SR
   If you want to use a SCSI CDROM under Linux, say Y and read the
   SCSI-HOWTO and the CDROM-HOWTO 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).
@@ -4307,12 +4307,12 @@ CONFIG_SCSI_LOGGING
   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
@@ -4475,7 +4475,7 @@ CONFIG_AIC7XXX_PROC_STATS
   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 systems support", below. 
 
   If unsure, say N.
 
@@ -5725,7 +5725,7 @@ CONFIG_AIRONET4500
   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)
@@ -5734,7 +5734,7 @@ CONFIG_AIRONET4500
        channel=1..?    meaningful in adhoc mode
   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
 
@@ -5770,7 +5770,7 @@ CONFIG_AIRONET4500_ISA
 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
 
@@ -5783,7 +5783,7 @@ CONFIG_AIRONET4500_CS
        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
@@ -6210,7 +6210,7 @@ CONFIG_NET_SCHED
   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
+  If you say Y here and to "/proc file systems" below, you will be able
   to read status information about packet schedulers from the file
   /proc/net/psched.
   
@@ -6415,7 +6415,7 @@ CONFIG_NET_CLS_RSVP6
 
 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 systems 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.
@@ -6873,7 +6873,7 @@ CONFIG_SK98LIN
   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
@@ -7666,7 +7666,7 @@ CONFIG_TMS380TR
   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
@@ -7739,6 +7739,36 @@ CONFIG_DEFXX
   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
@@ -7812,7 +7842,7 @@ CONFIG_CD_NO_IDESCSI
   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).
 
@@ -7829,7 +7859,7 @@ CONFIG_CDU31A
   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
@@ -7851,7 +7881,7 @@ CONFIG_MCD
   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
@@ -7884,7 +7914,7 @@ CONFIG_MCDX
   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
@@ -7922,7 +7952,7 @@ CONFIG_SBPCD
   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
@@ -7947,7 +7977,7 @@ CONFIG_AZTCD
   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
@@ -7961,7 +7991,7 @@ CONFIG_CDU535
   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
@@ -7977,7 +8007,7 @@ CONFIG_GSCD
   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
@@ -7992,7 +8022,7 @@ CONFIG_CM206
   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
@@ -8009,7 +8039,7 @@ CONFIG_OPTCD
   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
@@ -8021,8 +8051,8 @@ Sanyo CDR-H94A CDROM support
 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).
@@ -8057,7 +8087,7 @@ Quota support
 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.
@@ -8399,7 +8429,7 @@ CONFIG_USB_USS720
   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
@@ -8439,10 +8469,10 @@ CONFIG_ACPI
 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.
@@ -8450,16 +8480,16 @@ CONFIG_MINIX_FS
   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
@@ -8470,16 +8500,16 @@ CONFIG_EXT2_FS
   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
@@ -8490,34 +8520,34 @@ CONFIG_EXT2_FS
   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
 CONFIG_BFS_FS
-  Boot Filesystem (BFS) is a filesystem used under SCO UnixWare to
+  Boot Filesystem (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
+  This is the standard file system used on CDROMs. It was previously
   known as "High Sierra Filesystem" 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.
@@ -8534,7 +8564,7 @@ CONFIG_ISO9660_FS
 
 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
@@ -8543,12 +8573,12 @@ CONFIG_JOLIET
 
 UDF Filesystem 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. 
@@ -8557,32 +8587,32 @@ CONFIG_UDF_FS
 
 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.
@@ -8591,11 +8621,11 @@ CONFIG_FAT_FS
   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
@@ -8610,12 +8640,12 @@ CONFIG_MSDOS_FS
   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.
 
@@ -8628,11 +8658,11 @@ CONFIG_MSDOS_FS
 
 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).
@@ -8647,7 +8677,7 @@ CONFIG_VFAT_FS
   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 file system
 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
@@ -8657,11 +8687,11 @@ CONFIG_UMSDOS_FS
   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/ .
 
@@ -8670,13 +8700,13 @@ CONFIG_UMSDOS_FS
   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
@@ -8722,25 +8752,25 @@ CONFIG_NFS_FS
   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
@@ -8751,7 +8781,7 @@ CONFIG_NFS_FS
 
 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
@@ -8790,16 +8820,16 @@ CONFIG_NFSD_V3
   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.
@@ -8827,7 +8857,7 @@ CONFIG_NTFS_RW
 
   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
@@ -8843,15 +8873,15 @@ CONFIG_SYSV_FS
   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
@@ -8861,7 +8891,7 @@ CONFIG_SYSV_FS
 
   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
@@ -8870,9 +8900,9 @@ CONFIG_SYSV_FS_WRITE
 
   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
@@ -8886,31 +8916,31 @@ CONFIG_AFFS_FS
   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. 
@@ -8918,14 +8948,14 @@ CONFIG_ROMFS_FS
   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. 
@@ -8935,18 +8965,18 @@ CONFIG_QNX4FS_FS
 
 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),
@@ -8961,14 +8991,14 @@ CONFIG_AUTOFS_FS
 
 Kernel automounter v4 support
 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),
@@ -8980,17 +9010,17 @@ CONFIG_AUTOFS4_FS
   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. 
@@ -9000,19 +9030,19 @@ CONFIG_SGI_DISKLABEL
   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
@@ -9023,14 +9053,14 @@ CONFIG_UFS_FS
   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.
@@ -9068,7 +9098,7 @@ CONFIG_BSD_DISKLABEL
   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
@@ -9076,7 +9106,7 @@ CONFIG_SUN_PARTITION
   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
@@ -9090,16 +9120,16 @@ CONFIG_SOLARIS_X86_PARTITION
   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
@@ -9116,10 +9146,10 @@ CONFIG_ADFS_FS
 
   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
@@ -9140,8 +9170,8 @@ CONFIG_UNIXWARE_DISKLABEL
   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" or "System
+  V and Coherent 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
@@ -9152,12 +9182,12 @@ CONFIG_UNIXWARE_DISKLABEL
 
   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
@@ -9178,10 +9208,10 @@ CONFIG_SMB_FS
   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,
@@ -9199,7 +9229,7 @@ CONFIG_CODA_FS
   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
@@ -9307,7 +9337,7 @@ CONFIG_NCPFS_EXTRAS
 
 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
@@ -9318,7 +9348,7 @@ CONFIG_NLS_CODEPAGE_437
 
 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
@@ -9329,7 +9359,7 @@ CONFIG_NLS_CODEPAGE_737
 
 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
@@ -9340,7 +9370,7 @@ CONFIG_NLS_CODEPAGE_775
 
 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
@@ -9355,7 +9385,7 @@ CONFIG_NLS_CODEPAGE_850
 
 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
@@ -9369,7 +9399,7 @@ CONFIG_NLS_CODEPAGE_852
 
 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
@@ -9379,7 +9409,7 @@ CONFIG_NLS_CODEPAGE_855
 
 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
@@ -9389,7 +9419,7 @@ CONFIG_NLS_CODEPAGE_857
 
 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
@@ -9399,7 +9429,7 @@ CONFIG_NLS_CODEPAGE_860
 
 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
@@ -9409,7 +9439,7 @@ CONFIG_NLS_CODEPAGE_861
 
 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
@@ -9419,7 +9449,7 @@ CONFIG_NLS_CODEPAGE_862
 
 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
@@ -9430,7 +9460,7 @@ CONFIG_NLS_CODEPAGE_863
 
 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
@@ -9440,7 +9470,7 @@ CONFIG_NLS_CODEPAGE_864
 
 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
@@ -9451,7 +9481,7 @@ CONFIG_NLS_CODEPAGE_865
 
 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
@@ -9462,7 +9492,7 @@ CONFIG_NLS_CODEPAGE_866
 
 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
@@ -9475,7 +9505,7 @@ CONFIG_NLS_CODEPAGE_869
 
 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
@@ -9486,7 +9516,7 @@ CONFIG_NLS_CODEPAGE_874
 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,
@@ -9497,7 +9527,7 @@ CONFIG_NLS_ISO8859_1
 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
@@ -9507,7 +9537,7 @@ CONFIG_NLS_ISO8859_2
 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,
@@ -9516,7 +9546,7 @@ CONFIG_NLS_ISO8859_3
 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
@@ -9525,7 +9555,7 @@ CONFIG_NLS_ISO8859_4
 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,
@@ -9535,7 +9565,7 @@ CONFIG_NLS_ISO8859_5
 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.
@@ -9543,7 +9573,7 @@ CONFIG_NLS_ISO8859_6
 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.
@@ -9551,7 +9581,7 @@ CONFIG_NLS_ISO8859_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.
@@ -9559,7 +9589,7 @@ CONFIG_NLS_ISO8859_8
 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
@@ -9568,7 +9598,7 @@ CONFIG_NLS_ISO8859_9
 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)
@@ -9578,7 +9608,7 @@ CONFIG_NLS_ISO8859_10
 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)
@@ -9588,7 +9618,7 @@ CONFIG_NLS_ISO8859_14
 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,
@@ -9603,7 +9633,7 @@ CONFIG_NLS_ISO8859_15
 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.
@@ -9938,8 +9968,8 @@ CONFIG_UNIX98_PTYS
   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.*").
@@ -9992,7 +10022,7 @@ CONFIG_LP_CONSOLE
   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.
@@ -10722,7 +10752,7 @@ CONFIG_WATCHDOG
 
 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
@@ -10822,7 +10852,7 @@ CONFIG_RTC
   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
@@ -11015,7 +11045,7 @@ CONFIG_NWBUTTON
   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.
 
@@ -12358,7 +12388,7 @@ CONFIG_ZORRO
   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.
@@ -13137,7 +13167,7 @@ CONFIG_VIDEO_BWQCAM
 
 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
@@ -13190,7 +13220,7 @@ CONFIG_AGP
   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.
 
@@ -13329,7 +13359,7 @@ CONFIG_NWFPE
   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
@@ -13386,12 +13416,12 @@ CONFIG_DEBUG_INFO
   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
@@ -13452,7 +13482,7 @@ CONFIG_HOST_FOOTBRIDGE
 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.
 
@@ -13771,7 +13801,7 @@ Kernel httpd acceleration (EXPERIMENTAL)
 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.
@@ -13847,7 +13877,7 @@ CONFIG_I2C_CHARDEV
 # 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
@@ -13877,7 +13907,7 @@ CONFIG_I2C_CHARDEV
 # 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
@@ -13899,7 +13929,7 @@ CONFIG_I2C_CHARDEV
 # 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
@@ -14004,7 +14034,7 @@ CONFIG_I2C_CHARDEV
 # 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
@@ -14068,7 +14098,7 @@ CONFIG_I2C_CHARDEV
 # 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
index f3fc1dca30aeb180ebefce80bbcaec4e82546638..14237b851ef7dce3a7df64b024ef616300a14a5b 100644 (file)
@@ -28,19 +28,126 @@ First of all, you should make sure
 
 #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 @@ To allocate and map a static DMA region, you should do:
 
 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 @@ To unmap and free such a DMA region, you call:
        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 @@ To map a single region, you do:
 
        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 @@ Similarly with scatterlists, you map a region gathered from several regions by:
        }
 
 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 @@ To unmap a scatterlist, just call:
        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 @@ If you need to use the same streaming DMA region multiple times and touch
 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 @@ returned by the pci_alloc_consistent and pci_map_single calls (pci_map_sg
 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 --git a/Documentation/networking/bridge.txt b/Documentation/networking/bridge.txt
new file mode 100644 (file)
index 0000000..043a14b
--- /dev/null
@@ -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 --git a/Documentation/networking/skfp.txt b/Documentation/networking/skfp.txt
new file mode 100644 (file)
index 0000000..edf275b
--- /dev/null
@@ -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 ***
index e87edfafd7e04b2738ffdf117226cd9e5e3cda7f..7c0c5603262b7e91ee5cd8e5e95b738b3bd9339c 100644 (file)
@@ -330,6 +330,13 @@ M: Philip.Blundell@pobox.com
 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
index 148a413c8d52b847db14d8ecd16c1ac2241230e3..8cbc0c478231ba4b26be2315a843c585e772a895 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -400,6 +400,7 @@ modules_install:
        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; \
index b37a045cf220d19f404b728bfb2986c96a7bc080..72ce8bcb6926d865a3f0d2fe5ba8d9332c8619c3 100644 (file)
@@ -124,7 +124,7 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n)
    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 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size)
    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 @@ pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
        }
        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 @@ void
 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 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end,
 }
 
 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 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
        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;
        }
 
@@ -489,7 +489,7 @@ error:
        /* 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;
 }
 
@@ -499,7 +499,7 @@ error:
    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;
index bc4d2c2ba7db2e815dcb8eb49af8ff83eff69304..d575e20226fea652e7f3626dfc0f424601544572 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/core_pyxis.h>
 
 #include "proto.h"
-#include <asm/hw_irq.h>
 #include "pci_impl.h"
 #include "machvec_impl.h"
 
 
+static void enable_cabriolet_irq(unsigned int irq);
+static void disable_cabriolet_irq(unsigned int irq);
+
+static void enable_cabriolet_srm_irq(unsigned int irq);
+static void disable_cabriolet_srm_irq(unsigned int irq);
+
+#define end_cabriolet_irq              enable_cabriolet_irq
+#define shutdown_cabriolet_irq         disable_cabriolet_irq
+#define mask_and_ack_cabriolet_irq     disable_cabriolet_irq
+
+#define end_cabriolet_srm_irq          enable_cabriolet_srm_irq
+#define shutdown_cabriolet_srm_irq     disable_cabriolet_srm_irq
+#define mask_and_ack_cabriolet_srm_irq disable_cabriolet_srm_irq
+
+static unsigned int
+startup_cabriolet_irq(unsigned int irq)
+{ 
+       enable_cabriolet_irq(irq);
+       return 0; /* never anything pending */
+}
+
+static unsigned int
+startup_cabriolet_srm_irq(unsigned int irq)
+{ 
+       enable_cabriolet_srm_irq(irq);
+       return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type cabriolet_irq_type = {
+       "CABRIOLET",
+       startup_cabriolet_irq,
+       shutdown_cabriolet_irq,
+       enable_cabriolet_irq,
+       disable_cabriolet_irq,
+       mask_and_ack_cabriolet_irq,
+       end_cabriolet_irq,
+};
+
+static struct hw_interrupt_type cabriolet_srm_irq_type = {
+       "CABRIOLET-SRM",
+       startup_cabriolet_srm_irq,
+       shutdown_cabriolet_srm_irq,
+       enable_cabriolet_srm_irq,
+       disable_cabriolet_srm_irq,
+       mask_and_ack_cabriolet_srm_irq,
+       end_cabriolet_srm_irq,
+};
+
+static unsigned long cached_irq_mask = ~0UL;
+
+static inline void
+cabriolet_flush_irq_mask(unsigned long mask)
+{
+       outl(mask >> 16, 0x804);
+}
+
 static void
-cabriolet_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+enable_cabriolet_irq(unsigned int irq)
 {
-       if (irq >= 16)
-               outl(alpha_irq_mask >> 16, 0x804);
-       else if (irq >= 8)
-               outb(mask >> 8, 0xA1);
-       else
-               outb(mask, 0x21);
+       cached_irq_mask &= ~(1UL << irq);
+       cabriolet_flush_irq_mask(cached_irq_mask);
 }
 
+static void
+disable_cabriolet_irq(unsigned int irq)
+{
+       cached_irq_mask |= 1UL << irq;
+       cabriolet_flush_irq_mask(cached_irq_mask);
+}
+
+
 
 /* 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 void
-cabriolet_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmaskp)
+enable_cabriolet_srm_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);
+       cserve_ena(irq - 16);
+}
+
+static void
+disable_cabriolet_srm_irq(unsigned int irq)
+{
+       cserve_dis(irq - 16);
 }
 
+
 static void 
 cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
 {
@@ -86,26 +145,47 @@ cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
                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
+init_TSUNAMI_irqs(struct hw_interrupt_type * ops)
+{
+       int i;
+
+       for (i = 0; i < NR_IRQS; i++) {
+               if (i == RTC_IRQ)
+                       continue;
+               if (i < 16)
+                       continue;
+               if (i >= 35)
+                       break;
+               irq_desc[i].status = IRQ_DISABLED;
+               irq_desc[i].handler = ops;
+       }
+}
+
+static void __init
 cabriolet_init_irq(void)
 {
+       static struct irqaction cascade = { no_action, 0, 0, "sio-cascade", NULL, NULL};
+
        STANDARD_INIT_IRQ_PROLOG;
 
+       init_ISA_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_TSUNAMI_irqs(&cabriolet_srm_irq_type);
        }
        else {
-               outl(alpha_irq_mask >> 16, 0x804);
+               init_TSUNAMI_irqs(&cabriolet_irq_type);
+               cabriolet_flush_irq_mask(~0UL);
        }
 
-       enable_irq(16 + 4);             /* enable SIO cascade */
-       enable_irq(2);                  /* enable cascade */
+       setup_irq(16 + 4, &cascade);    /* enable SIO cascade */
 }
 
 
@@ -260,9 +340,6 @@ struct alpha_machine_vector cabriolet_mv __initmv = {
        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,
@@ -289,9 +366,6 @@ struct alpha_machine_vector eb164_mv __initmv = {
        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,
@@ -317,9 +391,6 @@ struct alpha_machine_vector eb66p_mv __initmv = {
        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,
@@ -345,9 +416,6 @@ struct alpha_machine_vector lx164_mv __initmv = {
        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,
@@ -373,9 +441,6 @@ struct alpha_machine_vector pc164_mv __initmv = {
        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,
index 39421c9850ffef0df8beee7a639e7f081b17f88d..fa54496572171076d3e23eb9b6bb3cd000e4a6c9 100644 (file)
@@ -143,6 +143,8 @@ sx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
 static void
 sx164_init_irq(void)
 {
+       static struct irqaction timer = { no_action, 0, 0, "sx164-timer", NULL, NULL};
+       static struct irqaction cascade = { no_action, 0, 0, "sx164-isa-cascade", NULL, NULL};
        struct hw_interrupt_type *ops;
        long i;
 
@@ -171,8 +173,8 @@ sx164_init_irq(void)
                irq_desc[i].handler = ops;
        }
 
-       ops->startup(16 + 6);   /* enable timer */
-       ops->startup(16 + 7);   /* enable ISA PIC cascade */
+       setup_irq(16 + 6, &timer);      /* enable timer */
+       setup_irq(16 + 7, &cascade);    /* enable ISA PIC cascade */
 }
 
 /*
index 66beb4ee351381bcc38fa93380ff740c885cb342..7589958c81dd76ab48fce3396e3251c5b97d9c92 100644 (file)
@@ -259,13 +259,12 @@ CONFIG_ISO9660_FS=m
 # 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
index b0e330a10bb7fab0d6141202c1ddd7ecbee51712..8c8903d26c71015f169f572dc7f5dddf6b3356b6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.33 2000/02/16 07:31:29 davem 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 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
  * 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 @@ u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len)
 #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 @@ void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n)
 #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 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n)
        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 @@ void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size)
        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 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba)
  * 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 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size)
  * 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 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
  * 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 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
  * 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 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents)
  * 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 @@ void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size)
  * 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,
index 747ded255906f66b418643ac4c40bfc47dbbb1c9..917bb5e745ca41c111cc0dd87e84b9866c49c3b0 100644 (file)
@@ -318,12 +318,12 @@ CONFIG_ISO9660_FS=m
 # 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
index 360b2d7b65d716e6c4e4561b877f6ad4106ca886..00f635ab300aba9cddff3cf5328ded6d4b3e7b5b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.9 2000/02/16 07:31:34 davem 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 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long
        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 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad
        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 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad
                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 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_
 /* 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 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz)
        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 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz)
        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 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz)
 }
 
 /* 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 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz)
        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 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz)
        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 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, un
                                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 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, un
  * 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 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
 
        /* 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 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
        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 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
                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 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
 }
 
 /* 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 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
        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 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
 /* 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 @@ void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz)
 /* 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;
@@ -684,3 +688,19 @@ void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelem
 
        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;
+}
index 5cf9d007d0c496f7c6d080707f93f161d19fddab..b3248de3945cf5983b1d76f00cc9c28893789fdd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.12 2000/02/17 08:58:18 davem 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 @@ static void __init psycho_iommu_init(struct pci_controller_info *p)
        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
index 2833ff94116eeb3d80574eee08931d9a9b092693..e96af490d15220d59cde43a4ceb86cb5d391a205 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.13 2000/02/16 07:31:34 davem 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_scan_bus(struct pci_controller_info *p)
 }
 
 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 @@ static void __init sabre_iommu_init(struct pci_controller_info *p,
        }
        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 @@ void __init sabre_init(int pnode)
        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 @@ void __init sabre_init(int pnode)
                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 @@ void __init sabre_init(int pnode)
                        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]);
 
index bdaa3a17c86f1c3e9ee3f7ab203d31b8adc1c27d..1b454fa2cb76bc6a8d578212bf4c98a7b509e11a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.8 2000/02/16 07:31:34 davem 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 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add
                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 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size)
        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 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size)
        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 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size)
        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 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused)
                                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 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused)
        }
 }
 
-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 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
        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 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
        }
        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 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
        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 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
 
        /* 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 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
        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 @@ void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size)
        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;
index 1e450b7e66d4c77c9cb7f88ba71570d5a2ad324e..3b6f5e56a34eada1f529634d643a09f1bcf37b97 100644 (file)
@@ -214,6 +214,10 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
        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 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
                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 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
                                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 @@ void ide_destroy_dmatable (ide_drive_t *drive)
        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);
 }
 
 /*
index 4b96ae1d3637a1f177d89f2ee1529fdd8cf54618..4123a73649abb67f77f92d20920a0e838cffa7d8 100644 (file)
 #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 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                        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 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                                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 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                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 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                        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 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status)
        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 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status)
        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 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status)
                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 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
                
                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 @@ int fcp_initialize(fc_channel *fcchain, int count)
                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 @@ int fcp_initialize(fc_channel *fcchain, int count)
                                } 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 @@ int fcp_initialize(fc_channel *fcchain, int count)
 
                                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 @@ int fcp_initialize(fc_channel *fcchain, int count)
                                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 @@ all_done:
                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 @@ static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, i
                        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 @@ static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len)
        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 @@ static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len)
        
        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;
 }
 
index 8d33f08f36b0991a1b4fb8df2dd3619578c244b1..839c15ebcce2f873f271ac9c5f9ee8b6b16e3f03 100644 (file)
@@ -1085,7 +1085,7 @@ vortex_open(struct net_device *dev)
                                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 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
                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 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                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 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                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 @@ static int vortex_rx(struct net_device *dev)
                                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 @@ boomerang_rx(struct net_device *dev)
                                && (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 @@ boomerang_rx(struct net_device *dev)
                                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 @@ boomerang_rx(struct net_device *dev)
                                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 @@ vortex_close(struct net_device *dev)
                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 @@ vortex_close(struct net_device *dev)
                        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;
                        }
index 6b86426fcaf0a4b0a5c224eb446d692ac11011dd..7439f809b4114086be9ae65625dfbd80fe85bb65 100644 (file)
@@ -1196,7 +1196,7 @@ static void rtl8139_tx_timeout (struct net_device *dev)
                        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;
                }
        }
@@ -1252,7 +1252,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
                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);
@@ -1328,7 +1328,8 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
                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. */
@@ -1669,7 +1670,7 @@ static int rtl8139_close (struct net_device *dev)
 
                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;
index bf3350a85e7f7ae7efaf31dabc8f0b1778ae42a0..2874bad9fde03c677c322957bb3c0334304102c5 100644 (file)
@@ -189,6 +189,7 @@ endmenu
 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
index 55e6d0e46a41cc9ea819de54122cbd79036249ef..0daf888875b063e6d5581697ceadbf195d8d32ab 100644 (file)
@@ -17,7 +17,8 @@ obj-            :=
 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
@@ -137,6 +138,15 @@ else
   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
+
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
 
index 9e2ba1a91eb558942397a2f91c58afb14e05e323..e3a53d7711c8e8d1ab32a4ec2745d348acde8d1c 100644 (file)
@@ -120,6 +120,7 @@ extern int de620_probe(struct net_device *);
 /* 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 @@ static int __init fddiif_probe(struct net_device *dev)
 #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. */
index c57d22f0fe3b3034250f020f70d24679add8ae35..3587dfe16a671d3c7a3f248859051aeb84450166 100644 (file)
@@ -121,8 +121,8 @@ static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
        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)
@@ -632,7 +632,8 @@ void __exit ace_module_cleanup(void)
                                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);
                        }
                }
@@ -647,7 +648,8 @@ void __exit ace_module_cleanup(void)
                                        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);
                                }
                        }
@@ -662,7 +664,8 @@ void __exit ace_module_cleanup(void)
                                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);
                        }
                }
@@ -1020,6 +1023,21 @@ static int __init ace_init(struct net_device *dev, int board_idx)
                        }
                }
        }
+#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);
 
        /*
@@ -1477,7 +1495,8 @@ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
                 */
                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;
 
@@ -1538,7 +1557,8 @@ static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs)
                 */
                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;
 
@@ -1596,7 +1616,8 @@ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs)
                 */
                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;
 
@@ -1774,7 +1795,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 
                skb = rip->skb;
                rip->skb = NULL;
-               pci_unmap_single(ap->pdev, rip->mapping, mapsize);
+               pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE);
                skb_put(skb, retdesc->size);
 #if 0
                /* unncessary */
@@ -1881,7 +1902,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 
                        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;
@@ -2122,7 +2143,7 @@ static int ace_close(struct net_device *dev)
                        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;
                }
@@ -2172,7 +2193,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        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);
index 15a5f22725e031563b383cb317ed6c4011fa3bf3..81e0dbdaea468dfaa7d42f8f87d615e3b5b4b168 100644 (file)
@@ -1759,7 +1759,8 @@ static inline void
 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;
@@ -1980,7 +1981,7 @@ load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
     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);
index c0ee881d1d94a5ab7607028f275c215dd2c710a1..98e0de005cb87d3f604451b4efff7c11be959186 100644 (file)
@@ -1101,7 +1101,7 @@ speedo_init_rx_ring(struct net_device *dev)
                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]);
@@ -1202,7 +1202,7 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
                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
@@ -1300,14 +1300,15 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                        sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
                                        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++;
@@ -1392,7 +1393,7 @@ speedo_rx(struct net_device *dev)
                                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);
@@ -1414,7 +1415,7 @@ speedo_rx(struct net_device *dev)
                                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);
@@ -1440,7 +1441,7 @@ speedo_rx(struct net_device *dev)
                        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;
@@ -1489,7 +1490,7 @@ speedo_close(struct net_device *dev)
                if (skb) {
                        pci_unmap_single(sp->pdev,
                                         sp->rx_ring_dma[i],
-                                        PKT_BUF_SZ + sizeof(struct RxFD));
+                                        PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(skb);
                }
        }
@@ -1502,7 +1503,7 @@ speedo_close(struct net_device *dev)
                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);
                }
        }
@@ -1747,7 +1748,7 @@ static void set_rx_mode(struct net_device *dev)
                /* 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. */
index 3c4e230166c16f2b91bfa8d6128a3b5681d0b593..bd1406e1f65a11a9842caeb2e909edc6749cabb4 100644 (file)
@@ -256,7 +256,7 @@ static void myri_clean_rings(struct myri_eth *mp)
                        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 @@ static void myri_clean_rings(struct myri_eth *mp)
                        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 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
                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 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
 
                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 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
                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 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
                        }
                        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 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
                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);
index 50e7eb382bfac180e721e6c9a91d170cedea12e9..b60a626086c4586e60f28f587feb682581112dd6 100644 (file)
@@ -908,7 +908,7 @@ static void rtl8129_tx_timeout(struct net_device *dev)
 
                        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 @@ static void rtl8129_tx_timeout(struct net_device *dev)
                                         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 @@ rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev)
                         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 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                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 @@ rtl8129_close(struct net_device *dev)
 
                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;
index 27d0dba242a23ba5b303e90ca5a2b38233df33ae..f6710a0b5ffef9fc6503f9946cfdd7c011175b7e 100644 (file)
@@ -1606,7 +1606,8 @@ int               BytesSend;
        /* 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;
@@ -1699,7 +1700,8 @@ SK_U64    PhysAddr;       /* address of DMA mapping */
                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);
 
                /* free message */
                DEV_KFREE_SKB_ANY(pTxd->pMBuf);
@@ -1780,7 +1782,8 @@ SK_U64            PhysAddr;       /* physical address of a rx buffer */
        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;
@@ -1903,7 +1906,8 @@ rx_start:
                                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,
@@ -1923,7 +1927,8 @@ rx_start:
                        /* 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);
@@ -2081,7 +2086,8 @@ rx_failed:
        PhysAddr |= (SK_U64) pRxd->VDataLow;
        pci_unmap_single(&pAC->PciDev,
                         PhysAddr,
-                        pAC->RxBufSize - 2);
+                        pAC->RxBufSize - 2,
+                        PCI_DMA_FROMDEVICE);
        DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
        pRxd->pMBuf = NULL;
        pRxPort->RxdRingFree++;
@@ -2160,7 +2166,8 @@ unsigned int      Flags;
                        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;
                }
@@ -3511,8 +3518,8 @@ unsigned int      Flags;
                pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
                skb_put(pMsg, pRlmtMbuf->Length);
                if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
-                             pMsg) <= 0)
-                       DEV_KFREE_SKB(pMsg);
+                             pMsg) < 0)
+                       DEV_KFREE_SKB_ANY(pMsg);
                break;
        default:
                break;
diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile
new file mode 100644 (file)
index 0000000..82aa26e
--- /dev/null
@@ -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 --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c
new file mode 100644 (file)
index 0000000..8a49abc
--- /dev/null
@@ -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 --git a/drivers/net/skfp/cfm.c b/drivers/net/skfp/cfm.c
new file mode 100644 (file)
index 0000000..7a51b76
--- /dev/null
@@ -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 --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
new file mode 100644 (file)
index 0000000..e1e48bc
--- /dev/null
@@ -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 --git a/drivers/net/skfp/ecm.c b/drivers/net/skfp/ecm.c
new file mode 100644 (file)
index 0000000..4111692
--- /dev/null
@@ -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 --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
new file mode 100644 (file)
index 0000000..868237b
--- /dev/null
@@ -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 --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
new file mode 100644 (file)
index 0000000..83a9357
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/skfp/h/cmtdef.h
new file mode 100644 (file)
index 0000000..0b54c57
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/fddi.h b/drivers/net/skfp/h/fddi.h
new file mode 100644 (file)
index 0000000..c9a28a8
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/fddimib.h b/drivers/net/skfp/h/fddimib.h
new file mode 100644 (file)
index 0000000..d1acdc7
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/fplustm.h b/drivers/net/skfp/h/fplustm.h
new file mode 100644 (file)
index 0000000..9e1ce03
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/hwmtm.h b/drivers/net/skfp/h/hwmtm.h
new file mode 100644 (file)
index 0000000..4e360af
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/lnkstat.h b/drivers/net/skfp/h/lnkstat.h
new file mode 100644 (file)
index 0000000..c73dcd9
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/mbuf.h b/drivers/net/skfp/h/mbuf.h
new file mode 100644 (file)
index 0000000..b339d1f
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/osdef1st.h b/drivers/net/skfp/h/osdef1st.h
new file mode 100644 (file)
index 0000000..69f2770
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/sba.h b/drivers/net/skfp/h/sba.h
new file mode 100644 (file)
index 0000000..df716cd
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/sba_def.h b/drivers/net/skfp/h/sba_def.h
new file mode 100644 (file)
index 0000000..0459a09
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h
new file mode 100644 (file)
index 0000000..f127bdd
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h
new file mode 100644 (file)
index 0000000..79d55ad
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/smc.h b/drivers/net/skfp/h/smc.h
new file mode 100644 (file)
index 0000000..b909586
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/smt.h b/drivers/net/skfp/h/smt.h
new file mode 100644 (file)
index 0000000..08eb1cc
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/smt_p.h b/drivers/net/skfp/h/smt_p.h
new file mode 100644 (file)
index 0000000..99f9be9
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/smtstate.h b/drivers/net/skfp/h/smtstate.h
new file mode 100644 (file)
index 0000000..689fa25
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/supern_2.h b/drivers/net/skfp/h/supern_2.h
new file mode 100644 (file)
index 0000000..ea564b3
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h
new file mode 100644 (file)
index 0000000..5e6f3a0
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/targetos.h b/drivers/net/skfp/h/targetos.h
new file mode 100644 (file)
index 0000000..dd88fb3
--- /dev/null
@@ -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 --git a/drivers/net/skfp/h/types.h b/drivers/net/skfp/h/types.h
new file mode 100644 (file)
index 0000000..43b48ff
--- /dev/null
@@ -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 --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
new file mode 100644 (file)
index 0000000..366b3b8
--- /dev/null
@@ -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 --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c
new file mode 100644 (file)
index 0000000..7d51b8b
--- /dev/null
@@ -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 --git a/drivers/net/skfp/lnkstat.c b/drivers/net/skfp/lnkstat.c
new file mode 100644 (file)
index 0000000..7d2d94e
--- /dev/null
@@ -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 --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c
new file mode 100644 (file)
index 0000000..5479b27
--- /dev/null
@@ -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 --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
new file mode 100644 (file)
index 0000000..d53355b
--- /dev/null
@@ -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 --git a/drivers/net/skfp/queue.c b/drivers/net/skfp/queue.c
new file mode 100644 (file)
index 0000000..e54b544
--- /dev/null
@@ -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 --git a/drivers/net/skfp/rmt.c b/drivers/net/skfp/rmt.c
new file mode 100644 (file)
index 0000000..473eb0c
--- /dev/null
@@ -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 --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
new file mode 100644 (file)
index 0000000..6aceec4
--- /dev/null
@@ -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 --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
new file mode 100644 (file)
index 0000000..ed85389
--- /dev/null
@@ -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 --git a/drivers/net/skfp/smtdef.c b/drivers/net/skfp/smtdef.c
new file mode 100644 (file)
index 0000000..221b033
--- /dev/null
@@ -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 --git a/drivers/net/skfp/smtinit.c b/drivers/net/skfp/smtinit.c
new file mode 100644 (file)
index 0000000..c4b5af9
--- /dev/null
@@ -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 --git a/drivers/net/skfp/smtparse.c b/drivers/net/skfp/smtparse.c
new file mode 100644 (file)
index 0000000..0b4a227
--- /dev/null
@@ -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 --git a/drivers/net/skfp/smttimer.c b/drivers/net/skfp/smttimer.c
new file mode 100644 (file)
index 0000000..9d7b71e
--- /dev/null
@@ -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 --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c
new file mode 100644 (file)
index 0000000..79bbfed
--- /dev/null
@@ -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 */
index 30e9e5b3dc374be95c20af774ed2cd36467cda8a..de085602052bd4daa38218b00a71bb074765af4f 100644 (file)
@@ -813,7 +813,7 @@ static void init_ring(struct net_device *dev)
                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 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
        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 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
                                        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 @@ static int netdev_rx(struct net_device *dev)
                                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 @@ static int netdev_rx(struct net_device *dev)
                        } 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 @@ static int netdev_rx(struct net_device *dev)
                        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 @@ static int netdev_close(struct net_device *dev)
        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 @@ static int netdev_close(struct net_device *dev)
                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;
index bd30b9c16aafcca08e2dcc9bd077de530c6c178e..6a773b66d3fa9a3206ae16c8bb7337bd57b5fa14 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.17 2000/02/17 18:29:04 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)
@@ -234,7 +234,8 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq)
 
                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));
        }
@@ -770,7 +771,8 @@ static void bigmac_tx(struct bigmac *bp)
                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;
@@ -825,14 +827,16 @@ static void bigmac_rx(struct bigmac *bp)
                        }
                        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));
 
@@ -849,7 +853,7 @@ static void bigmac_rx(struct bigmac *bp)
                        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. */
@@ -945,7 +949,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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);
index 76baa77024ed6e481047ed1f471631d255e31c78..344e682f818e5b2b40e989e8e6808893b18a12f9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.91 2000/02/17 18:29:02 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.
@@ -228,12 +228,12 @@ static u32 pci_hme_read_desc32(u32 *p)
        ((__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 */
@@ -252,12 +252,12 @@ do {      (__txd)->tx_addr = (__addr); \
        (__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) \
@@ -275,15 +275,19 @@ do {      (__txd)->tx_addr = cpu_to_le32(__addr); \
        (__txd)->tx_flags = cpu_to_le32(__flags); \
 } while(0)
 #define hme_read_desc32(__hp, __p)     cpu_to_le32p(__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_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)
 {
@@ -1208,7 +1212,7 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
 
                        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);
+                       hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
                        dev_kfree_skb_any(skb);
                        hp->rx_skbs[i] = NULL;
                }
@@ -1222,7 +1226,7 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
 
                        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);
+                       hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);
                        dev_kfree_skb_any(skb);
                        hp->tx_skbs[i] = NULL;
                }
@@ -1262,7 +1266,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
                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);
        }
 
@@ -1904,7 +1908,7 @@ static void happy_meal_tx(struct happy_meal *hp)
                        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;
 
@@ -1982,13 +1986,13 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
                                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. */
@@ -2004,7 +2008,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
                        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. */
@@ -2187,7 +2191,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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);
 
@@ -2652,9 +2656,9 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
        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
@@ -2827,9 +2831,9 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
        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
index 3708515e3fdda9f33692d1cb7009b0e0d8c0b25a..57b5d7f5e2b3c9ac8bafe63e62491e975d7f63b0 100644 (file)
@@ -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 @@ struct happy_meal {
        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. */
index 29206729ad9414a30e41a4191cb7606f2e9f7236..beb0a68b77fe58df38fcec8bf3f3efc176cd5953 100644 (file)
@@ -561,7 +561,8 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
                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 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
        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;
 }
index 82e0fc4941a8161ac2ac526743716f43efa94dea..e155a73b47fdfdde42accc488257eecfebdfb2eb 100644 (file)
@@ -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 int cs4231_open(struct inode * inode, struct file * file, struct sparcaud
 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 @@ static void cs4231_release(struct inode * inode, struct file * file, struct spar
                 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 @@ static void cs4231_release(struct inode * inode, struct file * file, struct spar
                 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 @@ static void cs4231_playintr(struct sparcaudio_driver *drv, int push)
         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 @@ static void cs4231_playintr(struct sparcaudio_driver *drv, int push)
                 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 @@ static void eb4231_playintr(struct sparcaudio_driver *drv)
         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 @@ static void eb4231_playintr(struct sparcaudio_driver *drv)
                 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 @@ static int cs4231_recintr(struct sparcaudio_driver *drv)
         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 @@ static int cs4231_recintr(struct sparcaudio_driver *drv)
                 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 @@ static int eb4231_recintr(struct sparcaudio_driver *drv)
         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 @@ static int eb4231_recintr(struct sparcaudio_driver *drv)
                 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 @@ static void eb4231_stop_output(struct sparcaudio_driver *drv)
         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 @@ static void eb4231_stop_output(struct sparcaudio_driver *drv)
         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 @@ static void cs4231_stop_output(struct sparcaudio_driver *drv)
         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 @@ static void cs4231_stop_output(struct sparcaudio_driver *drv)
         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 @@ static void cs4231_stop_input(struct sparcaudio_driver *drv)
         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 @@ static void cs4231_stop_input(struct sparcaudio_driver *drv)
         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 @@ static void eb4231_stop_input(struct sparcaudio_driver *drv)
         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 @@ static void eb4231_stop_input(struct sparcaudio_driver *drv)
         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;
         }
index a3f083eada9d190226becb645c408958aaca7c01..45ee9dd1b4f24666b4155771e343d28c641e97cf 100644 (file)
@@ -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 @@ static void transmission_complete_intr(struct dbri *dbri, int pipe)
                 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 @@ static void reception_complete_intr(struct dbri *dbri, int pipe)
         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 @@ static void reset_pipe(struct dbri *dbri, int pipe)
                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 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
                 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 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
         }
 
        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 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
 
         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 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
         /* 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 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
                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 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
 
        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;
 
index 9920f33c4aee53be7f03c4c627b0da95bdd73a02..e146ec1c4909eb4b487631114fde93b180cde358 100644 (file)
@@ -2899,11 +2899,12 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     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, le32_to_cpu(scb->sg_list[0].address),
-                    le32_to_cpu(scb->sg_list[0].length));
+                    le32_to_cpu(scb->sg_list[0].length),
+                     scsi_to_pci_dma_dir(cmd->sc_data_direction));
   if (scb->flags & SCB_RECOVERY_SCB)
   {
     p->flags &= ~AHC_ABORT_PENDING;
@@ -4887,7 +4888,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 }
                scb->sg_list[0].address =
                         cpu_to_le32(pci_map_single(p->pdev, sense_buffer,
-                                                   sizeof(cmd->sense_buffer)));
+                                                   sizeof(cmd->sense_buffer),
+                                                   scsi_to_pci_dma_dir(cmd->sc_data_direction)));
                 hscb->data_pointer = scb->sg_list[0].address;
 
                 scb->flags |= SCB_SENSE;
@@ -10607,6 +10609,7 @@ aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
   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 +10957,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
 
     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 +10984,8 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     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));
       scb->sg_list[0].address = cpu_to_le32(address);
       scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
       scb->sg_count = 1;
index dd603456178e2cecfe8800c0fbeb08f63a2bbae1..725a70a4a9eb01a2630e2acd529a44dbc89cb8be 100644 (file)
@@ -167,6 +167,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
        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 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
            cmnd[9] = 0;
            
            scmd->cmd_len = 10;
+           scmd->sc_data_direction = SCSI_DATA_READ;
 
            /*
             * Do the command and wait for it to finish.
index 57802859cbc63d6c8faffa82c889c14c53214836..fccfb59c86361a0bdf2d43d53ef1cf28a96034db 100644 (file)
@@ -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 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
                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 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
                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_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
 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));
        }
 }
 
index 83efa5df6e35207d3474e923c1dacddb47e1ece7..e07417b7e3bed3ca06d577c6b18b65e4d854cfa6 100644 (file)
 #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
 
@@ -119,6 +127,28 @@ static int WaitReady (PADAPTER2000 padapter)
                };                                                              
        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
  *
@@ -204,7 +234,7 @@ static int PsiRaidCmd (PADAPTER2000 padapter, char cmd)
        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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
        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 @@ irqProceed:;
        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 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
        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 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
                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 @@ int Pci2000_Release (struct Scsi_Host *pshost)
     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 @@ Scsi_Host_Template driver_template = PCI2000;
 
 #include "scsi_module.c"
 #endif
-
index 9b80a489b07e1afe6088444e5a145c685e36a544..a3daa5f76304ffc1173624c040d0a6420227db6e 100644 (file)
@@ -200,10 +200,13 @@ int Pci2000_BiosParam             (Disk *disk, kdev_t dev, int geom[]);
        #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 @@ int Pci2000_BiosParam              (Disk *disk, kdev_t dev, int geom[]);
                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
index e50ba45dc93053e05cb7a1ed14c7c29df9ff3ef2..80f58cb8ee2f0b1fd34df40952e634f7a37a490c 100644 (file)
  *     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>
 #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
 
 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 @@ typedef struct
        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 @@ typedef struct
        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 @@ typedef struct
        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 @@ typedef struct
 
 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 @@ static void MuteAlarm (PADAPTER2220I padapter)
        {
        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 @@ static int WaitReadyReset (PADAPTER2220I padapter)
        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;
        }
 /****************************************************************
@@ -251,6 +312,52 @@ static int WaitDrq (PADAPTER2220I padapter)
                }
        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
  *
@@ -265,23 +372,112 @@ static int WaitDrq (PADAPTER2220I padapter)
  ****************************************************************/
 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
  *
@@ -291,34 +487,84 @@ static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
  *                                     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 @@ static int WriteData (PADAPTER2220I padapter)
                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 @@ static int WriteData (PADAPTER2220I padapter)
  *
  *     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 @@ static int WriteDataBoth (PADAPTER2220I padapter)
                }
        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 @@ static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
        {
        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 @@ static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
  *     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 @@ static UCHAR IdeCmdBoth (PADAPTER2220I padapter)
                }
        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 @@ static void OpDone (PADAPTER2220I padapter, ULONG result)
                {
                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 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
        {
        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);  
@@ -534,6 +783,192 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
        insw (padapter->regData, padapter->kBuffer, sizeof (IDENTIFY_DATA) >> 1);
        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
  *
@@ -549,10 +984,9 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
 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 @@ static ULONG DecodeError (PADAPTER2220I   padapter, UCHAR status)
        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 WriteSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigo
  ******************************************************************************************************/
 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 @@ static void TimerExpiry (unsigned long data)
        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 @@ static void TimerExpiry (unsigned long data)
                        {
                        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 @@ static void TimerExpiry (unsigned long data)
                                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 @@ static void TimerExpiry (unsigned long data)
                                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 @@ static void TimerExpiry (unsigned long data)
                        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 @@ static void TimerExpiry (unsigned long data)
                        
                                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 @@ static void TimerExpiry (unsigned long data)
                                                }               
                                        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 @@ static void TimerExpiry (unsigned long data)
                        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 @@ static void TimerExpiry (unsigned long data)
        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 @@ static LONG SetReconstruct (POUR_DEVICE pdev, int index)
        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 @@ static void ReconTimerExpiry (unsigned long data)
        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 @@ static void ReconTimerExpiry (unsigned long data)
                        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);
-
-               while ( 1 )
+               if ( padapter->bigD )
                        {
-                       if ( HardReset (padapter, pdev, pdev->hotRecon) )
+                       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 )
+                       {
+                       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 @@ static void ReconTimerExpiry (unsigned long data)
                        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 @@ static void ReconTimerExpiry (unsigned long data)
        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 @@ static void ReconTimerExpiry (unsigned long data)
 
        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 @@ static void ReconTimerExpiry (unsigned long data)
        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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
        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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
        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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                goto irq_return;
                }
        padapter->expectingIRQ = 0;
-       outb_p (0x08, padapter->regDmaCmdStat);                                                                 // cancel interrupt from DMA engine
 
        if ( padapter->failinprog )
                {
@@ -1178,7 +1763,7 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                        {
                                        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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                        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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                        }
                                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                        {
                                        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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                        }
                                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                                }
                                        }
                                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                {
                                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                        }
                                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 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
                                }
                        if ( padapter->sectorCount )    
                                {       
-                               SelectSpigot (padapter, pdev->spigot);
+                               SelectSpigot (padapter, pdev->spigot | padapter->bigD);
                                status = WriteData (padapter);
                                if ( status )
                                        break;
@@ -1458,12 +2077,20 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
 
        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 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        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 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                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 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                                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 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                                                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 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 
        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 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                else
                        padapter->survivor = 0;
                                DEB (printk ("\npci2220i: FAILURE 19"));
-               if ( InitFailover (padapter, pdev ) )
+               if ( InitFailover (padapter, pdev) )
                        break;
                return 0;
                }
@@ -1618,14 +2330,14 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        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 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                }
        return 0;
        }
-
 static void internal_done(Scsi_Cmnd *SCpnt)
        {
        SCpnt->SCp.Status++;
@@ -1692,24 +2403,191 @@ int Pci2220i_Command (Scsi_Cmnd *SCpnt)
  *     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
  *
@@ -1722,204 +2600,284 @@ VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
  ****************************************************************/
 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 @@ unregister:;
  ****************************************************************/
 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_Abort (Scsi_Cmnd *SCpnt)
  ****************************************************************/
 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_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
 int Pci2220i_Release (struct Scsi_Host *pshost)
        {
     PADAPTER2220I      padapter = HOSTDATA (pshost);
+       USHORT                  z;
 
        if ( padapter->reconOn )
                {
@@ -1981,11 +2962,29 @@ int Pci2220i_Release (struct Scsi_Host *pshost)
                }
 
        // 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 @@ int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
        {
        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;
        }
 
index 1c75c8c3b2a77dacc60ca1aabab3449cb79a743e..aaa8457fc1ca71a8f29a55ccc5f26432354025a0 100644 (file)
 #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 @@ int Pci2220i_BiosParam             (Disk *disk, kdev_t dev, int geom[]);
        #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 @@ int Pci2220i_BiosParam             (Disk *disk, kdev_t dev, int geom[]);
                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
index bb7c8006b319c130055cf4500db14a55ccd76fa0..03da4c3b8066d1a0871d59b4e23bfe81a0ea28cb 100644 (file)
  *
  ****************************************************************************/
 
+/************************************************/
+/*             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
 
 /************************************************/
 /*             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_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_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_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_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
 
 /************************************************/
-/*             Dale cable select bits                                  */
+/*             BigD Scratchpad locations                               */
 /************************************************/
-#define        SEL_NONE                                                0x00
-#define        SEL_1                                                   0x01
-#define        SEL_2                                                   0x02
+#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
 
 /************************************************/
-/*             Programmable Interrupt Controller               */
+/*             Dale cable select bits                                  */
 /************************************************/
-#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                                */
 #define        DEVICE_DASD_NONLBA                      0x3                             // Non LBA incompatible device
 #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                             */
 /************************************************/
@@ -168,11 +242,11 @@ typedef struct            // master setup structure
        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 @@ typedef struct    DEVICE_RAID1
 #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 ()
index 31cd06cccf82501e612e4de18aa687a82d0d58c8..3125bd28fdc1c0302e4e60b92d3bdb217c9ec0f6 100644 (file)
@@ -810,7 +810,8 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
                sg = (struct scatterlist *) Cmnd->request_buffer;
                ds = cmd->dataseg;
 
-               sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg);
+               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);
 
@@ -856,7 +857,8 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
                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);
@@ -977,11 +979,13 @@ void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
                if (Cmnd->use_sg)
                        pci_unmap_sg(hostdata->pci_dev,
                                     (struct scatterlist *)Cmnd->buffer,
-                                    Cmnd->use_sg);
+                                    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);
index 89265a47f0f7b39752a3f2d488b1371014507483..d61c832c5cf0fb7e98be39817b512f60d2d5a7c6 100644 (file)
@@ -1036,7 +1036,7 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
                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 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
                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 @@ static Scsi_Cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
                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);
index e59bd318905568031d886b0c1151c924934dd42a..a6e2c14d935302545ec356c7067ac8299e376fb4 100644 (file)
@@ -224,6 +224,8 @@ void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
 {
        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,
index 47fbcc171524acac10ce7f44e41f78fbe052e251..7a073f86efb3f3d4c0420cdabf7b7a526d2ab73c 100644 (file)
 #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.
  */
index ae01a6dd4f8b9fc846d15293a7762009fa8ed48c..a957a4c017e3c78ea610b8c25adce68eee812a59 100644 (file)
@@ -231,7 +231,7 @@ static void scsi_request_sense(Scsi_Cmnd * SCpnt)
        SCpnt->use_sg = 0;
        SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
        SCpnt->result = 0;
-       SCpnt->sc_data_direction = SCSI_DATA_NONE;
+       SCpnt->sc_data_direction = SCSI_DATA_READ;
 
         /*
          * Ugly, ugly.  The newer interfaces all assume that the lock
index 6f22c402244655d50d757cb5d2009e0d2b176a80..40a7cb1240af1c48927e939b45c26d6bd67dcb0a 100644 (file)
@@ -705,7 +705,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
                scsi_cmd[4] = 0x2a;
                scsi_cmd[5] = 0;
                SCpnt->cmd_len = 0;
-               SCpnt->sc_data_direction = SCSI_DATA_NONE;
+               SCpnt->sc_data_direction = SCSI_DATA_READ;
                scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
                        (void *) scsi_result, 0x2a,
                        SCSI_TIMEOUT, 3);
index e25ed2423d28a668a418d10300392542c2ee5136..43187600bfb4be8f7123be9d3a8e5b0af283416a 100644 (file)
@@ -697,7 +697,7 @@ static int sd_init_onedisk(int i)
                        SCpnt->cmd_len = 0;
                        SCpnt->sense_buffer[0] = 0;
                        SCpnt->sense_buffer[2] = 0;
-                       SCpnt->sc_data_direction = SCSI_DATA_NONE;
+                       SCpnt->sc_data_direction = SCSI_DATA_READ;
 
                        scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
                                0/*512*/, SD_TIMEOUT, MAX_RETRIES);
@@ -741,7 +741,7 @@ static int sd_init_onedisk(int i)
                                SCpnt->sense_buffer[0] = 0;
                                SCpnt->sense_buffer[2] = 0;
 
-                               SCpnt->sc_data_direction = SCSI_DATA_NONE;
+                               SCpnt->sc_data_direction = SCSI_DATA_READ;
                                scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
                                            0/*512*/, SD_TIMEOUT, MAX_RETRIES);
                        }
index 916782fb28b4db5cb02de0cb54373fb94e67163e..df803226a0dc8b352b747b2c2d83a192ed5d05c8 100644 (file)
@@ -9,24 +9,24 @@ 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
@@ -84,9 +84,9 @@ mainmenu_option next_comment
 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
@@ -109,10 +109,10 @@ if [ "$CONFIG_INET" = "y" ]; then
    if [ "$CONFIG_NFSD_V3" == "y" ]; then
      define_bool CONFIG_LOCKD_V4 y
    fi
-   tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS
+   tristate 'SMB file system support (to mount WfW 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
index 96fd4912eef068cac96854d3a49e4828ab8849dd..0cf0e1c757e460476580061a54cee70cf42ab205 100644 (file)
@@ -76,7 +76,7 @@ extern void pci_free_consistent(struct pci_dev *, long, void *, dma_addr_t);
    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 *, 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 @@ extern dma_addr_t pci_map_single(struct pci_dev *, void *, long);
    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 @@ extern void pci_unmap_single(struct pci_dev *, dma_addr_t, long);
    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 @@ extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int);
    again owns the buffer.  */
 
 extern inline void
-pci_dma_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 @@ pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size)
    for a scatter-gather list, same rules and usage.  */
 
 extern inline void
-pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents)
+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 */
index 86ade5703166b44ba612617cfaa30c001aed3c42..e0de271b391f74e0b995f98b807e0697e223dbd5 100644 (file)
@@ -56,7 +56,7 @@ pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
  * 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 @@ pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size)
  * 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 @@ pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
  * 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_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
  * 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 @@ pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
  * 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,7 +133,7 @@ pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size)
  * 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;
 
@@ -141,6 +141,16 @@ pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems)
                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
  * to get bus addresses of each of the SG entries and their lengths.
  * You should only work with the number of sg entries pci_map_sg
index 8cc99dda0f4efbddded02009694ee49b4e1f45f6..1e55ec60fe47bff33bce7c5e58aa4da48f0bf38a 100644 (file)
@@ -52,8 +52,10 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
  * 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 @@ extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
  * 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 @@ extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
  * 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 @@ extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
  * 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_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
  */
 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,11 +135,23 @@ extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
  */
 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
  * to get bus addresses of each of the SG entries and their lengths.
  * You should only work with the number of sg entries pci_map_sg
index bb3e4fb2112d8eaf0fe93d7b9799d3ad7fa2eec4..de50f98f062703ab4266bb5491831f47934660f5 100644 (file)
@@ -55,8 +55,10 @@ extern void pci_free_consistent (struct pci_dev *hwdev, size_t size,
  * 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 @@ pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size)
  * 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 @@ pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
  * 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_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents)
  * 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 @@ pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents)
  * 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,11 +141,23 @@ pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size)
  * 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
  * to get bus addresses of each of the SG entries and their lengths.
  * You should only work with the number of sg entries pci_map_sg
index 92347e40673a9e3a021c6babf6defc6517cb3811..5d022e02c9db56a6abd1ce3701b468868edd660b 100644 (file)
@@ -27,38 +27,60 @@ extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 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))
 #define sg_dma_len(sg)         ((sg)->length)
 
index a2749a907258d5a854f0b419fd3f86c6ff4f8ae3..80ea9d11d0dfa54dd16d91c117e920b5a36e821a 100644 (file)
@@ -40,7 +40,7 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
  * 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 @@ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size);
  * 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 @@ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t
  * 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 @@ extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwe
  * 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 @@ extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, si
  * 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__ */
 
index b7f2b8f9ea4f356a4c1ab35a026160c9f5ba1637..6a687a465c214a005eba16b783ae2fa170ae313d 100644 (file)
@@ -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 @@ sbus_is_slave(struct sbus_dev *dev)
        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) */
index abf50c2424631dcd1942a3be8638d508d2aedc55..25cc6dd9f524130783537e7add190b8ae6d6220d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.27 2000/02/15 02:58:40 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 linux_ebus_dma *sun_pci_fd_ebus_dma;
 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 @@ static void sun_pci_fd_disable_dma(void)
        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 @@ static void sun_pci_fd_set_dma_mode(int mode)
         * 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 @@ static void sun_pci_fd_set_dma_addr(char *buffer)
 
        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);
 }
 
index 12f015edb4b3bedac94487e232b62c6c47bc6470..22281b176dfe8db964d662ba2e105ce57cffcfa6 100644 (file)
@@ -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 @@ struct pci_iommu {
         * 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. */
index 881de6c2f06a16b9eab9478c08fbca306d7fce7d..267cbf797c26b5bd23a93363d8bfc074cab6048c 100644 (file)
@@ -40,7 +40,7 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
  * 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 @@ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size);
  * 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 @@ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t
  * 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 @@ extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwe
  * 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 @@ extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, si
  * 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__ */
 
index f8c5e247f0fc15d8ae7dab46d72c463a5e1d7017..e9f7344b47cff40ebe24e6bb0cc2c9df710e3544 100644 (file)
@@ -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_set_sbus64(struct sbus_dev *, int);
 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) */
index 6d95ad2df605a30dde28ec6ffe1f07ef85015a23..957d024684b3b9b690f15b8ffde724b6865b1137 100644 (file)
@@ -379,6 +379,7 @@ typedef struct hwif_s {
        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 --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
new file mode 100644 (file)
index 0000000..2b0aa1e
--- /dev/null
@@ -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
index 50449b4dbaa0a1a584397266dc1214aa96d7a4a2..4c002a7cb09e2a75fe82b57076698885f260034a 100644 (file)
@@ -316,9 +316,6 @@ struct net_device
        /* 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);
@@ -359,6 +356,9 @@ struct net_device
        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. */
@@ -526,6 +526,7 @@ extern __inline__ void dev_kfree_skb_any(struct sk_buff *skb)
                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 *);
index 8fae97e9b050af9fcd4bdc618fd33657128dfa95..41a3c31904fdcc423f2f168c134145fc3dcdd6c0 100644 (file)
 #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
index f2170ed5f56b1709f7593099c3502e0e85dc95fc..015855fa0e52ef7352b2b0acccaabea484fe7ebd 100644 (file)
@@ -96,7 +96,6 @@ struct sk_buff {
        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 --git a/include/net/br.h b/include/net/br.h
deleted file mode 100644 (file)
index bfa25b6..0000000
+++ /dev/null
@@ -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
-
-
index 6ff0219ccd5fbcfa2628ed447bfee8997b942758..3e88ee85f0a44a5c44430c3b553670f3567d5e2b 100644 (file)
@@ -6,7 +6,6 @@ o       insw_and_csum
 
 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
index 82f4fe6d9d89b85c1d250f3cbad2cbba60bcea52..45f1b1168977bf54a607bd61eee5f30b704f44b4 100644 (file)
@@ -61,11 +61,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    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
index ccaed5154d4e39d4edceda9508933f5fad5b3319..bf234eae145a0f4759938c3a05880c7ef1148774 100644 (file)
@@ -67,6 +67,10 @@ endif
 
 ifeq ($(CONFIG_BRIDGE),y)
 SUB_DIRS += bridge
+else
+  ifeq ($(CONFIG_BRIDGE),m)
+    MOD_SUB_DIRS += bridge
+  endif
 endif
 
 ifeq ($(CONFIG_IPX),y)
index d54d8526b8bcede607b3bf1733c6931f842a4b1a..7490dff2bd54e154163a802ad4aa8bda81d2c18c 100644 (file)
@@ -7,6 +7,7 @@ Code Section            Bug Report Contact
     [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
index bcccefb75ac9f38e3e32ccbbbb94f17899f42a8d..082388fe5a014a4608e898f7ca352a06c9dd5428 100644 (file)
@@ -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 .
index 682012e91d2c68079267d13898e79d9538493927..ec59ff6220e40403d473c70f99751b76a78a8f2f 100644 (file)
 /*
- *     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>
-#include <net/pkt_sched.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)) */
-       }
-}
-
-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) */
-}
-
-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)
-{
-       port_info[port_no].state = state;
-}
-
-static void received_config_bpdu(int port_no, Config_bpdu *config)               /* (4.7.1)     */
-{
-       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)     */
-               }
-       }
-}
-
-static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)                        /* (4.7.2)     */
-{
-       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)  */
-       }
-}
-
-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();
-
-#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 (netif_running(dev)) {
-                         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 */
-       }
-}
+#include "br_private.h"
 
-/*
- * 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 */
+void br_dec_use_count()
 {
-       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));
+       MOD_DEC_USE_COUNT;
 }
 
-static void br_add_local_mac(unsigned char *mac)
+void br_inc_use_count()
 {
-       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);
-       }
+       MOD_INC_USE_COUNT;
 }
 
-/* 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)
+static int __init br_init(void)
 {
-       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;
-}
+       printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
 
-/*
- * 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;
+       br_handle_frame_hook = br_handle_frame;
+       br_ioctl_hook = br_ioctl_deviceless_stub;
+       register_netdevice_notifier(&br_device_notifier);
 
-       /* 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 */
+static void __br_clear_frame_hook(void)
 {
-       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 */
+       br_handle_frame_hook = NULL;
 }
 
-/*
- * this routine always consumes the skb 
- */
-
-static void br_bpdu(struct sk_buff *skb, int port) /* consumes skb */
+static void __br_clear_ioctl_hook(void)
 {
-       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);
+       br_ioctl_hook = NULL;
 }
 
-struct fdb_info *get_fdb_info(int user_buf_size, int *copied,int *notcopied)
+static void __exit br_deinit(void)
 {
-       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)
-{
-       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);
-}
-
-
-
-
-/* --------------------------------------------------------------------------------
- *
- *
- *  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
-{
-       __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;
-}
-
-/*
- *     Open/initialize the board.
- */
-
-static int brg_open(struct net_device *dev)
-{
-        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;
-
-       netif_start_queue(dev);
-       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);
-
-       netif_stop_queue(dev);
-
-       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 --git a/net/bridge/br_device.c b/net/bridge/br_device.c
new file mode 100644 (file)
index 0000000..de14e83
--- /dev/null
@@ -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 --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
new file mode 100644 (file)
index 0000000..6a89409
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
new file mode 100644 (file)
index 0000000..9b68ce5
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_if.c b/net/bridge/br_if.c
new file mode 100644 (file)
index 0000000..16f34f9
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_input.c b/net/bridge/br_input.c
new file mode 100644 (file)
index 0000000..b1d1cbf
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
new file mode 100644 (file)
index 0000000..334743a
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
new file mode 100644 (file)
index 0000000..d8820cb
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_private.h b/net/bridge/br_private.h
new file mode 100644 (file)
index 0000000..084e81b
--- /dev/null
@@ -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 --git a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h
new file mode 100644 (file)
index 0000000..91faaff
--- /dev/null
@@ -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 --git a/net/bridge/br_private_timer.h b/net/bridge/br_private_timer.h
new file mode 100644 (file)
index 0000000..6655ab9
--- /dev/null
@@ -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 --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
new file mode 100644 (file)
index 0000000..413c77d
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
new file mode 100644 (file)
index 0000000..8729e05
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
new file mode 100644 (file)
index 0000000..7ea37e2
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
new file mode 100644 (file)
index 0000000..594b6b7
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *     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/config.h>
+#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 --git a/net/bridge/br_tree.c b/net/bridge/br_tree.c
deleted file mode 100644 (file)
index 67efa8f..0000000
+++ /dev/null
@@ -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 --git a/net/bridge/sysctl_net_bridge.c b/net/bridge/sysctl_net_bridge.c
deleted file mode 100644 (file)
index 6e2f57d..0000000
+++ /dev/null
@@ -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}
-};
index 362ee6ddf095e4ff38c100531d47747d577b131c..34a818721cea8d65fea179ca48cbe9e2a39ae761 100644 (file)
@@ -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>
@@ -833,37 +833,6 @@ drop:
        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.
  */
@@ -953,6 +922,32 @@ static void net_tx_action(struct softirq_action *h)
        }
 }
 
+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 @@ static void net_rx_action(struct softirq_action *h)
                {
                        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 @@ static void net_rx_action(struct softirq_action *h)
                                        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 @@ static void net_rx_action(struct softirq_action *h)
                                        pt_prev = ptype;
                                }
                        }
+
                        if (pt_prev) {
                                if (!pt_prev->data)
                                        deliver_to_old_ones(pt_prev, skb, 1);
@@ -2071,15 +2070,6 @@ int __init net_dev_init(void)
                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);
@@ -2147,13 +2137,6 @@ int __init net_dev_init(void)
        dst_init();
        dev_mcast_init();
 
-#ifdef CONFIG_BRIDGE
-       /*
-        * Register any statically linked ethernet devices with the bridge
-        */
-       br_spacedevice_register();
-#endif
-
        /*
         *      Initialise network devices
         */
index a0307bbd62a6b1cdf4a3fa3c5450aa5942ff06e2..30aa1f6bbc67036bec4a30ccb5cd07ba11935956 100644 (file)
@@ -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 @@ static inline void skb_headerinit(void *p, kmem_cache_t *cache,
 
        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;
index 969fee200482d4dba9adbd76c0ea6839cf1936c9..b7512a1c9bb05a7a6d82eae7a778a4eb86591365 100644 (file)
@@ -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>
 #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 @@ extern int dlci_ioctl(unsigned int, void*);
 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 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        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:
index 1a1e7513eebd36b9e8ec965378bfa6858546fcc8..fbb07ab5a36e94d0f13c2ffee24a1ebb419c3daa 100644 (file)
 #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(sklist_insert_socket);
 
 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(nf_hooks);
 
 EXPORT_SYMBOL(register_gifconf);
 
+EXPORT_SYMBOL(net_call_rx_atomic);
 EXPORT_SYMBOL(softirq_state);
 EXPORT_SYMBOL(softnet_data);
 
index 6410e99d79a338ac0d48da758d56bc4b71dcf5da..46439faa365e37d954b7640daff0e59f78f4cd65 100644 (file)
@@ -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>
 #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 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, unsigned long 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                                         
                        
 #ifdef CONFIG_INET
                case SIOCADDRT:
index 36238c123d8e5212dccdb1153c50ccd72887d5b0..8ee8ab54fd717402c5e704eb42df44da1088c70d 100644 (file)
@@ -476,7 +476,7 @@ void dev_deactivate(struct net_device *dev)
 
        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();
        }
index 5f5e8593e80fbe701e46ae811805344fd5d8a0fa..e539693fef14a8315a3a4d2fd84bab00b2317bef 100644 (file)
@@ -34,10 +34,6 @@ extern ctl_table unix_table[];
 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
@@ -61,9 +57,6 @@ ctl_table net_table[] = {
 #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},
 #endif