From 4f6fa0ce546600dd1fbf533834b4ae9cef48cb67 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:31:51 -0500 Subject: [PATCH] Import 2.3.47pre5 --- CREDITS | 7 + Documentation/Configure.help | 476 ++--- Documentation/DMA-mapping.txt | 284 ++- Documentation/networking/bridge.txt | 11 + Documentation/networking/skfp.txt | 214 +++ MAINTAINERS | 7 + Makefile | 1 + arch/alpha/kernel/pci_iommu.c | 16 +- arch/alpha/kernel/sys_cabriolet.c | 145 +- arch/alpha/kernel/sys_sx164.c | 6 +- arch/sparc/defconfig | 3 +- arch/sparc/kernel/ioport.c | 40 +- arch/sparc64/defconfig | 4 +- arch/sparc64/kernel/pci_iommu.c | 100 +- arch/sparc64/kernel/pci_psycho.c | 3 +- arch/sparc64/kernel/pci_sabre.c | 17 +- arch/sparc64/kernel/sbus.c | 45 +- drivers/block/ide-dma.c | 11 +- drivers/fc4/fc.c | 68 +- drivers/net/3c59x.c | 24 +- drivers/net/8139too.c | 9 +- drivers/net/Config.in | 1 + drivers/net/Makefile | 12 +- drivers/net/Space.c | 4 + drivers/net/acenic.c | 45 +- drivers/net/de4x5.c | 5 +- drivers/net/eepro100.c | 21 +- drivers/net/myri_sbus.c | 18 +- drivers/net/rtl8129.c | 11 +- drivers/net/sk98lin/skge.c | 25 +- drivers/net/skfp/Makefile | 39 + drivers/net/skfp/can.c | 83 + drivers/net/skfp/cfm.c | 642 +++++++ drivers/net/skfp/drvfbi.c | 1612 ++++++++++++++++ drivers/net/skfp/ecm.c | 547 ++++++ drivers/net/skfp/ess.c | 732 +++++++ drivers/net/skfp/fplustm.c | 1645 ++++++++++++++++ drivers/net/skfp/h/cmtdef.h | 801 ++++++++ drivers/net/skfp/h/fddi.h | 69 + drivers/net/skfp/h/fddimib.h | 349 ++++ drivers/net/skfp/h/fplustm.h | 274 +++ drivers/net/skfp/h/hwmtm.h | 424 +++++ drivers/net/skfp/h/lnkstat.h | 84 + drivers/net/skfp/h/mbuf.h | 54 + drivers/net/skfp/h/osdef1st.h | 118 ++ drivers/net/skfp/h/sba.h | 142 ++ drivers/net/skfp/h/sba_def.h | 76 + drivers/net/skfp/h/skfbi.h | 1920 +++++++++++++++++++ drivers/net/skfp/h/skfbiinc.h | 123 ++ drivers/net/skfp/h/smc.h | 471 +++++ drivers/net/skfp/h/smt.h | 882 +++++++++ drivers/net/skfp/h/smt_p.h | 326 ++++ drivers/net/skfp/h/smtstate.h | 100 + drivers/net/skfp/h/supern_2.h | 1059 +++++++++++ drivers/net/skfp/h/targethw.h | 173 ++ drivers/net/skfp/h/targetos.h | 163 ++ drivers/net/skfp/h/types.h | 48 + drivers/net/skfp/hwmtm.c | 2261 ++++++++++++++++++++++ drivers/net/skfp/hwt.c | 314 +++ drivers/net/skfp/lnkstat.c | 209 ++ drivers/net/skfp/pcmplc.c | 2094 ++++++++++++++++++++ drivers/net/skfp/pmf.c | 1701 +++++++++++++++++ drivers/net/skfp/queue.c | 185 ++ drivers/net/skfp/rmt.c | 674 +++++++ drivers/net/skfp/skfddi.c | 2495 ++++++++++++++++++++++++ drivers/net/skfp/smt.c | 2225 ++++++++++++++++++++++ drivers/net/skfp/smtdef.c | 371 ++++ drivers/net/skfp/smtinit.c | 126 ++ drivers/net/skfp/smtparse.c | 475 +++++ drivers/net/skfp/smttimer.c | 173 ++ drivers/net/skfp/srf.c | 441 +++++ drivers/net/starfire.c | 22 +- drivers/net/sunbmac.c | 18 +- drivers/net/sunhme.c | 68 +- drivers/net/sunhme.h | 8 +- drivers/parport/parport_pc.c | 5 +- drivers/sbus/audio/cs4231.c | 66 +- drivers/sbus/audio/dbri.c | 31 +- drivers/scsi/aic7xxx.c | 14 +- drivers/scsi/eata_dma_proc.c | 2 + drivers/scsi/esp.c | 14 +- drivers/scsi/pci2000.c | 81 +- drivers/scsi/pci2000.h | 28 +- drivers/scsi/pci2220i.c | 1656 ++++++++++++---- drivers/scsi/pci2220i.h | 286 +-- drivers/scsi/psi_dale.h | 498 ++++- drivers/scsi/qlogicisp.c | 12 +- drivers/scsi/qlogicpti.c | 11 +- drivers/scsi/scsi.c | 2 + drivers/scsi/scsi.h | 36 + drivers/scsi/scsi_obsolete.c | 2 +- drivers/scsi/scsi_scan.c | 2 +- drivers/scsi/sd.c | 4 +- fs/Config.in | 26 +- include/asm-alpha/pci.h | 22 +- include/asm-arm/pci.h | 22 +- include/asm-i386/pci.h | 34 +- include/asm-ia64/pci.h | 34 +- include/asm-ppc/pci.h | 34 +- include/asm-sparc/pci.h | 22 +- include/asm-sparc/sbus.h | 23 +- include/asm-sparc64/floppy.h | 17 +- include/asm-sparc64/pbm.h | 14 +- include/asm-sparc64/pci.h | 19 +- include/asm-sparc64/sbus.h | 19 +- include/linux/ide.h | 1 + include/linux/if_bridge.h | 109 ++ include/linux/netdevice.h | 7 +- include/linux/pci.h | 6 + include/linux/skbuff.h | 1 - include/net/br.h | 330 ---- net/Changes | 1 - net/Config.in | 7 +- net/Makefile | 4 + net/README | 1 + net/bridge/Makefile | 17 +- net/bridge/br.c | 2728 +-------------------------- net/bridge/br_device.c | 141 ++ net/bridge/br_fdb.c | 319 ++++ net/bridge/br_forward.c | 96 + net/bridge/br_if.c | 294 +++ net/bridge/br_input.c | 114 ++ net/bridge/br_ioctl.c | 265 +++ net/bridge/br_notify.c | 76 + net/bridge/br_private.h | 199 ++ net/bridge/br_private_stp.h | 53 + net/bridge/br_private_timer.h | 54 + net/bridge/br_stp.c | 466 +++++ net/bridge/br_stp_bpdu.c | 192 ++ net/bridge/br_stp_if.c | 226 +++ net/bridge/br_stp_timer.c | 185 ++ net/bridge/br_tree.c | 501 ----- net/bridge/sysctl_net_bridge.c | 13 - net/core/dev.c | 85 +- net/core/skbuff.c | 3 +- net/ipv4/af_inet.c | 22 +- net/netsyms.c | 13 +- net/packet/af_packet.c | 22 +- net/sched/sch_generic.c | 2 +- net/sysctl_net.c | 7 - 140 files changed, 33069 insertions(+), 4976 deletions(-) create mode 100644 Documentation/networking/bridge.txt create mode 100644 Documentation/networking/skfp.txt create mode 100644 drivers/net/skfp/Makefile create mode 100644 drivers/net/skfp/can.c create mode 100644 drivers/net/skfp/cfm.c create mode 100644 drivers/net/skfp/drvfbi.c create mode 100644 drivers/net/skfp/ecm.c create mode 100644 drivers/net/skfp/ess.c create mode 100644 drivers/net/skfp/fplustm.c create mode 100644 drivers/net/skfp/h/cmtdef.h create mode 100644 drivers/net/skfp/h/fddi.h create mode 100644 drivers/net/skfp/h/fddimib.h create mode 100644 drivers/net/skfp/h/fplustm.h create mode 100644 drivers/net/skfp/h/hwmtm.h create mode 100644 drivers/net/skfp/h/lnkstat.h create mode 100644 drivers/net/skfp/h/mbuf.h create mode 100644 drivers/net/skfp/h/osdef1st.h create mode 100644 drivers/net/skfp/h/sba.h create mode 100644 drivers/net/skfp/h/sba_def.h create mode 100644 drivers/net/skfp/h/skfbi.h create mode 100644 drivers/net/skfp/h/skfbiinc.h create mode 100644 drivers/net/skfp/h/smc.h create mode 100644 drivers/net/skfp/h/smt.h create mode 100644 drivers/net/skfp/h/smt_p.h create mode 100644 drivers/net/skfp/h/smtstate.h create mode 100644 drivers/net/skfp/h/supern_2.h create mode 100644 drivers/net/skfp/h/targethw.h create mode 100644 drivers/net/skfp/h/targetos.h create mode 100644 drivers/net/skfp/h/types.h create mode 100644 drivers/net/skfp/hwmtm.c create mode 100644 drivers/net/skfp/hwt.c create mode 100644 drivers/net/skfp/lnkstat.c create mode 100644 drivers/net/skfp/pcmplc.c create mode 100644 drivers/net/skfp/pmf.c create mode 100644 drivers/net/skfp/queue.c create mode 100644 drivers/net/skfp/rmt.c create mode 100644 drivers/net/skfp/skfddi.c create mode 100644 drivers/net/skfp/smt.c create mode 100644 drivers/net/skfp/smtdef.c create mode 100644 drivers/net/skfp/smtinit.c create mode 100644 drivers/net/skfp/smtparse.c create mode 100644 drivers/net/skfp/smttimer.c create mode 100644 drivers/net/skfp/srf.c create mode 100644 include/linux/if_bridge.h delete mode 100644 include/net/br.h create mode 100644 net/bridge/br_device.c create mode 100644 net/bridge/br_fdb.c create mode 100644 net/bridge/br_forward.c create mode 100644 net/bridge/br_if.c create mode 100644 net/bridge/br_input.c create mode 100644 net/bridge/br_ioctl.c create mode 100644 net/bridge/br_notify.c create mode 100644 net/bridge/br_private.h create mode 100644 net/bridge/br_private_stp.h create mode 100644 net/bridge/br_private_timer.h create mode 100644 net/bridge/br_stp.c create mode 100644 net/bridge/br_stp_bpdu.c create mode 100644 net/bridge/br_stp_if.c create mode 100644 net/bridge/br_stp_timer.c delete mode 100644 net/bridge/br_tree.c delete mode 100644 net/bridge/sysctl_net_bridge.c diff --git a/CREDITS b/CREDITS index f7247ea8810d..f97a63889a02 100644 --- 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 diff --git a/Documentation/Configure.help b/Documentation/Configure.help index fe94f09920c2..4931d2680fc6 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -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 diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt index f3fc1dca30ae..14237b851ef7 100644 --- a/Documentation/DMA-mapping.txt +++ b/Documentation/DMA-mapping.txt @@ -28,19 +28,126 @@ First of all, you should make sure #include -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 + Leo Dagum + Ralf Baechle + Grant Grundler + Jay Estabrook + Thomas Sailer diff --git a/Documentation/networking/bridge.txt b/Documentation/networking/bridge.txt new file mode 100644 index 000000000000..043a14b1650b --- /dev/null +++ b/Documentation/networking/bridge.txt @@ -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 + diff --git a/Documentation/networking/skfp.txt b/Documentation/networking/skfp.txt new file mode 100644 index 000000000000..edf275b61396 --- /dev/null +++ b/Documentation/networking/skfp.txt @@ -0,0 +1,214 @@ +(C)Copyright 1998-2000 SysKonnect, +=========================================================================== + +skfp.txt created 17-Feb-2000 + +Readme File for skfp.o v2.05 + + +This file contains +(1) OVERVIEW +(2) SUPPORTED ADAPTERS +(3) GENERAL INFORMATION +(4) INSTALLATION +(5) INCLUSION OF THE ADAPTER IN SYSTEM START +(6) TROUBLESHOOTING +(7) FUNCTION OF THE ADAPTER LEDS +(8) HISTORY + +=========================================================================== + + + +(1) OVERVIEW +============ + +This README explains how to use the driver 'skfp' for Linux with your +network adapter. + +Chapter 2: Contains a list of all network adapters that are supported by + this driver. + +Chapter 3: Gives some general information. + +Chapter 4: Describes common problems and solutions. + +Chapter 5: Shows the changed functionality of the adapter LEDs. + +Chapter 6: History of development. + +*** + + +(2) SUPPORTED ADAPTERS +====================== + +The network driver 'skfp' supports the following network adapters: +SysKonnect adapters: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) +Compaq adapters (not tested): + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC +*** + + +(3) GENERAL INFORMATION +======================= + +From v2.01 on, the driver is integrated in the linux kernel sources. +Therefor, the installation is the same as for any other adapter +supported by the kernel. +Refer to the manual of your distribution about the installation +of network adapters. +Makes my life much easier :-) +*** + + +(4) TROUBLESHOOTING +=================== + +If you run into problems during installation, check those items: + +Problem: The FDDI adapter can not be found by the driver. +Reason: Look in /proc/pci for the following entry: + 'FDDI network controller: SysKonnect SK-FDDI-PCI ...' + If this entry exists, then the FDDI adapter has been + found by the system and should be able to be used. + If this entry does not exist or if the file '/proc/pci' + is not there, then you may have a hardware problem or PCI + support may not be enabled in your kernel. + The adapter can be checked using the diagnostic program + which is available from the SysKonnect web site: + www.syskonnect.de + Some COMPAQ machines have a problem with PCI under + Linux. This is described in the 'PCI howto' document + (included in some distributions or available from the + www, e.g. at 'www.linux.org') and no workaround is available. + +Problem: You want to use your computer as a router between + multiple IP subnetworks (using multiple adapters), but + you can not reach computers in other subnetworks. +Reason: Either the router's kernel is not configured for IP + forwarding or there is a problem with the routing table + and gateway configuration in at least one of the + computers. + +If your problem is not listed here, please contact our +technical support for help. +You can send email to: + linux@syskonnect.de +When contacting our technical support, +please ensure that the following information is available: +- System Manufacturer and Model +- Boards in your system +- Distribution +- Kernel version + +*** + + +(5) FUNCTION OF THE ADAPTER LEDS +================================ + + The functionality of the LED's on the FDDI network adapters was + changed in SMT version v2.82. With this new SMT version, the yellow + LED works as a ring operational indicator. An active yellow LED + indicates that the ring is down. The green LED on the adapter now + works as a link indicator where an active GREEN LED indicates that + the respective port has a physical connection. + + With versions of SMT prior to v2.82 a ring up was indicated if the + yellow LED was off while the green LED(s) showed the connection + status of the adapter. During a ring down the green LED was off and + the yellow LED was on. + + All implementations indicate that a driver is not loaded if + all LEDs are off. + +*** + + +(6) HISTORY +=========== + +v2.05 (20000217) (In-Kernel version) + New features: + - Changes for 2.3.45 kernel + +v2.04 (20000207) (Standalone version) + New features: + - Added rx/tx byte counter + +v2.03 (20000111) (Standalone version) + Problems fixed: + - Fixed printk statements from v2.02 + +v2.02 (991215) (Standalone version) + Problems fixed: + - Removed unnecessary output + - Fixed path for "printver.sh" in makefile + +v2.01 (991122) (In-Kernel version) + New features: + - Integration in Linux kernel sources + - Support for memory mapped I/O. + +v2.00 (991112) + New features: + - Full source released under GPL + +v1.05 (991023) + Problems fixed: + - Compilation with kernel version 2.2.13 failed + +v1.04 (990427) + Changes: + - New SMT module included, changing LED functionality + Problems fixed: + - Synchronization on SMP machines was buggy + +v1.03 (990325) + Problems fixed: + - Interrupt routing on SMP machines could be incorrect + +v1.02 (990310) + New features: + - Support for kernel versions 2.2.x added + - Kernel patch instead of private duplicate of kernel functions + +v1.01 (980812) + Problems fixed: + Connection hangup with telnet + Slow telnet connection + +v1.00 beta 01 (980507) + New features: + None. + Problems fixed: + None. + Known limitations: + - tar archive instead of standard package format (rpm). + - FDDI statistic is empty. + - not tested with 2.1.xx kernels + - integration in kernel not tested + - not tested simultaneously with FDDI adapters from other vendors. + - only X86 processors supported. + - SBA (Synchronous Bandwidth Allocator) parameters can + not be configured. + - does not work on some COMPAQ machines. See the PCI howto + document for details about this problem. + - data corruption with kernel versions below 2.0.33. + +*** End of information file *** diff --git a/MAINTAINERS b/MAINTAINERS index e87edfafd7e0..7c0c5603262b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/Makefile b/Makefile index 148a413c8d52..8cbc0c478231 100644 --- 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; \ diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index b37a045cf220..72ce8bcb6926 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -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; diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index bc4d2c2ba7db..d575e20226fe 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -31,42 +33,99 @@ #include #include "proto.h" -#include #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, diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c index 39421c9850ff..fa5449657217 100644 --- a/arch/alpha/kernel/sys_sx164.c +++ b/arch/alpha/kernel/sys_sx164.c @@ -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 */ } /* diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 66beb4ee3513..7589958c81dd 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -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 diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index b0e330a10bb7..8c8903d26c71 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -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, diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 747ded255906..917bb5e745ca 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -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 diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 360b2d7b65d7..00f635ab300a 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -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; +} diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 5cf9d007d0c4..b3248de3945c 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -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 diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 2833ff94116e..e96af490d152 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -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]); diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index bdaa3a17c86f..1b454fa2cb76 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -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; diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 1e450b7e66d4..3b6f5e56a34e 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -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); } /* diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c index 4b96ae1d3637..4123a73649ab 100644 --- a/drivers/fc4/fc.c +++ b/drivers/fc4/fc.c @@ -56,17 +56,21 @@ #ifdef __sparc__ #define dma_alloc_consistent(d,s,p) sbus_alloc_consistent(d,s,p) #define dma_free_consistent(d,s,v,h) sbus_free_consistent(d,s,v,h) -#define dma_map_single(d,v,s) sbus_map_single(d,v,s) -#define dma_unmap_single(d,h,s) sbus_unmap_single(d,h,s) -#define dma_map_sg(d,s,n) sbus_map_sg(d,s,n) -#define dma_unmap_sg(d,s,n) sbus_unmap_sg(d,s,n) +#define dma_map_single(d,v,s,dir) sbus_map_single(d,v,s,dir) +#define dma_unmap_single(d,h,s,dir) sbus_unmap_single(d,h,s,dir) +#define dma_map_sg(d,s,n,dir) sbus_map_sg(d,s,n,dir) +#define dma_unmap_sg(d,s,n,dir) sbus_unmap_sg(d,s,n,dir) +#define scsi_to_fc_dma_dir(dir) scsi_to_sbus_dma_dir(dir) +#define FC_DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL #else #define dma_alloc_consistent(d,s,p) pci_alloc_consistent(d,s,p) #define dma_free_consistent(d,s,v,h) pci_free_consistent(d,s,v,h) -#define dma_map_single(d,v,s) pci_map_single(d,v,s) -#define dma_unmap_single(d,h,s) pci_unmap_single(d,h,s) -#define dma_map_sg(d,s,n) pci_map_sg(d,s,n) -#define dma_unmap_sg(d,s,n) pci_unmap_sg(d,s,n) +#define dma_map_single(d,v,s,dir) pci_map_single(d,v,s,dir) +#define dma_unmap_single(d,h,s,dir) pci_unmap_single(d,h,s,dir) +#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir) +#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir) +#define scsi_to_fc_dma_dir(dir) scsi_to_pci_dma_dir(dir) +#define FC_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL #endif #define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp)) @@ -163,7 +167,8 @@ 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; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 8d33f08f36b0..839c15ebcce2 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -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; } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 6b86426fcaf0..7439f809b411 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -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; diff --git a/drivers/net/Config.in b/drivers/net/Config.in index bf3350a85e7f..2874bad9fde0 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -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 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 55e6d0e46a41..0daf888875b0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -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 diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 9e2ba1a91eb5..e3a53d7711c8 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -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. */ diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index c57d22f0fe3b..3587dfe16a67 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -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, ®s->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); diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index 15a5f22725e0..81e0dbdaea46 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -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); diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index c0ee881d1d94..98e0de005cb8 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -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. */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 3c4e230166c1..bd1406e1f65a 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -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); diff --git a/drivers/net/rtl8129.c b/drivers/net/rtl8129.c index 50e7eb382bfa..b60a626086c4 100644 --- a/drivers/net/rtl8129.c +++ b/drivers/net/rtl8129.c @@ -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; diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 27d0dba242a2..f6710a0b5ffe 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -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 index 000000000000..82aa26e4cdf5 --- /dev/null +++ b/drivers/net/skfp/Makefile @@ -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 index 000000000000..8a49abce7961 --- /dev/null +++ b/drivers/net/skfp/can.c @@ -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 index 000000000000..7a51b765b4a5 --- /dev/null +++ b/drivers/net/skfp/cfm.c @@ -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 index 000000000000..e1e48bc91cc6 --- /dev/null +++ b/drivers/net/skfp/drvfbi.c @@ -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; (ihw.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 index 000000000000..41116928613e --- /dev/null +++ b/drivers/net/skfp/ecm.c @@ -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 index 000000000000..868237b30879 --- /dev/null +++ b/drivers/net/skfp/ess.c @@ -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 index 000000000000..83a9357917c7 --- /dev/null +++ b/drivers/net/skfp/fplustm.c @@ -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 index 000000000000..0b54c57ca13c --- /dev/null +++ b/drivers/net/skfp/h/cmtdef.h @@ -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 index 000000000000..c9a28a8a383b --- /dev/null +++ b/drivers/net/skfp/h/fddi.h @@ -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 index 000000000000..d1acdc773950 --- /dev/null +++ b/drivers/net/skfp/h/fddimib.h @@ -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 index 000000000000..9e1ce036e449 --- /dev/null +++ b/drivers/net/skfp/h/fplustm.h @@ -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 index 000000000000..4e360af07d77 --- /dev/null +++ b/drivers/net/skfp/h/hwmtm.h @@ -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 index 000000000000..c73dcd96a40f --- /dev/null +++ b/drivers/net/skfp/h/lnkstat.h @@ -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 index 000000000000..b339d1f2e0e5 --- /dev/null +++ b/drivers/net/skfp/h/mbuf.h @@ -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 index 000000000000..69f27707d308 --- /dev/null +++ b/drivers/net/skfp/h/osdef1st.h @@ -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 index 000000000000..df716cd5784a --- /dev/null +++ b/drivers/net/skfp/h/sba.h @@ -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 index 000000000000..0459a095d0cd --- /dev/null +++ b/drivers/net/skfp/h/sba_def.h @@ -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 index 000000000000..f127bddb8be6 --- /dev/null +++ b/drivers/net/skfp/h/skfbi.h @@ -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__CRTL 8 bit 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__TEST 8 Bit 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__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__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__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__T1_TR 8 bit Test Register 1 TR (xx) */ +/* B4__T1_WR 8 bit Test Register 1 WR (xx) */ +/* B4__T1_RD 8 bit Test Register 1 RD (xx) */ +/* B4__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__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__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 index 000000000000..79d55ad2cd2a --- /dev/null +++ b/drivers/net/skfp/h/skfbiinc.h @@ -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 index 000000000000..b909586bca21 --- /dev/null +++ b/drivers/net/skfp/h/smc.h @@ -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 index 000000000000..08eb1ccbf22f --- /dev/null +++ b/drivers/net/skfp/h/smt.h @@ -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 index 000000000000..99f9be9552bb --- /dev/null +++ b/drivers/net/skfp/h/smt_p.h @@ -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 index 000000000000..689fa25dc044 --- /dev/null +++ b/drivers/net/skfp/h/smtstate.h @@ -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 index 000000000000..ea564b337c90 --- /dev/null +++ b/drivers/net/skfp/h/supern_2.h @@ -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 index 000000000000..5e6f3a050cea --- /dev/null +++ b/drivers/net/skfp/h/targethw.h @@ -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 index 000000000000..dd88fb35ef64 --- /dev/null +++ b/drivers/net/skfp/h/targetos.h @@ -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 +#include +#include +#include +#include +#include +#include + +// 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 + +#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 index 000000000000..43b48ff3ba2f --- /dev/null +++ b/drivers/net/skfp/h/types.h @@ -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 +/* + ---------------------- + 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 index 000000000000..366b3b890911 --- /dev/null +++ b/drivers/net/skfp/hwmtm.c @@ -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 index 000000000000..7d51b8b8bb3b --- /dev/null +++ b/drivers/net/skfp/hwt.c @@ -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 index 000000000000..7d2d94eaee0d --- /dev/null +++ b/drivers/net/skfp/lnkstat.c @@ -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 index 000000000000..5479b27ea0fa --- /dev/null +++ b/drivers/net/skfp/pcmplc.c @@ -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 index 000000000000..d53355bac5aa --- /dev/null +++ b/drivers/net/skfp/pmf.c @@ -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 index 000000000000..e54b544ff273 --- /dev/null +++ b/drivers/net/skfp/queue.c @@ -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 index 000000000000..473eb0c9cdfe --- /dev/null +++ b/drivers/net/skfp/rmt.c @@ -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 index 000000000000..6aceec4d5652 --- /dev/null +++ b/drivers/net/skfp/skfddi.c @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // isdigit + +#include +#include +#include + +#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 index 000000000000..ed8538958988 --- /dev/null +++ b/drivers/net/skfp/smt.c @@ -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 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 index 000000000000..221b0334ce70 --- /dev/null +++ b/drivers/net/skfp/smtdef.c @@ -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 index 000000000000..c4b5af9b502b --- /dev/null +++ b/drivers/net/skfp/smtinit.c @@ -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 index 000000000000..0b4a2274d055 --- /dev/null +++ b/drivers/net/skfp/smtparse.c @@ -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 index 000000000000..9d7b71e265c3 --- /dev/null +++ b/drivers/net/skfp/smttimer.c @@ -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 index 000000000000..79bbfedc6c3a --- /dev/null +++ b/drivers/net/skfp/srf.c @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT 7.2 Status Response Frame Implementation + SRF state machine and frame generation +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef SLIM_SMT +#ifndef BOOT + +#ifndef lint +static const char ID_sccs[] = "@(#)srf.c 1.18 97/08/04 (C) SK " ; +#endif + + +/* + * function declarations + */ +static void clear_all_rep() ; +static void clear_reported() ; +static void smt_send_srf() ; +static struct s_srf_evc *smt_get_evc() ; + +#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0])) + +struct evc_init { + u_char code ; + u_char index ; + u_char n ; + u_short para ; +} ; + +static const struct evc_init evc_inits[] = { + { SMT_COND_SMT_PEER_WRAP, 0,1,SMT_P1048 } , + + { SMT_COND_MAC_DUP_ADDR, INDEX_MAC, NUMMACS,SMT_P208C } , + { SMT_COND_MAC_FRAME_ERROR, INDEX_MAC, NUMMACS,SMT_P208D } , + { SMT_COND_MAC_NOT_COPIED, INDEX_MAC, NUMMACS,SMT_P208E } , + { SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC, NUMMACS,SMT_P208F } , + { SMT_EVENT_MAC_PATH_CHANGE, INDEX_MAC, NUMMACS,SMT_P2090 } , + + { SMT_COND_PORT_LER, INDEX_PORT,NUMPHYS,SMT_P4050 } , + { SMT_COND_PORT_EB_ERROR, INDEX_PORT,NUMPHYS,SMT_P4052 } , + { SMT_EVENT_PORT_CONNECTION, INDEX_PORT,NUMPHYS,SMT_P4051 } , + { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } , +} ; + +#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0])) + +void smt_init_evc(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + const struct evc_init *init ; + int i ; + int index ; + int offset ; + + static u_char fail_safe = FALSE ; + + memset((char *)smc->evcs,0,sizeof(smc->evcs)) ; + + evc = smc->evcs ; + init = evc_inits ; + + for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) { + for (index = 0 ; index < init->n ; index++) { + evc->evc_code = init->code ; + evc->evc_para = init->para ; + evc->evc_index = init->index + index ; +#ifndef DEBUG + evc->evc_multiple = &fail_safe ; + evc->evc_cond_state = &fail_safe ; +#endif + evc++ ; + } + init++ ; + } + + if ((unsigned) (evc - smc->evcs) > MAX_EVCS) { + SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ; + } + + /* + * conditions + */ + smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ; + smc->evcs[1].evc_cond_state = + &smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; + smc->evcs[2].evc_cond_state = + &smc->mib.m[MAC0].fddiMACFrameErrorFlag ; + smc->evcs[3].evc_cond_state = + &smc->mib.m[MAC0].fddiMACNotCopiedFlag ; + + /* + * events + */ + smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ; + smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ; + + offset = 6 ; + for (i = 0 ; i < NUMPHYS ; i++) { + /* + * conditions + */ + smc->evcs[offset + 0*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTLerFlag ; + smc->evcs[offset + 1*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTEB_Condition ; + + /* + * events + */ + smc->evcs[offset + 2*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_U ; + smc->evcs[offset + 3*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_P ; + offset++ ; + } +#ifdef DEBUG + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (!evc->evc_cond_state) { + SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ; + } + evc->evc_multiple = &fail_safe ; + } + else { + if (!evc->evc_multiple) { + SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ; + } + evc->evc_cond_state = &fail_safe ; + } + } +#endif + smc->srf.TSR = smt_get_time() ; + smc->srf.sr_state = SR0_WAIT ; +} + +static struct s_srf_evc *smt_get_evc(smc,code,index) +struct s_smc *smc ; +int code ; +int index ; +{ + int i ; + struct s_srf_evc *evc ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_code == code && evc->evc_index == index) + return(evc) ; + } + return(0) ; +} + +#define THRESHOLD_2 (2*TICKS_PER_SECOND) +#define THRESHOLD_32 (32*TICKS_PER_SECOND) + +#ifdef DEBUG +static const char * const srf_names[] = { + "None","MACPathChangeEvent", "MACNeighborChangeEvent", + "PORTPathChangeEvent", "PORTUndesiredConnectionAttemptEvent", + "SMTPeerWrapCondition", "SMTHoldCondition", + "MACFrameErrorCondition", "MACDuplicateAddressCondition", + "MACNotCopiedCondition", "PORTEBErrorCondition", + "PORTLerCondition" +} ; +#endif + +void smt_srf_event(smc,code,index,cond) +struct s_smc *smc ; +int code ; +int index ; +int cond ; +{ + struct s_srf_evc *evc ; + int cond_asserted = 0 ; + int cond_deasserted = 0 ; + int event_occured = 0 ; + int tsr ; + int T_Limit = 2*TICKS_PER_SECOND ; + + if (code == SMT_COND_MAC_DUP_ADDR && cond) { + RS_SET(smc,RS_DUPADDR) ; + } + + if (code) { + DB_SMT("SRF: %s index %d\n",srf_names[code],index) ; + + if (!(evc = smt_get_evc(smc,code,index))) { + DB_SMT("SRF : smt_get_evc() failed\n",0,0) ; + return ; + } + /* + * ignore condition if no change + */ + if (SMT_IS_CONDITION(code)) { + if (*evc->evc_cond_state == cond) + return ; + } + + /* + * set transition time stamp + */ + smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ; + if (SMT_IS_CONDITION(code)) { + DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ; + if (cond) { + *evc->evc_cond_state = TRUE ; + evc->evc_rep_required = TRUE ; + smc->srf.any_report = TRUE ; + cond_asserted = TRUE ; + } + else { + *evc->evc_cond_state = FALSE ; + cond_deasserted = TRUE ; + } + } + else { + if (evc->evc_rep_required) { + *evc->evc_multiple = TRUE ; + } + else { + evc->evc_rep_required = TRUE ; + *evc->evc_multiple = FALSE ; + } + smc->srf.any_report = TRUE ; + event_occured = TRUE ; + } +#ifdef FDDI_MIB + snmp_srf_event(smc,evc) ; +#endif /* FDDI_MIB */ + } + tsr = smt_get_time() - smc->srf.TSR ; + + switch (smc->srf.sr_state) { + case SR0_WAIT : + /* SR01a */ + if (cond_asserted && tsr < T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01b */ + if (cond_deasserted && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01c */ + if (event_occured && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR00b */ + if (cond_asserted && tsr >= T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00c */ + if (cond_deasserted && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00d */ + if (event_occured && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00e */ + if (smc->srf.any_report && (u_long) tsr >= + smc->srf.SRThreshold) { + smc->srf.SRThreshold *= 2 ; + if (smc->srf.SRThreshold > THRESHOLD_32) + smc->srf.SRThreshold = THRESHOLD_32 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR02 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR1_HOLDOFF : + /* SR10b */ + if (tsr >= T_Limit) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR11a */ + if (cond_asserted) { + smc->srf.SRThreshold = THRESHOLD_2 ; + } + /* SR11b */ + /* SR11c */ + /* handled above */ + /* SR12 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR2_DISABLED : + if (smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smc->srf.SRThreshold = THRESHOLD_2 ; + clear_all_rep(smc) ; + break ; + } + break ; + } +} + +static void clear_all_rep(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + int i ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + evc->evc_rep_required = FALSE ; + if (SMT_IS_CONDITION(evc->evc_code)) + *evc->evc_cond_state = FALSE ; + } + smc->srf.any_report = FALSE ; +} + +static void clear_reported(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + int i ; + + smc->srf.any_report = FALSE ; + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (*evc->evc_cond_state == FALSE) + evc->evc_rep_required = FALSE ; + else + smc->srf.any_report = TRUE ; + } + else { + evc->evc_rep_required = FALSE ; + *evc->evc_multiple = FALSE ; + } + } +} + +extern SMbuf *smt_build_frame() ; + +/* + * build and send SMT SRF frame + */ +static void smt_send_srf(smc) +struct s_smc *smc ; +{ + + struct smt_header *smt ; + struct s_srf_evc *evc ; + SK_LOC_DECL(struct s_pcon,pcon) ; + SMbuf *mb ; + int i ; + + static const struct fddi_addr SMT_SRF_DA = { + 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 + } ; + + /* + * build SMT header + */ + if (!smc->r.sm_ma_avail) + return ; + if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0))) + return ; + + RS_SET(smc,RS_SOFTERROR) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = SMT_SRF_DA ; /* DA == SRF multicast */ + + /* + * setup parameter status + */ + pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ + pcon.pc_err = 0 ; /* no error */ + pcon.pc_badset = 0 ; /* no bad set count */ + pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ + + smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_rep_required) { + smt_add_para(smc,&pcon,evc->evc_para, + (int)evc->evc_index,0) ; + } + } + smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; + mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; + + DB_SMT("SRF: sending SRF at %x, len %d \n",smt,mb->sm_len) ; + DB_SMT("SRF: state SR%d Threshold %d\n", + smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ; +#ifdef DEBUG + dump_smt(smc,smt,"SRF Send") ; +#endif + smt_send_frame(smc,mb,FC_SMT_INFO,0) ; + clear_reported(smc) ; +} + +#endif /* no BOOT */ +#endif /* no SLIM_SMT */ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 30e9e5b3dc37..de085602052b 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -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; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index bd30b9c16aaf..6a773b66d3fa 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -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); diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 76baa77024ed..344e682f818e 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -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 diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index 3708515e3fdd..57b5d7f5e2b3 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -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. */ diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 29206729ad94..beb0a68b77fe 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -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; } diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c index 82e0fc4941a8..e155a73b47fd 100644 --- a/drivers/sbus/audio/cs4231.c +++ b/drivers/sbus/audio/cs4231.c @@ -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; } diff --git a/drivers/sbus/audio/dbri.c b/drivers/sbus/audio/dbri.c index a3f083eada9d..45ee9dd1b4f2 100644 --- a/drivers/sbus/audio/dbri.c +++ b/drivers/sbus/audio/dbri.c @@ -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; diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index 9920f33c4aee..e146ec1c4909 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -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; diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c index dd603456178e..725a70a4a9eb 100644 --- a/drivers/scsi/eata_dma_proc.c +++ b/drivers/scsi/eata_dma_proc.c @@ -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. diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 57802859cbc6..fccfb59c8636 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -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)); } } diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index 83efa5df6e35..e07417b7e3be 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -53,7 +53,15 @@ #include "pci2000.h" #include "psi_roy.h" -#include +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) +#include +#endif +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) +#include +#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 - diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h index 9b80a489b07e..a3daa5f76304 100644 --- a/drivers/scsi/pci2000.h +++ b/drivers/scsi/pci2000.h @@ -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 diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index e50ba45dc930..80f58cb8ee2f 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -24,8 +24,15 @@ * Revisions 1.11 Mar-26-1999 * - Fixed spinlock and PCI configuration. * + * Revision 2.00 December-1-1999 + * - Added code for the PCI-2240I controller + * - Added code for ATAPI devices. + * - Double buffer for scatter/gather support + * ****************************************************************************/ +//#define DEBUG 1 + #include #include #include @@ -46,18 +53,22 @@ #include "scsi.h" #include "hosts.h" #include "pci2220i.h" +#include "psi_dale.h" -#include +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) +#include +#endif +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) +#include +#endif -#define PCI2220I_VERSION "1.11" -//#define READ_CMD IDE_COMMAND_READ -//#define WRITE_CMD IDE_COMMAND_WRITE -//#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master +#define PCI2220I_VERSION "2.00" #define READ_CMD IDE_CMD_READ_MULTIPLE #define WRITE_CMD IDE_CMD_WRITE_MULTIPLE #define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master -//#define DEBUG 1 +struct proc_dir_entry Proc_Scsi_Pci2220i = + { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; #ifdef DEBUG #define DEB(x) x @@ -72,10 +83,10 @@ typedef struct { - UCHAR device; // device code UCHAR byte6; // device select register image UCHAR spigot; // spigot number - UCHAR sparebyte; // placeholder + UCHAR spigots[2]; // RAID spigots + UCHAR deviceID[2]; // device ID codes USHORT sectors; // number of sectors per track USHORT heads; // number of heads USHORT cylinders; // number of cylinders for this device @@ -85,12 +96,17 @@ 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; } diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h index 1c75c8c3b2a7..aaa8457fc1ca 100644 --- a/drivers/scsi/pci2220i.h +++ b/drivers/scsi/pci2220i.h @@ -21,265 +21,11 @@ #ifndef _PCI2220I_H #define _PCI2220I_H -#ifndef PSI_EIDE_SCSIOP -#define PSI_EIDE_SCSIOP 1 - #ifndef LINUX_VERSION_CODE #include #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 diff --git a/drivers/scsi/psi_dale.h b/drivers/scsi/psi_dale.h index bb7c8006b319..03da4c3b8066 100644 --- a/drivers/scsi/psi_dale.h +++ b/drivers/scsi/psi_dale.h @@ -19,17 +19,33 @@ * ****************************************************************************/ +/************************************************/ +/* Some defines that we like */ +/************************************************/ +#define CHAR char +#define UCHAR unsigned char +#define SHORT short +#define USHORT unsigned short +#define BOOL unsigned short +#define LONG long +#define ULONG unsigned long +#define VOID void + /************************************************/ /* Dale PCI setup */ /************************************************/ #define VENDOR_PSI 0x1256 #define DEVICE_DALE_1 0x4401 /* 'D1' */ +#define DEVICE_BIGD_1 0x4201 /* 'B1' */ +#define DEVICE_BIGD_2 0x4202 /* 'B2' */ /************************************************/ /* Misc konstants */ /************************************************/ #define DALE_MAXDRIVES 4 +#define BIGD_MAXDRIVES 8 #define SECTORSXFER 8 +#define ATAPI_TRANSFER 8192 #define BYTES_PER_SECTOR 512 #define DEFAULT_TIMING_MODE 5 @@ -49,90 +65,136 @@ /************************************************/ /* DALE Register address offsets */ /************************************************/ -#define REG_DATA 0x80 -#define REG_ERROR 0x84 -#define REG_SECTOR_COUNT 0x88 -#define REG_LBA_0 0x8C -#define REG_LBA_8 0x90 -#define REG_LBA_16 0x94 -#define REG_LBA_24 0x98 -#define REG_STAT_CMD 0x9C -#define REG_STAT_SEL 0xA0 -#define REG_FAIL 0xB0 -#define REG_ALT_STAT 0xB8 -#define REG_DRIVE_ADRS 0xBC - -#define DALE_DATA_SLOW 0x00040000L -#define DALE_DATA_MODE2 0x00040000L -#define DALE_DATA_MODE3 0x00050000L -#define DALE_DATA_MODE4 0x00060000L -#define DALE_DATA_MODE4P 0x00070000L - -#define RTR_LOCAL_RANGE 0x000 -#define RTR_LOCAL_REMAP 0x004 -#define RTR_EXP_RANGE 0x010 -#define RTR_EXP_REMAP 0x014 -#define RTR_REGIONS 0x018 -#define RTR_DM_MASK 0x01C -#define RTR_DM_LOCAL_BASE 0x020 -#define RTR_DM_IO_BASE 0x024 -#define RTR_DM_PCI_REMAP 0x028 -#define RTR_DM_IO_CONFIG 0x02C -#define RTR_MAILBOX 0x040 -#define RTR_LOCAL_DOORBELL 0x060 -#define RTR_PCI_DOORBELL 0x064 -#define RTR_INT_CONTROL_STATUS 0x068 -#define RTR_EEPROM_CONTROL_STATUS 0x06C - -#define RTL_DMA0_MODE 0x00 -#define RTL_DMA0_PCI_ADDR 0x04 -#define RTL_DMA0_LOCAL_ADDR 0x08 -#define RTL_DMA0_COUNT 0x0C -#define RTL_DMA0_DESC_PTR 0x10 -#define RTL_DMA1_MODE 0x14 -#define RTL_DMA1_PCI_ADDR 0x18 -#define RTL_DMA1_LOCAL_ADDR 0x1C -#define RTL_DMA1_COUNT 0x20 -#define RTL_DMA1_DESC_PTR 0x24 -#define RTL_DMA_COMMAND_STATUS 0x28 -#define RTL_DMA_ARB0 0x2C -#define RTL_DMA_ARB1 0x30 +#define REG_DATA 0x80 +#define REG_ERROR 0x84 +#define REG_SECTOR_COUNT 0x88 +#define REG_LBA_0 0x8C +#define REG_LBA_8 0x90 +#define REG_LBA_16 0x94 +#define REG_LBA_24 0x98 +#define REG_STAT_CMD 0x9C +#define REG_STAT_SEL 0xA0 +#define REG_FAIL 0xB0 +#define REG_ALT_STAT 0xB8 +#define REG_DRIVE_ADRS 0xBC + +#define DALE_DATA_SLOW 0x00040000L +#define DALE_DATA_MODE2 0x00040000L +#define DALE_DATA_MODE3 0x00050000L +#define DALE_DATA_MODE4 0x00060000L +#define DALE_DATA_MODE5 0x00070000L + +#define BIGD_DATA_SLOW 0x00000000L +#define BIGD_DATA_MODE0 0x00000000L +#define BIGD_DATA_MODE2 0x00000000L +#define BIGD_DATA_MODE3 0x00000008L +#define BIGD_DATA_MODE4 0x00000010L +#define BIGD_DATA_MODE5 0x00000020L + +#define RTR_LOCAL_RANGE 0x000 +#define RTR_LOCAL_REMAP 0x004 +#define RTR_EXP_RANGE 0x010 +#define RTR_EXP_REMAP 0x014 +#define RTR_REGIONS 0x018 +#define RTR_DM_MASK 0x01C +#define RTR_DM_LOCAL_BASE 0x020 +#define RTR_DM_IO_BASE 0x024 +#define RTR_DM_PCI_REMAP 0x028 +#define RTR_DM_IO_CONFIG 0x02C +#define RTR_MAILBOX 0x040 +#define RTR_LOCAL_DOORBELL 0x060 +#define RTR_PCI_DOORBELL 0x064 +#define RTR_INT_CONTROL_STATUS 0x068 +#define RTR_EEPROM_CONTROL_STATUS 0x06C + +#define RTR_DMA0_MODE 0x0080 +#define RTR_DMA0_PCI_ADDR 0x0084 +#define RTR_DMA0_LOCAL_ADDR 0x0088 +#define RTR_DMA0_COUNT 0x008C +#define RTR_DMA0_DESC_PTR 0x0090 +#define RTR_DMA1_MODE 0x0094 +#define RTR_DMA1_PCI_ADDR 0x0098 +#define RTR_DMA1_LOCAL_ADDR 0x009C +#define RTR_DMA1_COUNT 0x00A0 +#define RTR_DMA1_DESC_PTR 0x00A4 +#define RTR_DMA_COMMAND_STATUS 0x00A8 +#define RTR_DMA_ARB0 0x00AC +#define RTR_DMA_ARB1 0x00B0 + +#define RTL_DMA0_MODE 0x00 +#define RTL_DMA0_PCI_ADDR 0x04 +#define RTL_DMA0_LOCAL_ADDR 0x08 +#define RTL_DMA0_COUNT 0x0C +#define RTL_DMA0_DESC_PTR 0x10 +#define RTL_DMA1_MODE 0x14 +#define RTL_DMA1_PCI_ADDR 0x18 +#define RTL_DMA1_LOCAL_ADDR 0x1C +#define RTL_DMA1_COUNT 0x20 +#define RTL_DMA1_DESC_PTR 0x24 +#define RTL_DMA_COMMAND_STATUS 0x28 +#define RTL_DMA_ARB0 0x2C +#define RTL_DMA_ARB1 0x30 /************************************************/ /* Dale Scratchpad locations */ /************************************************/ -#define DALE_CHANNEL_DEVICE_0 0 // device channel locations -#define DALE_CHANNEL_DEVICE_1 1 -#define DALE_CHANNEL_DEVICE_2 2 -#define DALE_CHANNEL_DEVICE_3 3 +#define DALE_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 */ @@ -148,6 +210,18 @@ #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 () diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c index 31cd06cccf82..3125bd28fdc1 100644 --- a/drivers/scsi/qlogicisp.c +++ b/drivers/scsi/qlogicisp.c @@ -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); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 89265a47f0f7..d61c832c5cf0 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -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); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index e59bd3189055..a6e2c14d9353 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -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, diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 47fbcc171524..7a073f86efb3 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -43,6 +43,42 @@ #define SCSI_DATA_READ 2 #define SCSI_DATA_NONE 3 +#ifdef CONFIG_PCI +#include +#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 +#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. */ diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c index ae01a6dd4f8b..a957a4c017e3 100644 --- a/drivers/scsi/scsi_obsolete.c +++ b/drivers/scsi/scsi_obsolete.c @@ -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 diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 6f22c4022446..40a7cb1240af 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -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); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e25ed2423d28..43187600bfb4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -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); } diff --git a/fs/Config.in b/fs/Config.in index 916782fb28b4..df803226a0dc 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -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 diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index 96fd4912eef0..0cf0e1c757e4 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -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 */ diff --git a/include/asm-arm/pci.h b/include/asm-arm/pci.h index 86ade5703166..e0de271b391f 100644 --- a/include/asm-arm/pci.h +++ b/include/asm-arm/pci.h @@ -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 diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h index 8cc99dda0f4e..1e55ec60fe47 100644 --- a/include/asm-i386/pci.h +++ b/include/asm-i386/pci.h @@ -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 diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h index bb3e4fb2112d..de50f98f0627 100644 --- a/include/asm-ia64/pci.h +++ b/include/asm-ia64/pci.h @@ -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 diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index 92347e40673a..5d022e02c9db 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h @@ -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) diff --git a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h index a2749a907258..80ea9d11d0df 100644 --- a/include/asm-sparc/pci.h +++ b/include/asm-sparc/pci.h @@ -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__ */ diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h index b7f2b8f9ea4f..6a687a465c21 100644 --- a/include/asm-sparc/sbus.h +++ b/include/asm-sparc/sbus.h @@ -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) */ diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index abf50c242463..25cc6dd9f524 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -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); } diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 12f015edb4b3..22281b176dfe 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -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. */ diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 881de6c2f06a..267cbf797c26 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -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__ */ diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h index f8c5e247f0fc..e9f7344b47cf 100644 --- a/include/asm-sparc64/sbus.h +++ b/include/asm-sparc64/sbus.h @@ -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) */ diff --git a/include/linux/ide.h b/include/linux/ide.h index 6d95ad2df605..957d024684b3 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -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 index 000000000000..2b0aa1e9d698 --- /dev/null +++ b/include/linux/if_bridge.h @@ -0,0 +1,109 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 + +#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 + +struct net_bridge; +struct net_bridge_port; + +extern int (*br_ioctl_hook)(unsigned long arg); +extern void (*br_handle_frame_hook)(struct sk_buff *skb); + +#endif + +#endif diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 50449b4dbaa0..4c002a7cb09e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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 *); diff --git a/include/linux/pci.h b/include/linux/pci.h index 8fae97e9b050..41a3c31904fd 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -286,6 +286,12 @@ #include #include +/* 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 #define DEVICE_COUNT_COMPATIBLE 4 diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f2170ed5f56b..015855fa0e52 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -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 index bfa25b645476..000000000000 --- a/include/net/br.h +++ /dev/null @@ -1,330 +0,0 @@ -#include -/* - * Constants and structure definitions for the bridging code - */ - -#if !defined(One) -#define Zero 0 -#define One 1 -#endif /* !defined(One) */ - -#if !defined(TRUE) -#define FALSE 0 -#define TRUE 1 -#endif /* !defined(TRUE) */ - -/** port states. **/ -#define Disabled 0 /* (4.4 5) */ -#define Listening 1 /* (4.4.2) */ -#define Learning 2 /* (4.4.3) */ -#define Forwarding 3 /* (4 4 4) */ -#define Blocking 4 /* (4.4.1) */ - - -/* MAG Yich! Easiest way of giving a configurable number of ports - * If you want more than 32, change BR_MAX_PORTS and recompile brcfg! - */ -#define BR_MAX_PORTS (32) -#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS -#undef CONFIG_BRIDGE_NUM_PORTS -#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS -#endif -#define No_of_ports CONFIG_BRIDGE_NUM_PORTS -/* arbitrary choice, to allow the code below to compile */ - -#define All_ports (No_of_ports + 1) - -/* - * We time out our entries in the FDB after this many seconds. - */ -#define FDB_TIMEOUT 20 /* JRP: 20s as NSC bridge code, was 300 for Linux */ - -/* - * the following defines are the initial values used when the - * bridge is booted. These may be overridden when this bridge is - * not the root bridge. These are the recommended default values - * from the 802.1d specification. - */ -#define BRIDGE_MAX_AGE 20 -#define BRIDGE_HELLO_TIME 2 -#define BRIDGE_FORWARD_DELAY 15 -#define HOLD_TIME 1 - -/* broacast/multicast storm limitation. This per source. */ -#define MAX_MCAST_PER_PERIOD 4 -#define MCAST_HOLD_TIME (10*HZ/100) - -#define Default_path_cost 10 - -/* - * minimum increment possible to avoid underestimating age, allows for BPDU - * transmission time - */ -#define Message_age_increment 1 - -#define No_port 0 -/* - * reserved value for Bridge's root port parameter indicating no root port, - * used when Bridge is the root - also used to indicate the source when - * a frame is being generated by a higher layer protocol on this host - */ - -/** Configuration BPDU Parameters (4.5.1) **/ - -typedef struct { - union { - struct { - unsigned short priority; - unsigned char ula[6]; - } p_u; - unsigned int id[2]; - } bi; -} bridge_id_t; - -#define BRIDGE_PRIORITY bi.p_u.priority -#define BRIDGE_ID_ULA bi.p_u.ula -#define BRIDGE_ID bi.id - -/* JRP: on the network the flags field is between "type" and "root_id" - * this is unfortunated! To make the code portable to a RISC machine - * the pdus are now massaged a little bit for processing - */ -#define TOPOLOGY_CHANGE 0x01 -#define TOPOLOGY_CHANGE_ACK 0x80 -#define BRIDGE_BPDU_8021_CONFIG_SIZE 35 /* real size */ -#define BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET 4 -#define BRIDGE_BPDU_8021_PROTOCOL_ID 0 -#define BRIDGE_BPDU_8021_PROTOCOL_VERSION_ID 0 -#define BRIDGE_LLC1_HS 3 -#define BRIDGE_LLC1_DSAP 0x42 -#define BRIDGE_LLC1_SSAP 0x42 -#define BRIDGE_LLC1_CTRL 0x03 - -typedef struct { - unsigned short protocol_id; - unsigned char protocol_version_id; - unsigned char type; - bridge_id_t root_id; /* (4.5.1.1) */ - unsigned int root_path_cost; /* (4.5.1.2) */ - bridge_id_t bridge_id; /* (4.5.1.3) */ - unsigned short port_id; /* (4.5.1.4) */ - unsigned short message_age; /* (4.5.1.5) */ - unsigned short max_age; /* (4.5.1.6) */ - unsigned short hello_time; /* (4.5.1.7) */ - unsigned short forward_delay; /* (4.5.1.8) */ - unsigned char top_change_ack; - unsigned char top_change; -} Config_bpdu; - -#ifdef __LITTLE_ENDIAN -#define config_bpdu_hton(config_bpdu) \ - (config_bpdu)->root_path_cost = htonl((config_bpdu)->root_path_cost); \ - (config_bpdu)->port_id = htons((config_bpdu)->port_id); \ - (config_bpdu)->message_age = htons((config_bpdu)->message_age); \ - (config_bpdu)->max_age = htons((config_bpdu)->max_age); \ - (config_bpdu)->hello_time = htons((config_bpdu)->hello_time); \ - (config_bpdu)->forward_delay = htons((config_bpdu)->forward_delay); -#else -#define config_bpdu_hton(config_bpdu) -#endif -#define config_bpdu_ntoh config_bpdu_hton - - -/** Topology Change Notification BPDU Parameters (4.5.2) **/ - -typedef struct { - unsigned short protocol_id; - unsigned char protocol_version_id; - unsigned char type; -} Tcn_bpdu; - -#define BPDU_TYPE_CONFIG 0 -#define BPDU_TYPE_TOPO_CHANGE 128 - -/** Bridge Parameters (4.5.3) **/ -typedef struct { - bridge_id_t designated_root; /* (4.5.3.1) */ - unsigned int root_path_cost; /* (4.5.3.2) */ - unsigned int root_port; /* (4.5.3.3) */ - unsigned short max_age; /* (4.5.3.4) */ - unsigned short hello_time; /* (4.5.3.5) */ - unsigned short forward_delay; /* (4.5.3.6) */ - bridge_id_t bridge_id; /* (4.5.3.7) */ - unsigned short bridge_max_age; /* (4.5.3.8) */ - unsigned short bridge_hello_time; /* (4.5.3.9) */ - unsigned short bridge_forward_delay; /* (4.5.3.10) */ - unsigned int top_change_detected; /* (4.5.3.11) */ - unsigned int top_change; /* (4.5.3.12) */ - unsigned short topology_change_time; /* (4.5.3.13) */ - unsigned short hold_time; /* (4.5.3.14) */ - unsigned int instance; -} Bridge_data; - -/** Port Parameters (4.5.5) **/ -typedef struct { - unsigned short port_id; /* (4.5.5.1) */ - unsigned int state; /* (4.5.5.2) */ - unsigned int path_cost; /* (4.5.5.3) */ - bridge_id_t designated_root; /* (4.5.5.4) */ - unsigned int designated_cost; /* (4.5.5.5) */ - bridge_id_t designated_bridge; /* (4.5.5.6) */ - unsigned short designated_port; /* (4.5.5.7) */ - unsigned int top_change_ack; /* (4.5.5.8) */ - unsigned int config_pending; /* (4.5.5.9) */ - bridge_id_t ifmac; - char ifname[IFNAMSIZ]; /* Make life easier for brcfg */ - struct net_device *dev; - struct fdb *fdb; /* head of per port fdb chain */ -} Port_data; - - - -/** types to support timers for this pseudo-implementation. **/ -typedef struct { - unsigned int active; /* timer in use. */ - unsigned int value; /* current value of timer, - * counting up. */ -} Timer; - -struct fdb { - unsigned char ula[6]; - unsigned char pad[2]; - unsigned short port; - unsigned int timer; - unsigned short flags; -#define FDB_ENT_VALID 0x01 - unsigned short mcast_count; - unsigned int mcast_timer; /* oldest xxxxxcast */ - -/* AVL tree of all addresses, sorted by address */ - short fdb_avl_height; - struct fdb *fdb_avl_left; - struct fdb *fdb_avl_right; -/* linked list of addresses for each port */ - struct fdb *fdb_next; -}; - -/* data returned on BRCMD_DISPLAY_FDB */ -struct fdb_info { - unsigned char ula[6]; - unsigned char port; - unsigned char flags; - unsigned int timer; -}; -struct fdb_info_hdr { - int copied; /* nb of entries copied to user */ - int not_copied; /* when user buffer is too small */ - int cmd_time; -}; - -#define IS_BRIDGED 0x2e - - -#define BR_MAX_PROTOCOLS 32 -#define BR_MAX_PROT_STATS BR_MAX_PROTOCOLS - -/* policy values for policy field */ -#define BR_ACCEPT 1 -#define BR_REJECT 0 - -/* JRP: extra statistics for debug */ -typedef struct { - /* br_receive_frame counters */ - int port_disable_up_stack; - int rcv_bpdu; - int notForwarding; - int forwarding_up_stack; - int unknown_state; - - /* br_tx_frame counters */ - int port_disable; - int port_not_disable; - - /* br_forward counters */ - int local_multicast; - int forwarded_multicast; /* up stack as well */ - int flood_unicast; - int aged_flood_unicast; - int forwarded_unicast; - int forwarded_unicast_up_stack; - int forwarded_ip_up_stack; - int forwarded_ip_up_stack_lie; /* received on alternate device */ - int arp_for_local_mac; - int drop_same_port; - int drop_same_port_aged; - int drop_multicast; -} br_stats_counter; - -struct br_stat { - unsigned int flags; - Bridge_data bridge_data; - unsigned int policy; - unsigned int exempt_protocols; - unsigned short protocols[BR_MAX_PROTOCOLS]; - unsigned short prot_id[BR_MAX_PROT_STATS]; /* Protocol encountered */ - unsigned int prot_counter[BR_MAX_PROT_STATS]; /* How many packets ? */ - br_stats_counter packet_cnts; - unsigned int num_ports; - Port_data port_data[BR_MAX_PORTS + 1]; -}; - -/* defined flags for br_stat.flags */ -#define BR_UP 0x0001 /* bridging enabled */ -#define BR_DEBUG 0x0002 /* debugging enabled */ -#define BR_PROT_STATS 0x0004 /* protocol statistics enabled */ -#define BR_STP_DISABLED 0x0008 /* Spanning tree protocol disabled */ - -struct br_cf { - unsigned int cmd; - unsigned int arg1; - unsigned int arg2; -}; - -/* defined cmds */ -#define BRCMD_BRIDGE_ENABLE 1 -#define BRCMD_BRIDGE_DISABLE 2 -#define BRCMD_PORT_ENABLE 3 /* arg1 = port */ -#define BRCMD_PORT_DISABLE 4 /* arg1 = port */ -#define BRCMD_SET_BRIDGE_PRIORITY 5 /* arg1 = priority */ -#define BRCMD_SET_PORT_PRIORITY 6 /* arg1 = port, arg2 = priority */ -#define BRCMD_SET_PATH_COST 7 /* arg1 = port, arg2 = cost */ -#define BRCMD_DISPLAY_FDB 8 -#define BRCMD_ENABLE_DEBUG 9 -#define BRCMD_DISABLE_DEBUG 10 -#define BRCMD_SET_POLICY 11 /* arg1 = default policy (1==bridge all) */ -#define BRCMD_EXEMPT_PROTOCOL 12 /* arg1 = protocol (see net/if_ether.h) */ -#define BRCMD_ENABLE_PROT_STATS 13 -#define BRCMD_DISABLE_PROT_STATS 14 -#define BRCMD_ZERO_PROT_STATS 15 -#define BRCMD_TOGGLE_STP 16 -#define BRCMD_IF_ENABLE 17 /* arg1 = if_index */ -#define BRCMD_IF_DISABLE 18 /* arg1 = if_index */ -#define BRCMD_SET_IF_PRIORITY 19 /* arg1 = if_index, arg2 = priority */ -#define BRCMD_SET_IF_PATH_COST 20 /* arg1 = if_index, arg2 = cost */ - -/* prototypes of exported bridging functions... */ - -#ifdef __KERNEL__ -void br_init(void); -int br_receive_frame(struct sk_buff *skb); /* 3.5 */ -int br_tx_frame(struct sk_buff *skb); -int brg_init(void); -int br_ioctl(unsigned int cmd, void *arg); -void requeue_fdb(struct fdb *node, int new_port); - -struct fdb *br_avl_find_addr(unsigned char addr[6]); -struct fdb *br_avl_insert (struct fdb * new_node); -void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length); -void br_avl_delete_by_port(int port); -int br_call_bridge(struct sk_buff *skb, unsigned short type); -void br_spacedevice_register(void); - -/* externs */ - -extern struct br_stat br_stats; -extern Port_data port_info[]; - -#endif - - - diff --git a/net/Changes b/net/Changes index 6ff0219ccd5f..3e88ee85f0a4 100644 --- a/net/Changes +++ b/net/Changes @@ -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 diff --git a/net/Config.in b/net/Config.in index 82f4fe6d9d89..45f1b1168977 100644 --- a/net/Config.in +++ b/net/Config.in @@ -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 diff --git a/net/Makefile b/net/Makefile index ccaed5154d4e..bf234eae145a 100644 --- a/net/Makefile +++ b/net/Makefile @@ -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) diff --git a/net/README b/net/README index d54d8526b8bc..7490dff2bd54 100644 --- a/net/README +++ b/net/README @@ -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 diff --git a/net/bridge/Makefile b/net/bridge/Makefile index bcccefb75ac9..082388fe5a01 100644 --- a/net/bridge/Makefile +++ b/net/bridge/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the Linux Bridge layer. +# Makefile for the IEEE 802.1d ethernet bridging layer. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -7,15 +7,10 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -O_TARGET := bridge.o -O_OBJS := br.o br_tree.o -M_OBJS := $(O_TARGET) - -ifeq ($(CONFIG_SYSCTL),y) -O_OBJS += sysctl_net_bridge.o -endif +O_TARGET := bridge.o +O_OBJS := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ + br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \ + br_stp_if.o br_stp_timer.o +M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make - -tar: - tar -cvf /dev/f1 . diff --git a/net/bridge/br.c b/net/bridge/br.c index 682012e91d2c..ec59ff6220e4 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -1,2735 +1,67 @@ /* - * Linux NET3 Bridge Support + * Generic parts + * Linux ethernet bridge * - * Originally by John Hayes (Network Plumbing). - * Minor hacks to get it to run with 1.3.x by Alan Cox - * More hacks to be able to switch protocols on and off by Christoph Lameter - * - * Software and more Documentation for the bridge is available from ftp.debian.org - * in the bridgex package + * Authors: + * Lennert Buytenhek + * + * $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 -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include #include -#include #include -#include -#include -#include -#include #include +#include #include -#include -#include -#include -#include -#include -#include - -#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_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.arg2cmd_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, ¬copied); - 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 index 000000000000..de14e83a86d1 --- /dev/null +++ b/net/bridge/br_device.c @@ -0,0 +1,141 @@ +/* + * Device handling code + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#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 index 000000000000..6a894098b690 --- /dev/null +++ b/net/bridge/br_fdb.c @@ -0,0 +1,319 @@ +/* + * Forwarding database + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#include +#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;ihash[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;ihash[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;ihash[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;ihash[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 index 000000000000..9b68ce583429 --- /dev/null +++ b/net/bridge/br_forward.c @@ -0,0 +1,96 @@ +/* + * Forwarding decision + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#include +#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 index 000000000000..16f34f9ed2f7 --- /dev/null +++ b/net/bridge/br_if.c @@ -0,0 +1,294 @@ +/* + * Userspace interface + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#include +#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;idev.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 index 000000000000..b1d1cbf653a5 --- /dev/null +++ b/net/bridge/br_input.c @@ -0,0 +1,114 @@ +/* + * Handle incoming frames + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#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 index 000000000000..334743af8ed7 --- /dev/null +++ b/net/bridge/br_ioctl.c @@ -0,0 +1,265 @@ +/* + * Ioctl handler + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#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 index 000000000000..d8820cb13f55 --- /dev/null +++ b/net/bridge/br_notify.c @@ -0,0 +1,76 @@ +/* + * Device event handling + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#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 index 000000000000..084e81b4b0e3 --- /dev/null +++ b/net/bridge/br_private.h @@ -0,0 +1,199 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#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 index 000000000000..91faafff5410 --- /dev/null +++ b/net/bridge/br_private_stp.h @@ -0,0 +1,53 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 index 000000000000..6655ab9f5887 --- /dev/null +++ b/net/bridge/br_private_timer.h @@ -0,0 +1,54 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 index 000000000000..413c77d88021 --- /dev/null +++ b/net/bridge/br_stp.c @@ -0,0 +1,466 @@ +/* + * Spanning tree protocol; generic parts + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#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 index 000000000000..8729e05a1292 --- /dev/null +++ b/net/bridge/br_stp_bpdu.c @@ -0,0 +1,192 @@ +/* + * Spanning tree protocol; BPDU handling + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#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 index 000000000000..7ea37e2f649f --- /dev/null +++ b/net/bridge/br_stp_if.c @@ -0,0 +1,226 @@ +/* + * Spanning tree protocol; interface code + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#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 index 000000000000..594b6b7819a8 --- /dev/null +++ b/net/bridge/br_stp_timer.c @@ -0,0 +1,185 @@ +/* + * Spanning tree protocol; timer-related code + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 +#include +#include +#include +#include +#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 index 67efa8f1ba2b..000000000000 --- a/net/bridge/br_tree.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * This code is derived from the avl functions in mmap.c - */ - -#include -#include -#include -#include -#include -#include - -#include -#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 . - * Taken from mmap.c, extensively modified by John Hayes - * - * 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 = (heightleftfdb_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 index 6e2f57d65601..000000000000 --- a/net/bridge/sysctl_net_bridge.c +++ /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 -#include - -ctl_table bridge_table[] = { - {0} -}; diff --git a/net/core/dev.c b/net/core/dev.c index 362ee6ddf095..34a818721cea 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -81,7 +81,7 @@ #include #include #include -#include +#include #include #include #include @@ -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 */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a0307bbd62a6..30aa1f6bbc67 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4,7 +4,7 @@ * Authors: Alan Cox * Florian La Roche * - * 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; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 969fee200482..b7512a1c9bb0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -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, * Fred N. van Kempen, @@ -103,9 +103,7 @@ #ifdef CONFIG_IP_MROUTE #include #endif -#ifdef CONFIG_BRIDGE -#include -#endif +#include #ifdef CONFIG_KMOD #include #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: diff --git a/net/netsyms.c b/net/netsyms.c index 1a1e7513eebd..fbb07ab5a36e 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -28,12 +28,9 @@ #endif #include #include +#include #include -#ifdef CONFIG_BRIDGE -#include -#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); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6410e99d79a3..46439faa365e 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -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, * Fred N. van Kempen, @@ -65,16 +65,12 @@ #include #include #include +#include #ifdef CONFIG_INET #include #endif -#ifdef CONFIG_BRIDGE -#include -#include -#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: diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 36238c123d8e..8ee8ab54fd71 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -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(); } diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 5f5e8593e80f..e539693fef14 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -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 -- 2.39.5